Révision c6ba8333
Ajouté par Thomas Noël il y a environ 12 ans
extra/modules/payments.py | ||
---|---|---|
6 | 6 |
|
7 | 7 |
from decimal import Decimal |
8 | 8 |
|
9 |
from quixote import redirect, get_request, get_session |
|
9 |
from quixote import redirect, get_publisher, get_request, get_session
|
|
10 | 10 |
from quixote.directory import Directory |
11 | 11 |
|
12 | 12 |
if not set: |
... | ... | |
47 | 47 |
|
48 | 48 |
class Invoice(StorableObject): |
49 | 49 |
_names = 'invoices' |
50 |
_hashed_indexes = ['user_id', 'regie_id'] |
|
50 |
_hashed_indexes = ['user_id', 'user_hash', 'regie_id']
|
|
51 | 51 |
|
52 | 52 |
user_id = None |
53 |
user_hash = None |
|
53 | 54 |
regie_id = None |
54 | 55 |
formdef_id = None |
55 | 56 |
formdata_id = None |
... | ... | |
59 | 60 |
date = None |
60 | 61 |
paid = False |
61 | 62 |
paid_date = None |
63 |
canceled = False |
|
64 |
canceled_date = None |
|
65 |
canceled_reason = None |
|
62 | 66 |
next_status = None |
63 | 67 |
|
64 | 68 |
def __init__(self, id=None, regie_id=None, formdef_id=None): |
... | ... | |
90 | 94 |
return False |
91 | 95 |
check_crc = classmethod(check_crc) |
92 | 96 |
|
97 |
def cancel(self, reason=None): |
|
98 |
self.canceled = True |
|
99 |
self.canceled_date = dt.now() |
|
100 |
if reason: |
|
101 |
self.canceled_reason = reason |
|
102 |
self.store() |
|
103 |
|
|
104 |
|
|
105 |
INVOICE_EVO_VIEW = { |
|
106 |
'create': N_('Create Invoice <a href="%(url)s">%(id)s</a>: %(subject)s - %(amount)s €'), |
|
107 |
'pay': N_('Invoice <a href="%(url)s">%(id)s</a> is paid'), |
|
108 |
'cancel': N_('Cancel Invoice <a href="%(url)s">%(id)s</a>'), |
|
109 |
} |
|
110 |
|
|
111 |
class InvoiceEvolutionPart: |
|
112 |
action = None |
|
113 |
id = None |
|
114 |
subject = None |
|
115 |
amount = None |
|
116 |
|
|
117 |
def __init__(self, action, invoice): |
|
118 |
self.action = action |
|
119 |
self.id = invoice.id |
|
120 |
self.subject = invoice.subject |
|
121 |
self.amount = invoice.amount |
|
122 |
|
|
123 |
def view(self): |
|
124 |
vars = { |
|
125 |
'url': '%s/invoices/%s' % (get_publisher().get_frontoffice_url(), self.id), |
|
126 |
'id': self.id, |
|
127 |
'subject': self.subject, |
|
128 |
'amount': self.amount, |
|
129 |
} |
|
130 |
return htmltext('<p class="invoice-%s">' % self.action + \ |
|
131 |
_(INVOICE_EVO_VIEW[self.action]) % vars + '</p>') |
|
132 |
|
|
93 | 133 |
|
94 | 134 |
class Transaction(StorableObject): |
95 | 135 |
_names = 'transactions' |
... | ... | |
168 | 208 |
|
169 | 209 |
def perform(self, formdata): |
170 | 210 |
invoice = Invoice(regie_id=self.regie_id, formdef_id=formdata.formdef.id) |
171 |
invoice.user_id = get_request().user.id # FIXME: handle user_hash |
|
211 |
invoice.user_id = formdata.user_id |
|
212 |
invoice.user_hash = formdata.user_hash |
|
172 | 213 |
invoice.formdata_id = formdata.id |
173 | 214 |
invoice.next_status = self.next_status |
174 | 215 |
if self.subject: |
... | ... | |
181 | 222 |
invoice.amount = self.calculate_amount(formdata) |
182 | 223 |
invoice.date = dt.now() |
183 | 224 |
invoice.store() |
184 |
# FIXME: add a message in formdata.evolution |
|
185 |
|
|
225 |
# add a message in formdata.evolution |
|
226 |
evo = Evolution() |
|
227 |
evo.time = time.localtime() |
|
228 |
evo.status = formdata.status |
|
229 |
evo.add_part(InvoiceEvolutionPart('create', invoice)) |
|
230 |
if not formdata.evolution: |
|
231 |
formdata.evolution = [] |
|
232 |
formdata.evolution.append(evo) |
|
233 |
formdata.store() |
|
234 |
# redirect the user to "my invoices" |
|
186 | 235 |
return get_publisher().get_frontoffice_url() + '/myspace/invoices/' |
187 | 236 |
|
188 | 237 |
register_item_class(PaymentWorkflowStatusItem) |
189 | 238 |
|
239 |
class PaymentCancelWorkflowStatusItem(WorkflowStatusItem): |
|
240 |
description = N_('Payment Cancel') |
|
241 |
key = 'payment-cancel' |
|
242 |
endpoint = False |
|
243 |
|
|
244 |
reason = None |
|
245 |
regie_id = None |
|
246 |
|
|
247 |
def render_as_line(self): |
|
248 |
if self.regie_id: |
|
249 |
if self.regie_id == '_all': |
|
250 |
return _('Cancel all Payments') |
|
251 |
else: |
|
252 |
return _('Cancel Payments for %s' % Regie.get(self.regie_id).label) |
|
253 |
else: |
|
254 |
return _('Cancel Payments (non completed)') |
|
255 |
|
|
256 |
def get_parameters(self): |
|
257 |
return ('reason', 'regie_id') |
|
258 |
|
|
259 |
def add_parameters_widgets(self, form, parameters, prefix='', formdef=None): |
|
260 |
if 'reason' in parameters: |
|
261 |
form.add(StringWidget, '%sreason' % prefix, title=_('Reason'), |
|
262 |
value=self.reason, size=40) |
|
263 |
if 'regie_id' in parameters: |
|
264 |
form.add(SingleSelectWidget, '%sregie_id' % prefix, |
|
265 |
title=_('Regie'), value=self.regie_id, |
|
266 |
options = [(None, '---'), ('_all', _('All Regies'))] + \ |
|
267 |
[(x.id, x.label) for x in Regie.select()]) |
|
268 |
|
|
269 |
def perform(self, formdata): |
|
270 |
invoices_id = [] |
|
271 |
# get all invoices for the formdata and the selected regie |
|
272 |
for evo in [evo for evo in formdata.evolution if evo.parts]: |
|
273 |
for part in [part for part in evo.parts if isinstance(part, InvoiceEvolutionPart)]: |
|
274 |
if part.action == 'create': |
|
275 |
invoices_id.append(part.id) |
|
276 |
elif part.id in invoices_id: |
|
277 |
invoices_id.remove(part.id) |
|
278 |
invoices = [Invoice.get(id) for id in invoices_id] |
|
279 |
# select invoices for the selected regie (if not "all regies") |
|
280 |
if self.regie_id != '_all': |
|
281 |
invoices = [i for i in invoices if i.regie_id == self.regie_id] |
|
282 |
# security filter: check user |
|
283 |
invoices = [i for i in invoices if (i.user_id == formdata.user_id) \ |
|
284 |
or (i.user_hash == formdata.user_hash)] |
|
285 |
# security filter: check formdata & formdef |
|
286 |
invoices = [i for i in invoices if (i.formdata_id == formdata.id) \ |
|
287 |
and (i.formdef_id == formdata.formdef.id)] |
|
288 |
evo = Evolution() |
|
289 |
evo.time = time.localtime() |
|
290 |
for invoice in invoices: |
|
291 |
if not (invoice.paid or invoice.canceled): |
|
292 |
invoice.cancel(self.reason) |
|
293 |
evo.add_part(InvoiceEvolutionPart('cancel', invoice)) |
|
294 |
if not formdata.evolution: |
|
295 |
formdata.evolution = [] |
|
296 |
formdata.evolution.append(evo) |
|
297 |
formdata.store() |
|
298 |
return get_publisher().get_frontoffice_url() + '/myspace/invoices/' |
|
299 |
|
|
300 |
register_item_class(PaymentCancelWorkflowStatusItem) |
|
301 |
|
|
302 |
|
|
190 | 303 |
def request_payment(invoice_ids, url, add_regie=True): |
191 | 304 |
for invoice_id in invoice_ids: |
192 | 305 |
if not Invoice.check_crc(invoice_id): |
193 | 306 |
raise KeyError() |
194 | 307 |
invoices = [ Invoice.get(invoice_id) for invoice_id in invoice_ids ] |
195 |
invoices = filter(lambda x: not x.paid, invoices)
|
|
308 |
invoices = [ i for i in invoices if not (i.paid or i.canceled) ]
|
|
196 | 309 |
regie_ids = set([invoice.regie_id for invoice in invoices]) |
197 |
# Do not apply if more than one regie is used or no invoice is not paid |
|
310 |
# Do not apply if more than one regie is used or no invoice is not paid or canceled
|
|
198 | 311 |
if len(invoices) == 0 or len(regie_ids) != 1: |
199 | 312 |
url = get_publisher().get_frontoffice_url() |
200 | 313 |
if get_session().user: |
Formats disponibles : Unified diff
add workflow item "cancel payment" (fix #1255)
+ add_part(invoice) in formdata.evolution