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()
|
93 |
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>' + _(INVOICE_EVO_VIEW[self.action]) % vars + '</p>')
|
|
131 |
|
|
132 |
|
94 |
133 |
class Transaction(StorableObject):
|
95 |
134 |
_names = 'transactions'
|
96 |
135 |
_hashed_indexes = ['invoice_ids']
|
... | ... | |
168 |
207 |
|
169 |
208 |
def perform(self, formdata):
|
170 |
209 |
invoice = Invoice(regie_id=self.regie_id, formdef_id=formdata.formdef.id)
|
171 |
|
invoice.user_id = get_request().user.id # FIXME: handle user_hash
|
|
210 |
invoice.user_id = formdata.user_id
|
|
211 |
invoice.user_hash = formdata.user_hash
|
172 |
212 |
invoice.formdata_id = formdata.id
|
173 |
213 |
invoice.next_status = self.next_status
|
174 |
214 |
if self.subject:
|
... | ... | |
181 |
221 |
invoice.amount = self.calculate_amount(formdata)
|
182 |
222 |
invoice.date = dt.now()
|
183 |
223 |
invoice.store()
|
184 |
|
# FIXME: add a message in formdata.evolution
|
185 |
|
|
|
224 |
# add a message in formdata.evolution
|
|
225 |
evo = Evolution()
|
|
226 |
evo.time = time.localtime()
|
|
227 |
evo.status = formdata.status
|
|
228 |
evo.add_part(InvoiceEvolutionPart('create', invoice))
|
|
229 |
if not formdata.evolution:
|
|
230 |
formdata.evolution = []
|
|
231 |
formdata.evolution.append(evo)
|
|
232 |
formdata.store()
|
|
233 |
# redirect the user to "my invoices"
|
186 |
234 |
return get_publisher().get_frontoffice_url() + '/myspace/invoices/'
|
187 |
235 |
|
188 |
236 |
register_item_class(PaymentWorkflowStatusItem)
|
189 |
237 |
|
|
238 |
class PaymentCancelWorkflowStatusItem(WorkflowStatusItem):
|
|
239 |
description = N_('Payment Cancel')
|
|
240 |
key = 'payment-cancel'
|
|
241 |
endpoint = False
|
|
242 |
|
|
243 |
reason = None
|
|
244 |
regie_id = None
|
|
245 |
|
|
246 |
def render_as_line(self):
|
|
247 |
if self.regie_id:
|
|
248 |
if self.regie_id == '_all':
|
|
249 |
return _('Cancel all Payments')
|
|
250 |
else:
|
|
251 |
return _('Cancel Payments for %s' % Regie.get(self.regie_id).label)
|
|
252 |
else:
|
|
253 |
return _('Cancel Payments (non completed)')
|
|
254 |
|
|
255 |
def get_parameters(self):
|
|
256 |
return ('reason', 'regie_id')
|
|
257 |
|
|
258 |
def add_parameters_widgets(self, form, parameters, prefix='', formdef=None):
|
|
259 |
if 'reason' in parameters:
|
|
260 |
form.add(StringWidget, '%sreason' % prefix, title=_('Reason'),
|
|
261 |
value=self.reason, size=40)
|
|
262 |
if 'regie_id' in parameters:
|
|
263 |
form.add(SingleSelectWidget, '%sregie_id' % prefix,
|
|
264 |
title=_('Regie'), value=self.regie_id,
|
|
265 |
options = [(None, '---'), ('_all', _('All Regies'))] + \
|
|
266 |
[(x.id, x.label) for x in Regie.select()])
|
|
267 |
|
|
268 |
def perform(self, formdata):
|
|
269 |
invoices_id = []
|
|
270 |
# get all invoices for the formdata and the selected regie
|
|
271 |
for evo in [evo for evo in formdata.evolution if evo.parts]:
|
|
272 |
for part in [part for part in evo.parts if isinstance(part, InvoiceEvolutionPart)]:
|
|
273 |
if part.action == 'create':
|
|
274 |
invoices_id.append(part.id)
|
|
275 |
elif part.id in invoices_id:
|
|
276 |
invoices_id.remove(part.id)
|
|
277 |
invoices = [Invoice.get(id) for id in invoices_id]
|
|
278 |
# select invoices for the selected regie (if not "all regies")
|
|
279 |
if self.regie_id != '_all':
|
|
280 |
invoices = [i for i in invoices if i.regie_id == self.regie_id]
|
|
281 |
# security filter: check user
|
|
282 |
invoices = [i for i in invoices if (i.user_id == formdata.user_id) \
|
|
283 |
or (i.user_hash == formdata.user_hash)]
|
|
284 |
# security filter: check formdata & formdef
|
|
285 |
invoices = [i for i in invoices if (i.formdata_id == formdata.id) \
|
|
286 |
and (i.formdef_id == formdata.formdef.id)]
|
|
287 |
evo = Evolution()
|
|
288 |
evo.time = time.localtime()
|
|
289 |
for invoice in invoices:
|
|
290 |
if not (invoice.paid or invoice.canceled):
|
|
291 |
invoice.cancel(self.reason)
|
|
292 |
evo.add_part(InvoiceEvolutionPart('cancel', invoice))
|
|
293 |
if not formdata.evolution:
|
|
294 |
formdata.evolution = []
|
|
295 |
formdata.evolution.append(evo)
|
|
296 |
formdata.store()
|
|
297 |
return get_publisher().get_frontoffice_url() + '/myspace/invoices/'
|
|
298 |
|
|
299 |
register_item_class(PaymentCancelWorkflowStatusItem)
|
|
300 |
|
|
301 |
|
190 |
302 |
def request_payment(invoice_ids, url, add_regie=True):
|
191 |
303 |
for invoice_id in invoice_ids:
|
192 |
304 |
if not Invoice.check_crc(invoice_id):
|
193 |
305 |
raise KeyError()
|
194 |
306 |
invoices = [ Invoice.get(invoice_id) for invoice_id in invoice_ids ]
|
195 |
|
invoices = filter(lambda x: not x.paid, invoices)
|
|
307 |
invoices = [ i for i in invoices if not (i.paid or i.canceled) ]
|
196 |
308 |
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
|
|
309 |
# Do not apply if more than one regie is used or no invoice is not paid or canceled
|
198 |
310 |
if len(invoices) == 0 or len(regie_ids) != 1:
|
199 |
311 |
url = get_publisher().get_frontoffice_url()
|
200 |
312 |
if get_session().user:
|