1
|
import time
|
2
|
import pprint
|
3
|
import locale
|
4
|
import decimal
|
5
|
import datetime
|
6
|
|
7
|
from quixote import get_request, get_response, get_session, redirect
|
8
|
from quixote.directory import Directory, AccessControlled
|
9
|
from quixote.html import TemplateIO, htmltext
|
10
|
|
11
|
import wcs
|
12
|
import wcs.admin.root
|
13
|
from wcs.formdef import FormDef
|
14
|
|
15
|
from qommon import _
|
16
|
from qommon import errors, misc, template, get_logger
|
17
|
from qommon.form import *
|
18
|
from qommon.strftime import strftime
|
19
|
from qommon.admin.emails import EmailsDirectory
|
20
|
from qommon.backoffice.menu import html_top
|
21
|
from qommon import get_cfg
|
22
|
|
23
|
from payments import (eopayment, Regie, is_payment_supported, Invoice,
|
24
|
Transaction, notify_paid_invoice)
|
25
|
|
26
|
from qommon.admin.texts import TextsDirectory
|
27
|
|
28
|
if not set:
|
29
|
from sets import Set as set
|
30
|
|
31
|
def invoice_as_html(invoice):
|
32
|
r = TemplateIO(html=True)
|
33
|
r += htmltext('<div id="invoice">')
|
34
|
r += htmltext('<h2>%s</h2>') % _('Invoice: %s') % invoice.subject
|
35
|
r += htmltext('<h3>%s') % _('Amount: %s') % invoice.amount
|
36
|
r += htmltext(' €</h3>')
|
37
|
r += htmltext('<!-- DEBUG \n')
|
38
|
r += 'Invoice:\n'
|
39
|
r += pprint.pformat(invoice.__dict__)
|
40
|
for transaction in Transaction.get_with_indexed_value('invoice_ids', invoice.id):
|
41
|
r += '\nTransaction:\n'
|
42
|
r += pprint.pformat(transaction.__dict__)
|
43
|
r += htmltext('\n-->')
|
44
|
if invoice.formdef_id and invoice.formdata_id and \
|
45
|
get_session().user == invoice.user_id:
|
46
|
formdef = FormDef.get(invoice.formdef_id)
|
47
|
if formdef:
|
48
|
formdata = formdef.data_class().get(invoice.formdata_id, ignore_errors=True)
|
49
|
if formdata:
|
50
|
name = _('%(form_name)s #%(formdata_id)s') % {
|
51
|
'form_name': formdata.formdef.name,
|
52
|
'formdata_id': formdata.id }
|
53
|
r += htmltext('<p class="from">%s <a href="%s">%s</a></p>') % (_('From:'), formdata.get_url(), name)
|
54
|
r += htmltext('<p class="regie">%s</p>') % _('Regie: %s') % Regie.get(invoice.regie_id).label
|
55
|
r += htmltext('<p class="date">%s</p>') % _('Created on: %s') % misc.localstrftime(invoice.date)
|
56
|
if invoice.details:
|
57
|
r += htmltext('<p class="details">%s</p>') % _('Details:')
|
58
|
r += htmltext('<div class="details">')
|
59
|
r += htmltext(invoice.details)
|
60
|
r += htmltext('</div>')
|
61
|
if invoice.canceled:
|
62
|
r += htmltext('<p class="canceled">')
|
63
|
r += '%s' % _('canceled on %s') % misc.localstrftime(invoice.canceled_date)
|
64
|
if invoice.canceled_reason:
|
65
|
r += ' (%s)' % invoice.canceled_reason
|
66
|
r += htmltext('</p>')
|
67
|
if invoice.paid:
|
68
|
r += htmltext('<p class="paid">%s</p>') % _('paid on %s') % misc.localstrftime(invoice.paid_date)
|
69
|
r += htmltext('</div>')
|
70
|
return r.getvalue()
|
71
|
|
72
|
|
73
|
class InvoicesDirectory(Directory):
|
74
|
_q_exports = ['', 'multiple']
|
75
|
|
76
|
def _q_traverse(self, path):
|
77
|
if not is_payment_supported():
|
78
|
raise errors.TraversalError()
|
79
|
get_response().filter['bigdiv'] = 'profile'
|
80
|
if get_session().user:
|
81
|
# fake breadcrumb
|
82
|
get_response().breadcrumb.append(('myspace/', _('My Space')))
|
83
|
get_response().breadcrumb.append(('invoices/', _('Invoices')))
|
84
|
return Directory._q_traverse(self, path)
|
85
|
|
86
|
def multiple(self):
|
87
|
invoice_ids = get_request().form.get('invoice')
|
88
|
if type(invoice_ids) is not list:
|
89
|
return redirect('%s' % invoice_ids)
|
90
|
return redirect('+'.join(invoice_ids))
|
91
|
|
92
|
def _q_lookup(self, component):
|
93
|
if str('+') in component:
|
94
|
invoice_ids = component.split(str('+'))
|
95
|
else:
|
96
|
invoice_ids = [component]
|
97
|
for invoice_id in invoice_ids:
|
98
|
if not Invoice.check_crc(invoice_id):
|
99
|
raise errors.TraversalError()
|
100
|
|
101
|
template.html_top(_('Invoices'))
|
102
|
r = TemplateIO(html=True)
|
103
|
r += TextsDirectory.get_html_text('aq-invoice')
|
104
|
|
105
|
regies_id = set()
|
106
|
for invoice_id in invoice_ids:
|
107
|
try:
|
108
|
invoice = Invoice.get(invoice_id)
|
109
|
except KeyError:
|
110
|
raise errors.TraversalError()
|
111
|
r += invoice_as_html(invoice)
|
112
|
if not (invoice.paid or invoice.canceled):
|
113
|
regies_id.add(invoice.regie_id)
|
114
|
|
115
|
if len(regies_id) == 1:
|
116
|
r += htmltext('<p class="command">')
|
117
|
r += htmltext('<a href="%s/payment/init?invoice_ids=%s">') % (
|
118
|
get_publisher().get_frontoffice_url(), component)
|
119
|
if len(invoice_ids) > 1:
|
120
|
r += _('Pay Selected Invoices')
|
121
|
else:
|
122
|
r += _('Pay')
|
123
|
r += htmltext('</a></p>')
|
124
|
if len(regies_id) > 1:
|
125
|
r += _('You can not pay to different regies.')
|
126
|
|
127
|
return r.getvalue()
|
128
|
|
129
|
def _q_index(self):
|
130
|
return redirect('..')
|
131
|
|
132
|
|
133
|
class RegieDirectory(Directory):
|
134
|
_q_exports = ['', 'edit', 'delete', 'options']
|
135
|
|
136
|
def __init__(self, regie):
|
137
|
self.regie = regie
|
138
|
|
139
|
def _q_index(self):
|
140
|
html_top('payments', title = _('Regie: %s') % self.regie.label)
|
141
|
r = TemplateIO(html=True)
|
142
|
get_response().filter['sidebar'] = self.get_sidebar()
|
143
|
r += htmltext('<h2>%s</h2>') % _('Regie: %s') % self.regie.label
|
144
|
|
145
|
r += get_session().display_message()
|
146
|
|
147
|
if self.regie.description:
|
148
|
r += htmltext('<div class="bo-block">')
|
149
|
r += htmltext('<p>')
|
150
|
r += self.regie.description
|
151
|
r += htmltext('</p>')
|
152
|
r += htmltext('</div>')
|
153
|
|
154
|
if self.regie.service:
|
155
|
r += htmltext('<div class="bo-block">')
|
156
|
url = get_publisher().get_frontoffice_url() + '/payment/back_asynchronous/'
|
157
|
url += str(self.regie.id)
|
158
|
r += htmltext('<p>')
|
159
|
r += '%s %s' % (_('Banking Service:'), self.regie.service)
|
160
|
r += htmltext(' (<a href="options">%s</a>)') % _('options')
|
161
|
r += htmltext('</p>')
|
162
|
r += htmltext('<p>')
|
163
|
r += '%s %s' % (_('Payment notification URL:'), url)
|
164
|
r += htmltext('</div>')
|
165
|
|
166
|
r += self.invoice_listing()
|
167
|
return r.getvalue()
|
168
|
|
169
|
def get_sidebar(self):
|
170
|
r = TemplateIO(html=True)
|
171
|
r += htmltext('<ul>')
|
172
|
r += htmltext('<li><a href="edit">%s</a></li>') % _('Edit')
|
173
|
r += htmltext('<li><a href="delete">%s</a></li>') % _('Delete')
|
174
|
r += htmltext('</ul>')
|
175
|
return r.getvalue()
|
176
|
|
177
|
def edit(self):
|
178
|
form = self.form()
|
179
|
if form.get_submit() == 'cancel':
|
180
|
return redirect('.')
|
181
|
|
182
|
if form.is_submitted() and not form.has_errors():
|
183
|
self.submit(form)
|
184
|
return redirect('..')
|
185
|
|
186
|
html_top('payments', title = _('Edit Regie: %s') % self.regie.label)
|
187
|
r = TemplateIO(html=True)
|
188
|
r += htmltext('<h2>%s</h2>') % _('Edit Regie: %s') % self.regie.label
|
189
|
r += form.render()
|
190
|
return r.getvalue()
|
191
|
|
192
|
|
193
|
def form(self):
|
194
|
form = Form(enctype='multipart/form-data')
|
195
|
form.add(StringWidget, 'label', title=_('Label'), required=True,
|
196
|
value=self.regie.label)
|
197
|
form.add(TextWidget, 'description', title=_('Description'),
|
198
|
value=self.regie.description, rows=5, cols=60)
|
199
|
form.add(SingleSelectWidget, 'service', title=_('Banking Service'),
|
200
|
value=self.regie.service, required=True,
|
201
|
options = [
|
202
|
('dummy', _('Dummy (for tests)')),
|
203
|
('sips', 'SIPS'),
|
204
|
('systempayv2', 'systempay (Banque Populaire)'),
|
205
|
('spplus', _('SP+ (Caisse d\'epargne)'))])
|
206
|
form.add_submit('submit', _('Submit'))
|
207
|
form.add_submit('cancel', _('Cancel'))
|
208
|
return form
|
209
|
|
210
|
def submit(self, form):
|
211
|
for k in ('label', 'description', 'service'):
|
212
|
widget = form.get_widget(k)
|
213
|
if widget:
|
214
|
setattr(self.regie, k, widget.parse())
|
215
|
self.regie.store()
|
216
|
|
217
|
def delete(self):
|
218
|
form = Form(enctype='multipart/form-data')
|
219
|
form.widgets.append(HtmlWidget('<p>%s</p>' % _(
|
220
|
'You are about to irrevocably delete this regie.')))
|
221
|
form.add_submit('submit', _('Submit'))
|
222
|
form.add_submit('cancel', _('Cancel'))
|
223
|
if form.get_submit() == 'cancel':
|
224
|
return redirect('..')
|
225
|
if not form.is_submitted() or form.has_errors():
|
226
|
get_response().breadcrumb.append(('delete', _('Delete')))
|
227
|
r = TemplateIO(html=True)
|
228
|
html_top('payments', title = _('Delete Regie'))
|
229
|
r += htmltext('<h2>%s</h2>') % _('Deleting Regie: %s') % self.regie.label
|
230
|
r += form.render()
|
231
|
return r.getvalue()
|
232
|
else:
|
233
|
self.regie.remove_self()
|
234
|
return redirect('..')
|
235
|
|
236
|
def option_form(self):
|
237
|
form = Form(enctype='multipart/form-data')
|
238
|
module = eopayment.get_backend(self.regie.service)
|
239
|
service_options = {}
|
240
|
for infos in module.description['parameters']:
|
241
|
if 'default' in infos:
|
242
|
service_options[infos['name']] = infos['default']
|
243
|
service_options.update(self.regie.service_options or {})
|
244
|
|
245
|
banking_titles = {
|
246
|
('dummy', 'direct_notification_url'): N_('Direct Notification URL'),
|
247
|
('dummy', 'siret'): N_('Dummy SIRET'),
|
248
|
}
|
249
|
|
250
|
for infos in module.description['parameters']:
|
251
|
name = infos['name']
|
252
|
caption = infos.get('caption', name).encode(get_publisher().site_charset)
|
253
|
title = banking_titles.get((self.regie.service, name), caption)
|
254
|
kwargs = {}
|
255
|
widget = StringWidget
|
256
|
if infos.get('help_text') is not None:
|
257
|
kwargs['hint'] = _(infos['help_text'].encode(get_publisher().site_charset))
|
258
|
if infos.get('required', False):
|
259
|
kwargs['required'] = True
|
260
|
if infos.get('max_length') is not None:
|
261
|
kwargs['size'] = infos['max_length']
|
262
|
elif infos.get('length') is not None:
|
263
|
kwargs['size'] = infos['length']
|
264
|
else:
|
265
|
kwargs['size'] = 80
|
266
|
if kwargs['size'] > 100:
|
267
|
widget = TextWidget
|
268
|
kwargs['cols'] = 80
|
269
|
kwargs['rows'] = 5
|
270
|
if 'type' not in infos or infos['type'] is str:
|
271
|
form.add(widget, name, title=_(title),
|
272
|
value=service_options.get(name), **kwargs)
|
273
|
elif infos['type'] is bool:
|
274
|
form.add(CheckboxWidget, name, title=title,
|
275
|
value=service_options.get(name), **kwargs)
|
276
|
form.add_submit('submit', _('Submit'))
|
277
|
form.add_submit('cancel', _('Cancel'))
|
278
|
return form
|
279
|
|
280
|
def options(self):
|
281
|
r = TemplateIO(html=True)
|
282
|
form = self.option_form()
|
283
|
|
284
|
module = eopayment.get_backend(self.regie.service)
|
285
|
try:
|
286
|
r += htmltext('<!-- Payment backend description: \n')
|
287
|
r += pprint.pformat(module.description)
|
288
|
r += htmltext('-->')
|
289
|
except:
|
290
|
return template.error_page(_('Payment backend do not list its options'))
|
291
|
raise errors.TraversalError()
|
292
|
r += htmltext('<!-- \n')
|
293
|
r += 'Service options\n'
|
294
|
r += pprint.pformat(self.regie.service_options)
|
295
|
r += htmltext('-->')
|
296
|
|
297
|
if form.get_submit() == 'cancel':
|
298
|
return redirect('.')
|
299
|
|
300
|
if form.is_submitted() and not form.has_errors():
|
301
|
if self.submit_options(form, module):
|
302
|
return redirect('..')
|
303
|
|
304
|
html_top('payments', title=_('Edit Service Options'))
|
305
|
r += htmltext('<h2>%s</h2>') % _('Edit Service Options')
|
306
|
r += form.render()
|
307
|
return r.getvalue()
|
308
|
|
309
|
def submit_options(self, form, module):
|
310
|
# extra validation
|
311
|
error = False
|
312
|
for infos in module.description['parameters']:
|
313
|
widget = form.get_widget(infos['name'])
|
314
|
value = widget.parse()
|
315
|
if value and 'validation' in infos:
|
316
|
try:
|
317
|
if not infos['validation'](value):
|
318
|
widget.set_error(_('Valeur invalide'))
|
319
|
error = True
|
320
|
except ValueError, e:
|
321
|
widget.set_error(_(e.message))
|
322
|
error = True
|
323
|
if error:
|
324
|
return False
|
325
|
if not self.regie.service_options:
|
326
|
self.regie.service_options = {}
|
327
|
for infos in module.description['parameters']:
|
328
|
name = infos['name']
|
329
|
value = form.get_widget(name).parse()
|
330
|
if value is None:
|
331
|
value = ''
|
332
|
if hasattr(value, 'strip'):
|
333
|
value = value.strip()
|
334
|
if infos.get('default') is not None:
|
335
|
if value == infos['default']:
|
336
|
self.regie.service_options.pop(name, None)
|
337
|
else:
|
338
|
self.regie.service_options[name] = form.get_widget(name).parse()
|
339
|
elif not value:
|
340
|
self.regie.service_options.pop(name, None)
|
341
|
else:
|
342
|
self.regie.service_options[name] = form.get_widget(name).parse()
|
343
|
self.regie.store()
|
344
|
return True
|
345
|
|
346
|
PAGINATION = 50
|
347
|
|
348
|
def monetary_amount(self, val):
|
349
|
if not val:
|
350
|
return ''
|
351
|
if isinstance(val, basestring):
|
352
|
val = val.replace(',', '.')
|
353
|
return '%.2f' % decimal.Decimal(val)
|
354
|
|
355
|
def get_sort_by(self):
|
356
|
request = get_request()
|
357
|
sort_by = request.form.get('sort_by')
|
358
|
if sort_by not in ('date', 'paid_date', 'username'):
|
359
|
sort_by = 'date'
|
360
|
return sort_by
|
361
|
|
362
|
def get_invoices(self):
|
363
|
sort_by = self.get_sort_by()
|
364
|
invoices = Invoice.get_with_indexed_value('regie_id', self.regie.id,
|
365
|
ignore_errors=True)
|
366
|
if 'date' in sort_by:
|
367
|
reverse = True
|
368
|
key = lambda i: getattr(i, sort_by) or datetime.datetime.now()
|
369
|
else:
|
370
|
reverse = False
|
371
|
key = lambda i: getattr(i, sort_by) or ''
|
372
|
invoices.sort(reverse=reverse, key=key)
|
373
|
return invoices
|
374
|
|
375
|
def unpay(self, request, invoice):
|
376
|
get_logger().info(_('manually set unpaid invoice %(invoice_id)s in regie %(regie)s')
|
377
|
% dict(invoice_id=invoice.id, regie=self.regie.id))
|
378
|
transaction = Transaction()
|
379
|
transaction.invoice_ids = [ invoice.id ]
|
380
|
transaction.order_id = 'Manual action'
|
381
|
transaction.start = datetime.datetime.now()
|
382
|
transaction.end = transaction.start
|
383
|
transaction.bank_data = {
|
384
|
'action': 'Set unpaid',
|
385
|
'by': request.user.get_display_name() + ' (%s)' % request.user.id
|
386
|
}
|
387
|
transaction.store()
|
388
|
invoice.unpay()
|
389
|
|
390
|
def pay(self, request, invoice):
|
391
|
get_logger().info(_('manually set paid invoice %(invoice_id)s in regie %(regie)s')
|
392
|
% dict(invoice_id=invoice.id, regie=self.regie.id))
|
393
|
transaction = Transaction()
|
394
|
transaction.invoice_ids = [ invoice.id ]
|
395
|
transaction.order_id = 'Manual action'
|
396
|
transaction.start = datetime.datetime.now()
|
397
|
transaction.end = transaction.start
|
398
|
transaction.bank_data = {
|
399
|
'action': 'Set paid',
|
400
|
'by': request.user.get_display_name() + ' (%s)' % request.user.id
|
401
|
}
|
402
|
transaction.store()
|
403
|
invoice.pay()
|
404
|
|
405
|
def invoice_listing(self):
|
406
|
request = get_request()
|
407
|
get_response().add_css_include('../../themes/auquotidien/admin.css')
|
408
|
if request.get_method() == 'POST':
|
409
|
invoice_id = request.form.get('id')
|
410
|
invoice = Invoice.get(invoice_id, ignore_errors=True)
|
411
|
if invoice:
|
412
|
if 'unpay' in request.form:
|
413
|
self.unpay(request, invoice)
|
414
|
elif 'pay' in request.form:
|
415
|
self.pay(request, invoice)
|
416
|
return redirect('')
|
417
|
try:
|
418
|
offset = int(request.form.get('offset', 0))
|
419
|
except ValueError:
|
420
|
offset = 0
|
421
|
r = TemplateIO(html=True)
|
422
|
r += htmltext('<table id="invoice-listing" borderspacing="0">')
|
423
|
r += htmltext('<thead>')
|
424
|
r += htmltext('<tr>')
|
425
|
r += htmltext('<td><a href="?sort_by=date&offset=%d">Creation</a></td>') % offset
|
426
|
r += htmltext('<td>Amount</td>')
|
427
|
r += htmltext('<td><a href="?sort_by=paid_date&offset=%d">Paid</a></td>') % offset
|
428
|
r += htmltext('<td><a href="?sort_by=username&offset=%d">User</a></td>') % offset
|
429
|
r += htmltext('<td>Titre</td>')
|
430
|
r += htmltext('<td></td>')
|
431
|
r += htmltext('</tr>')
|
432
|
r += htmltext('</thead>')
|
433
|
invoices = self.get_invoices()
|
434
|
for invoice in invoices[offset:offset+self.PAGINATION]:
|
435
|
r += htmltext('<tbody class="invoice-rows">')
|
436
|
r += htmltext('<tr class="invoice-row"><td>')
|
437
|
r += misc.localstrftime(invoice.date)
|
438
|
r += htmltext('</td><td class="amount">')
|
439
|
r += self.monetary_amount(invoice.amount)
|
440
|
r += htmltext('</td><td>')
|
441
|
if invoice.paid:
|
442
|
r += misc.localstrftime(invoice.paid_date)
|
443
|
else:
|
444
|
r += ''
|
445
|
r += htmltext('</td><td>')
|
446
|
user = invoice.get_user()
|
447
|
if user:
|
448
|
r += user.name
|
449
|
r += htmltext('</td><td class="subject">%s</td>') % (invoice.subject or '')
|
450
|
r += htmltext('<td>')
|
451
|
r += htmltext('<form method="post">')
|
452
|
r += htmltext('<input type="hidden" name="id" value="%s"/> ') % invoice.id
|
453
|
if invoice.paid:
|
454
|
r += htmltext('<input type="submit" name="unpay" value="%s"/>') % _('Set unpaid')
|
455
|
else:
|
456
|
r += htmltext('<input type="submit" name="pay" value="%s"/>') % _('Set paid')
|
457
|
r += htmltext('</form>')
|
458
|
|
459
|
r += htmltext('</td></tr>')
|
460
|
transactions = Transaction.get_with_indexed_value('invoice_ids',
|
461
|
invoice.id)
|
462
|
for transaction in sorted(transactions, key=lambda x: x.start):
|
463
|
r += htmltext('<tr>')
|
464
|
r += htmltext('<td></td>')
|
465
|
r += htmltext('<td colspan="5">')
|
466
|
r += 'OrderID: %s' % transaction.order_id
|
467
|
r += ' Start: %s' % transaction.start
|
468
|
if transaction.end:
|
469
|
r += ' End: %s' % transaction.end
|
470
|
if transaction.bank_data:
|
471
|
r += ' Bank data: %r' % transaction.bank_data
|
472
|
r += htmltext('</td>')
|
473
|
r += htmltext('</tr>')
|
474
|
r += htmltext('</tbody>')
|
475
|
r += htmltext('</tbody></table>')
|
476
|
if offset != 0:
|
477
|
r += htmltext('<a href="?offset=%d>%s</a> ') % (
|
478
|
max(0, offset-self.PAGINATION), _('Previous'))
|
479
|
if offset + self.PAGINATION < len(invoices):
|
480
|
r += htmltext('<a href="?offset=%d>%s</a> ') % (
|
481
|
max(0, offset-self.PAGINATION), _('Previous'))
|
482
|
return r.getvalue()
|
483
|
|
484
|
|
485
|
class RegiesDirectory(Directory):
|
486
|
_q_exports = ['', 'new']
|
487
|
|
488
|
def _q_traverse(self, path):
|
489
|
get_response().breadcrumb.append(('regie/', _('Regies')))
|
490
|
return Directory._q_traverse(self, path)
|
491
|
|
492
|
def _q_index(self):
|
493
|
return redirect('..')
|
494
|
|
495
|
def new(self):
|
496
|
regie_ui = RegieDirectory(Regie())
|
497
|
|
498
|
form = regie_ui.form()
|
499
|
if form.get_submit() == 'cancel':
|
500
|
return redirect('.')
|
501
|
|
502
|
if form.is_submitted() and not form.has_errors():
|
503
|
regie_ui.submit(form)
|
504
|
return redirect('%s/' % regie_ui.regie.id)
|
505
|
|
506
|
get_response().breadcrumb.append(('new', _('New Regie')))
|
507
|
html_top('payments', title = _('New Regie'))
|
508
|
r = TemplateIO(html=True)
|
509
|
r += htmltext('<h2>%s</h2>') % _('New Regie')
|
510
|
r += form.render()
|
511
|
return r.getvalue()
|
512
|
|
513
|
def _q_lookup(self, component):
|
514
|
try:
|
515
|
regie = Regie.get(component)
|
516
|
except KeyError:
|
517
|
raise errors.TraversalError()
|
518
|
get_response().breadcrumb.append((str(regie.id), regie.label))
|
519
|
return RegieDirectory(regie)
|
520
|
|
521
|
|
522
|
class PaymentsDirectory(AccessControlled, Directory):
|
523
|
_q_exports = ['', 'regie']
|
524
|
label = N_('Payments')
|
525
|
|
526
|
regie = RegiesDirectory()
|
527
|
|
528
|
def is_accessible(self, user):
|
529
|
from .backoffice import check_visibility
|
530
|
return check_visibility('payments', user)
|
531
|
|
532
|
def _q_access(self):
|
533
|
user = get_request().user
|
534
|
if not user:
|
535
|
raise errors.AccessUnauthorizedError()
|
536
|
|
537
|
if not self.is_accessible(user):
|
538
|
raise errors.AccessForbiddenError(
|
539
|
public_msg = _('You are not allowed to access Payments Management'),
|
540
|
location_hint = 'backoffice')
|
541
|
|
542
|
get_response().breadcrumb.append(('payments/', _('Payments')))
|
543
|
|
544
|
def _q_index(self):
|
545
|
html_top('payments', _('Payments'))
|
546
|
get_response().filter['sidebar'] = self.get_sidebar()
|
547
|
r = TemplateIO(html=True)
|
548
|
|
549
|
if not is_payment_supported:
|
550
|
r += htmltext('<p class="infonotice">')
|
551
|
r += _('Payment is not supported.')
|
552
|
r += htmltext('</p>')
|
553
|
|
554
|
regies = Regie.select()
|
555
|
r += htmltext('<h2>%s</h2>') % _('Regies')
|
556
|
if not regies:
|
557
|
r += htmltext('<p>')
|
558
|
r += _('There are no regies defined at the moment.')
|
559
|
r += htmltext('</p>')
|
560
|
r += htmltext('<ul class="biglist" id="regies-list">')
|
561
|
for l in regies:
|
562
|
regie_id = l.id
|
563
|
r += htmltext('<li class="biglistitem" id="itemId_%s">') % regie_id
|
564
|
r += htmltext('<strong class="label"><a href="regie/%s/">%s</a></strong>') % (regie_id, l.label)
|
565
|
r += htmltext('</li>')
|
566
|
r += htmltext('</ul>')
|
567
|
return r.getvalue()
|
568
|
|
569
|
def get_sidebar(self):
|
570
|
r = TemplateIO(html=True)
|
571
|
r += htmltext('<ul id="sidebar-actions">')
|
572
|
r += htmltext(' <li><a class="new-item" href="regie/new">%s</a></li>') % _('New Regie')
|
573
|
r += htmltext('</ul>')
|
574
|
return r.getvalue()
|
575
|
|
576
|
|
577
|
TextsDirectory.register('aq-invoice',
|
578
|
N_('Message on top of an invoice'),
|
579
|
category = N_('Invoices'))
|
580
|
|
581
|
EmailsDirectory.register('payment-new-invoice-email',
|
582
|
N_('New invoice'),
|
583
|
N_('Available variables: user, regie, invoice, invoice_url'),
|
584
|
category = N_('Invoices'),
|
585
|
default_subject = N_('New invoice'),
|
586
|
default_body = N_('''
|
587
|
A new invoice is available at [invoice_url].
|
588
|
'''))
|
589
|
|
590
|
EmailsDirectory.register('payment-invoice-paid-email',
|
591
|
N_('Paid invoice'),
|
592
|
N_('Available variables: user, regie, invoice, invoice_url'),
|
593
|
category = N_('Invoices'),
|
594
|
default_subject = N_('Paid invoice'),
|
595
|
default_body = N_('''
|
596
|
The invoice [invoice_url] has been paid.
|
597
|
'''))
|
598
|
|
599
|
EmailsDirectory.register('payment-invoice-canceled-email',
|
600
|
N_('Canceled invoice'),
|
601
|
N_('Available variables: user, regie, invoice, invoice_url'),
|
602
|
category = N_('Invoices'),
|
603
|
default_subject = N_('Canceled invoice'),
|
604
|
default_body = N_('''
|
605
|
The invoice [invoice.id] has been canceled.
|
606
|
'''))
|