1
|
import time
|
2
|
|
3
|
from quixote import get_request, get_response, get_session, redirect
|
4
|
from quixote.directory import Directory, AccessControlled
|
5
|
|
6
|
import wcs
|
7
|
import wcs.admin.root
|
8
|
from wcs.backoffice.menu import *
|
9
|
from wcs.formdef import FormDef
|
10
|
|
11
|
from qommon import errors, misc, template
|
12
|
from qommon.form import *
|
13
|
from qommon.strftime import strftime
|
14
|
|
15
|
from payments import eopayment, Regie, is_payment_supported, Invoice
|
16
|
|
17
|
from qommon.admin.texts import TextsDirectory
|
18
|
|
19
|
if not set:
|
20
|
from sets import Set as set
|
21
|
|
22
|
def invoice_as_html [html] (invoice):
|
23
|
'<div id="invoice">'
|
24
|
'<h2>%s</h2>' % _('Invoice: %s') % invoice.subject
|
25
|
'<h3>%s' % _('Amount: %s') % invoice.amount
|
26
|
' €</h3>'
|
27
|
if invoice.formdef_id and invoice.formdata_id and \
|
28
|
get_session().user == invoice.user_id:
|
29
|
formdef = FormDef.get(invoice.formdef_id)
|
30
|
formdata = formdef.data_class().get(invoice.formdata_id)
|
31
|
name = _('%(form_name)s #%(formdata_id)s') % {
|
32
|
'form_name': formdata.formdef.name,
|
33
|
'formdata_id': formdata.id }
|
34
|
'<p class="from">%s <a href="%s">%s</a></p>' % (_('From:'), formdata.get_url(), name)
|
35
|
'<p class="regie">%s</p>' % _('Regie: %s') % Regie.get(invoice.regie_id).label
|
36
|
'<p class="date">%s</p>' % _('Created on: %s') % misc.localstrftime(invoice.date)
|
37
|
if invoice.details:
|
38
|
'<p class="details">%s</p>' % _('Details:')
|
39
|
'<div class="details">'
|
40
|
htmltext(invoice.details)
|
41
|
'</div>'
|
42
|
if invoice.canceled:
|
43
|
'<p class="canceled">'
|
44
|
'%s' % _('canceled on %s') % misc.localstrftime(invoice.canceled_date)
|
45
|
if invoice.canceled_reason:
|
46
|
' (%s)' % invoice.canceled_reason
|
47
|
'</p>'
|
48
|
if invoice.paid:
|
49
|
'<p class="paid">%s</p>' % _('paid on %s') % misc.localstrftime(invoice.paid_date)
|
50
|
'</div>'
|
51
|
|
52
|
class InvoicesDirectory(Directory):
|
53
|
_q_exports = ['', 'multiple']
|
54
|
|
55
|
def _q_traverse(self, path):
|
56
|
if not is_payment_supported():
|
57
|
raise errors.TraversalError()
|
58
|
get_response().filter['bigdiv'] = 'profile'
|
59
|
if get_session().user:
|
60
|
# fake breadcrumb
|
61
|
get_response().breadcrumb.append(('myspace/', _('My Space')))
|
62
|
get_response().breadcrumb.append(('invoices/', _('Invoices')))
|
63
|
return Directory._q_traverse(self, path)
|
64
|
|
65
|
def multiple [html] (self):
|
66
|
invoice_ids = get_request().form.get('invoice')
|
67
|
if type(invoice_ids) is not list:
|
68
|
return redirect('%s' % invoice_ids)
|
69
|
return redirect('+'.join(invoice_ids))
|
70
|
|
71
|
def _q_lookup [html] (self, component):
|
72
|
if str('+') in component:
|
73
|
invoice_ids = component.split(str('+'))
|
74
|
else:
|
75
|
invoice_ids = [component]
|
76
|
for invoice_id in invoice_ids:
|
77
|
if not Invoice.check_crc(invoice_id):
|
78
|
raise errors.TraversalError()
|
79
|
|
80
|
template.html_top(_('Invoices'))
|
81
|
TextsDirectory.get_html_text('aq-invoice')
|
82
|
|
83
|
regies_id = set()
|
84
|
for invoice_id in invoice_ids:
|
85
|
try:
|
86
|
invoice = Invoice.get(invoice_id)
|
87
|
except KeyError:
|
88
|
raise errors.TraversalError()
|
89
|
invoice_as_html(invoice)
|
90
|
if not (invoice.paid or invoice.canceled):
|
91
|
regies_id.add(invoice.regie_id)
|
92
|
|
93
|
if len(regies_id) == 1:
|
94
|
'<p class="command">'
|
95
|
'<a href="%s/payment/init?invoice_ids=%s">' % (get_publisher().get_frontoffice_url(), component)
|
96
|
if len(invoice_ids) > 1:
|
97
|
_('Pay Selected Invoices')
|
98
|
else:
|
99
|
_('Pay')
|
100
|
'</a></p>'
|
101
|
if len(regies_id) > 1:
|
102
|
_('You can not pay to different regies.')
|
103
|
|
104
|
def _q_index(self):
|
105
|
return redirect('..')
|
106
|
|
107
|
|
108
|
class RegieDirectory(Directory):
|
109
|
_q_exports = ['', 'edit', 'delete', 'options']
|
110
|
|
111
|
def __init__(self, regie):
|
112
|
self.regie = regie
|
113
|
|
114
|
def _q_index [html] (self):
|
115
|
form = Form(enctype='multipart/form-data')
|
116
|
form.add_submit('edit', _('Edit'))
|
117
|
form.add_submit('delete', _('Delete'))
|
118
|
form.add_submit('back', _('Back'))
|
119
|
|
120
|
if form.get_submit() == 'edit':
|
121
|
return redirect('edit')
|
122
|
if form.get_submit() == 'delete':
|
123
|
return redirect('delete')
|
124
|
if form.get_submit() == 'back':
|
125
|
return redirect('..')
|
126
|
|
127
|
html_top('payments', title = _('Regie: %s') % self.regie.label)
|
128
|
'<h2>%s</h2>' % _('Regie: %s') % self.regie.label
|
129
|
|
130
|
get_session().display_message()
|
131
|
|
132
|
if self.regie.description:
|
133
|
'<p>'
|
134
|
self.regie.description
|
135
|
'</p>'
|
136
|
|
137
|
if self.regie.service:
|
138
|
'<p>'
|
139
|
'%s %s' % (_('Banking Service:'), self.regie.service)
|
140
|
' (<a href="options">%s</a>)' % _('options')
|
141
|
'</p>'
|
142
|
|
143
|
form.render()
|
144
|
|
145
|
def edit [html] (self):
|
146
|
form = self.form()
|
147
|
if form.get_submit() == 'cancel':
|
148
|
return redirect('.')
|
149
|
|
150
|
if form.is_submitted() and not form.has_errors():
|
151
|
self.submit(form)
|
152
|
return redirect('..')
|
153
|
|
154
|
html_top('payments', title = _('Edit Regie: %s') % self.regie.label)
|
155
|
'<h2>%s</h2>' % _('Edit Regie: %s') % self.regie.label
|
156
|
form.render()
|
157
|
|
158
|
|
159
|
def form(self):
|
160
|
form = Form(enctype='multipart/form-data')
|
161
|
form.add(StringWidget, 'label', title=_('Label'), required=True,
|
162
|
value=self.regie.label)
|
163
|
form.add(TextWidget, 'description', title=_('Description'),
|
164
|
value=self.regie.description, rows=5, cols=60)
|
165
|
form.add(SingleSelectWidget, 'service', title=_('Banking Service'),
|
166
|
value=self.regie.service, required=True,
|
167
|
options = [
|
168
|
('dummy', _('Dummy (for tests)')),
|
169
|
('sips', 'SIPS'),
|
170
|
('systempayv2', 'systempay (Banque Populaire)'),
|
171
|
('spplus', _('SP+ (Caisse d\'epargne)'))])
|
172
|
form.add_submit('submit', _('Submit'))
|
173
|
form.add_submit('cancel', _('Cancel'))
|
174
|
return form
|
175
|
|
176
|
def submit(self, form):
|
177
|
for k in ('label', 'description', 'service'):
|
178
|
widget = form.get_widget(k)
|
179
|
if widget:
|
180
|
setattr(self.regie, k, widget.parse())
|
181
|
self.regie.store()
|
182
|
|
183
|
def delete [html] (self):
|
184
|
form = Form(enctype='multipart/form-data')
|
185
|
form.widgets.append(HtmlWidget('<p>%s</p>' % _(
|
186
|
'You are about to irrevocably delete this regie.')))
|
187
|
form.add_submit('submit', _('Submit'))
|
188
|
form.add_submit('cancel', _('Cancel'))
|
189
|
if form.get_submit() == 'cancel':
|
190
|
return redirect('..')
|
191
|
if not form.is_submitted() or form.has_errors():
|
192
|
get_response().breadcrumb.append(('delete', _('Delete')))
|
193
|
html_top('payments', title = _('Delete Regie'))
|
194
|
'<h2>%s</h2>' % _('Deleting Regie: %s') % self.regie.label
|
195
|
form.render()
|
196
|
else:
|
197
|
self.regie.remove_self()
|
198
|
return redirect('..')
|
199
|
|
200
|
def options [html] (self):
|
201
|
form = Form(enctype='multipart/form-data')
|
202
|
module = eopayment.get_backend(self.regie.service)
|
203
|
try:
|
204
|
'<!-- \n'
|
205
|
module.description['parameters']
|
206
|
'-->'
|
207
|
except:
|
208
|
return template.error_page(_('Payment backend do not list its options'))
|
209
|
raise errors.TraversalError()
|
210
|
service_options = self.regie.service_options or {}
|
211
|
banking_titles = {
|
212
|
('dummy', 'direct_notification_url'): N_('Direct Notification URL'),
|
213
|
('dummy', 'siret'): N_('Dummy SIRET'),
|
214
|
}
|
215
|
for parameter, infos in module.description['parameters'].items():
|
216
|
title = banking_titles.get((self.regie.service, parameter), infos.get('caption'))
|
217
|
if 'type' not in infos or infos['type'] is str:
|
218
|
form.add(StringWidget, parameter, title=title,
|
219
|
value=service_options.get(parameter))
|
220
|
elif infos['type'] is bool:
|
221
|
form.add(CheckboxWidget, parameter, title=title,
|
222
|
value=service_options.get(parameter))
|
223
|
form.add_submit('submit', _('Submit'))
|
224
|
form.add_submit('cancel', _('Cancel'))
|
225
|
|
226
|
if form.get_submit() == 'cancel':
|
227
|
return redirect('.')
|
228
|
|
229
|
if form.is_submitted() and not form.has_errors():
|
230
|
self.submit_options(form, module)
|
231
|
return redirect('..')
|
232
|
|
233
|
html_top('payments', title=_('Edit Service Options'))
|
234
|
'<h2>%s</h2>' % _('Edit Service Options')
|
235
|
form.render()
|
236
|
|
237
|
def submit_options(self, form, module):
|
238
|
if not self.regie.service_options:
|
239
|
self.regie.service_options = {}
|
240
|
for parameter, infos in module.description['parameters'].items():
|
241
|
self.regie.service_options[parameter] = form.get_widget(parameter).parse()
|
242
|
self.regie.store()
|
243
|
|
244
|
class RegiesDirectory(Directory):
|
245
|
_q_exports = ['', 'new']
|
246
|
|
247
|
def _q_traverse(self, path):
|
248
|
get_response().breadcrumb.append(('regie/', _('Regies')))
|
249
|
return Directory._q_traverse(self, path)
|
250
|
|
251
|
def _q_index [html] (self):
|
252
|
return redirect('..')
|
253
|
|
254
|
def new [html] (self):
|
255
|
regie_ui = RegieDirectory(Regie())
|
256
|
|
257
|
form = regie_ui.form()
|
258
|
if form.get_submit() == 'cancel':
|
259
|
return redirect('.')
|
260
|
|
261
|
if form.is_submitted() and not form.has_errors():
|
262
|
regie_ui.submit(form)
|
263
|
return redirect('%s/' % regie_ui.regie.id)
|
264
|
|
265
|
get_response().breadcrumb.append(('new', _('New Regie')))
|
266
|
html_top('payments', title = _('New Regie'))
|
267
|
'<h2>%s</h2>' % _('New Regie')
|
268
|
form.render()
|
269
|
|
270
|
def _q_lookup(self, component):
|
271
|
try:
|
272
|
regie = Regie.get(component)
|
273
|
except KeyError:
|
274
|
raise errors.TraversalError()
|
275
|
get_response().breadcrumb.append((str(regie.id), regie.label))
|
276
|
return RegieDirectory(regie)
|
277
|
|
278
|
|
279
|
class PaymentsDirectory(AccessControlled, Directory):
|
280
|
_q_exports = ['', 'regie']
|
281
|
label = N_('Payments')
|
282
|
|
283
|
regie = RegiesDirectory()
|
284
|
|
285
|
def _q_access(self):
|
286
|
user = get_request().user
|
287
|
if not user:
|
288
|
raise errors.AccessUnauthorizedError()
|
289
|
admin_role = get_cfg('aq-permissions', {}).get('payments', None)
|
290
|
if not (user.is_admin or admin_role in (user.roles or [])):
|
291
|
raise errors.AccessForbiddenError(
|
292
|
public_msg = _('You are not allowed to access Payments Management'),
|
293
|
location_hint = 'backoffice')
|
294
|
|
295
|
get_response().breadcrumb.append(('payments/', _('Payments')))
|
296
|
|
297
|
|
298
|
def _q_index [html] (self):
|
299
|
html_top('payments', _('Payments'))
|
300
|
|
301
|
'<ul id="main-actions">'
|
302
|
' <li><a class="new-item" href="regie/new">%s</a></li>' % _('New Regie')
|
303
|
'</ul>'
|
304
|
|
305
|
if not is_payment_supported:
|
306
|
'<p class="infonotice">'
|
307
|
_('Payment is not supported.')
|
308
|
'</p>'
|
309
|
|
310
|
regies = Regie.select()
|
311
|
'<h2>%s</h2>' % _('Regies')
|
312
|
if not regies:
|
313
|
'<p>'
|
314
|
_('There are no regies defined at the moment.')
|
315
|
'</p>'
|
316
|
'<ul class="biglist" id="regies-list">'
|
317
|
for l in regies:
|
318
|
regie_id = l.id
|
319
|
'<li class="biglistitem" id="itemId_%s">' % regie_id
|
320
|
'<strong class="label"><a href="regie/%s/">%s</a></strong>' % (regie_id, l.label)
|
321
|
'<p class="commands">'
|
322
|
command_icon('regie/%s/edit' % regie_id, 'edit')
|
323
|
command_icon('regie/%s/delete' % regie_id, 'remove')
|
324
|
'</p></li>'
|
325
|
'</ul>'
|
326
|
|
327
|
|
328
|
TextsDirectory.register('aq-invoice',
|
329
|
N_('Message on top of an invoice'),
|
330
|
category = N_('Invoices'))
|