Projet

Général

Profil

Télécharger (14,2 ko) Statistiques
| Branche: | Tag: | Révision:

root / extra / modules / payments_ui.ptl @ e8e6dedb

1
import time
2
import pprint
3

    
4
from quixote import get_request, get_response, get_session, redirect
5
from quixote.directory import Directory, AccessControlled
6

    
7
import wcs
8
import wcs.admin.root
9
from wcs.backoffice.menu import *
10
from wcs.formdef import FormDef
11

    
12
from qommon import errors, misc, template
13
from qommon.form import *
14
from qommon.strftime import strftime
15

    
16
from payments import eopayment, Regie, is_payment_supported, Invoice, Transaction
17

    
18
from qommon.admin.texts import TextsDirectory
19

    
20
if not set:
21
    from sets import Set as set
22

    
23
def invoice_as_html [html] (invoice):
24
    '<div id="invoice">'
25
    '<h2>%s</h2>' % _('Invoice: %s') % invoice.subject
26
    '<h3>%s' % _('Amount: %s') % invoice.amount
27
    ' &euro;</h3>'
28
    '<!-- DEBUG \n'
29
    'Invoice:\n'
30
    pprint.pformat(invoice.__dict__)
31
    for transaction in Transaction.get_with_indexed_value('invoice_ids', invoice.id):
32
        '\nTransaction:\n'
33
        pprint.pformat(transaction.__dict__)
34
    '\n-->'
35
    if invoice.formdef_id and invoice.formdata_id and \
36
            get_session().user == invoice.user_id:
37
        formdef = FormDef.get(invoice.formdef_id)
38
        if formdef:
39
            formdata = formdef.data_class().get(invoice.formdata_id, ignore_errors=True)
40
            if formdata:
41
                name = _('%(form_name)s #%(formdata_id)s') % {
42
                        'form_name': formdata.formdef.name,
43
                        'formdata_id': formdata.id }
44
                '<p class="from">%s <a href="%s">%s</a></p>' % (_('From:'), formdata.get_url(), name)
45
    '<p class="regie">%s</p>' % _('Regie: %s') % Regie.get(invoice.regie_id).label
46
    '<p class="date">%s</p>' % _('Created on: %s') % misc.localstrftime(invoice.date)
47
    if invoice.details:
48
        '<p class="details">%s</p>' % _('Details:')
49
        '<div class="details">'
50
        htmltext(invoice.details)
51
        '</div>'
52
    if invoice.canceled:
53
        '<p class="canceled">'
54
        '%s' % _('canceled on %s') % misc.localstrftime(invoice.canceled_date)
55
        if invoice.canceled_reason:
56
            ' (%s)' % invoice.canceled_reason
57
        '</p>'
58
    if invoice.paid:
59
        '<p class="paid">%s</p>' % _('paid on %s') % misc.localstrftime(invoice.paid_date)
60
    '</div>'
61

    
62
class InvoicesDirectory(Directory):
63
    _q_exports = ['', 'multiple']
64

    
65
    def _q_traverse(self, path):
66
        if not is_payment_supported():
67
            raise errors.TraversalError()
68
        get_response().filter['bigdiv'] = 'profile'
69
        if get_session().user:
70
            # fake breadcrumb
71
            get_response().breadcrumb.append(('myspace/', _('My Space')))
72
            get_response().breadcrumb.append(('invoices/', _('Invoices')))
73
        return Directory._q_traverse(self, path)
74

    
75
    def multiple [html] (self):
76
        invoice_ids = get_request().form.get('invoice')
77
        if type(invoice_ids) is not list:
78
            return redirect('%s' % invoice_ids)
79
        return redirect('+'.join(invoice_ids))
80

    
81
    def _q_lookup [html] (self, component):
82
        if str('+') in component:
83
            invoice_ids = component.split(str('+'))
84
        else:
85
            invoice_ids = [component]
86
        for invoice_id in invoice_ids:
87
            if not Invoice.check_crc(invoice_id):
88
                raise errors.TraversalError()
89

    
90
        template.html_top(_('Invoices'))
91
        TextsDirectory.get_html_text('aq-invoice')
92

    
93
        regies_id = set()
94
        for invoice_id in invoice_ids:
95
            try:
96
                invoice = Invoice.get(invoice_id)
97
            except KeyError:
98
                raise errors.TraversalError()
99
            invoice_as_html(invoice)
100
            if not (invoice.paid or invoice.canceled):
101
                regies_id.add(invoice.regie_id)
102

    
103
        if len(regies_id) == 1:
104
            '<p class="command">'
105
            '<a href="%s/payment/init?invoice_ids=%s">' % (get_publisher().get_frontoffice_url(), component)
106
            if len(invoice_ids) > 1:
107
                _('Pay Selected Invoices')
108
            else:
109
                _('Pay')
110
            '</a></p>'
111
        if len(regies_id) > 1:
112
            _('You can not pay to different regies.')
113

    
114
    def _q_index(self):
115
        return redirect('..')
116

    
117

    
118
class RegieDirectory(Directory):
119
    _q_exports = ['', 'edit', 'delete', 'options']
120

    
121
    def __init__(self, regie):
122
        self.regie = regie
123

    
124
    def _q_index [html] (self):
125
        html_top('payments', title = _('Regie: %s') % self.regie.label)
126
        get_response().filter['sidebar'] = self.get_sidebar()
127
        '<h2>%s</h2>' % _('Regie: %s') % self.regie.label
128

    
129
        get_session().display_message()
130

    
131
        if self.regie.description:
132
            '<div class="bo-block">'
133
            '<p>'
134
            self.regie.description
135
            '</p>'
136
            '</div>'
137

    
138
        if self.regie.service:
139
            '<div class="bo-block">'
140
            url = get_publisher().get_frontoffice_url() + '/payment/back_asynchronous/'
141
            url += str(self.regie.id)
142
            '<p>'
143
            '%s %s' % (_('Banking Service:'), self.regie.service)
144
            ' (<a href="options">%s</a>)' % _('options')
145
            '</p>'
146
            '<p>'
147
            '%s %s' % (_('Payment notification URL:'), url)
148
            '</div>'
149

    
150
    def get_sidebar [html] (self):
151
        '<ul>'
152
        '<li><a href="edit">%s</a></li>' % _('Edit')
153
        '<li><a href="delete">%s</a></li>' % _('Delete')
154
        '</ul>'
155

    
156
    def edit [html] (self):
157
        form = self.form()
158
        if form.get_submit() == 'cancel':
159
            return redirect('.')
160

    
161
        if form.is_submitted() and not form.has_errors():
162
            self.submit(form)
163
            return redirect('..')
164

    
165
        html_top('payments', title = _('Edit Regie: %s') % self.regie.label)
166
        '<h2>%s</h2>' % _('Edit Regie: %s') % self.regie.label
167
        form.render()
168

    
169

    
170
    def form(self):
171
        form = Form(enctype='multipart/form-data')
172
        form.add(StringWidget, 'label', title=_('Label'), required=True,
173
                value=self.regie.label)
174
        form.add(TextWidget, 'description', title=_('Description'),
175
                value=self.regie.description, rows=5, cols=60)
176
        form.add(SingleSelectWidget, 'service', title=_('Banking Service'),
177
                value=self.regie.service, required=True,
178
                options = [
179
                        ('dummy', _('Dummy (for tests)')),
180
                        ('sips', 'SIPS'),
181
                        ('systempayv2', 'systempay (Banque Populaire)'),
182
                        ('spplus', _('SP+ (Caisse d\'epargne)'))])
183
        form.add_submit('submit', _('Submit'))
184
        form.add_submit('cancel', _('Cancel'))
185
        return form
186

    
187
    def submit(self, form):
188
        for k in ('label', 'description', 'service'):
189
            widget = form.get_widget(k)
190
            if widget:
191
                setattr(self.regie, k, widget.parse())
192
        self.regie.store()
193

    
194
    def delete [html] (self):
195
        form = Form(enctype='multipart/form-data')
196
        form.widgets.append(HtmlWidget('<p>%s</p>' % _(
197
                        'You are about to irrevocably delete this regie.')))
198
        form.add_submit('submit', _('Submit'))
199
        form.add_submit('cancel', _('Cancel'))
200
        if form.get_submit() == 'cancel':
201
            return redirect('..')
202
        if not form.is_submitted() or form.has_errors():
203
            get_response().breadcrumb.append(('delete', _('Delete')))
204
            html_top('payments', title = _('Delete Regie'))
205
            '<h2>%s</h2>' % _('Deleting Regie: %s') % self.regie.label
206
            form.render()
207
        else:
208
            self.regie.remove_self()
209
            return redirect('..')
210

    
211
    def option_form(self):
212
        form = Form(enctype='multipart/form-data')
213
        module = eopayment.get_backend(self.regie.service)
214
        service_options = {}
215
        for infos in module.description['parameters']:
216
            if 'default' in infos:
217
                service_options[infos['name']] = infos['default']
218
        service_options.update(self.regie.service_options or {})
219

    
220
        banking_titles = {
221
            ('dummy', 'direct_notification_url'): N_('Direct Notification URL'),
222
            ('dummy', 'siret'): N_('Dummy SIRET'),
223
        }
224

    
225
        print module
226
        for infos in module.description['parameters']:
227
            name = infos['name']
228
            caption = infos.get('caption', name).encode(get_publisher().site_charset)
229
            title = banking_titles.get((self.regie.service, name), caption)
230
            kwargs = {}
231
            widget = StringWidget
232
            if infos.get('help_text') is not None:
233
                kwargs['hint'] = _(infos['help_text'].encode(get_publisher().site_charset))
234
            if infos.get('required', False):
235
                kwargs['required'] = True
236
            if infos.get('max_length') is not None:
237
                kwargs['size'] = infos['max_length']
238
            elif infos.get('length') is not None:
239
                kwargs['size'] = infos['length']
240
            else:
241
                kwargs['size'] = 80
242
            if kwargs['size'] > 100:
243
                widget = TextWidget
244
                kwargs['cols'] = 80
245
                kwargs['rows'] = 5
246
            if 'type' not in infos or infos['type'] is str:
247
                form.add(widget, name, title=_(title),
248
                         value=service_options.get(name), **kwargs)
249
            elif infos['type'] is bool:
250
                form.add(CheckboxWidget, name, title=title,
251
                         value=service_options.get(name), **kwargs)
252
        form.add_submit('submit', _('Submit'))
253
        form.add_submit('cancel', _('Cancel'))
254
        return form
255

    
256
    def options [html] (self):
257
        form = self.option_form()
258

    
259
        module = eopayment.get_backend(self.regie.service)
260
        try:
261
            '<!-- Payment backend description: \n'
262
            pprint.pformat(module.description)
263
            '-->'
264
        except:
265
            return template.error_page(_('Payment backend do not list its options'))
266
            raise errors.TraversalError()
267
        '<!-- \n'
268
        'Service options\n'
269
        pprint.pformat(self.regie.service_options)
270
        '-->'
271

    
272
        if form.get_submit() == 'cancel':
273
            return redirect('.')
274

    
275
        if form.is_submitted() and not form.has_errors():
276
             if self.submit_options(form, module):
277
                return redirect('..')
278

    
279
        html_top('payments', title=_('Edit Service Options'))
280
        '<h2>%s</h2>' % _('Edit Service Options')
281
        form.render()
282

    
283
    def submit_options(self, form, module):
284
        # extra validation
285
        error = False
286
        for infos in module.description['parameters']:
287
            widget = form.get_widget(infos['name'])
288
            value = widget.parse()
289
            if value and 'validation' in infos:
290
                try:
291
                    if not infos['validation'](value):
292
                        widget.set_error(_('Valeur invalide'))
293
                        error = True
294
                except ValueError, e:
295
                    widget.set_error(_(e.message))
296
                    error = True
297
        if error:
298
            return False
299
        if not self.regie.service_options:
300
            self.regie.service_options = {}
301
        for infos in module.description['parameters']:
302
            name = infos['name']
303
            value = form.get_widget(name).parse()
304
            if value is None:
305
                value = ''
306
            value = value.strip()
307
            if infos.get('default') is not None:
308
                if value == infos['default']:
309
                    self.regie.service_options.pop(name, None)
310
                else:
311
                    self.regie.service_options[name] = form.get_widget(name).parse()
312
            elif not value:
313
                self.regie.service_options.pop(name, None)
314
            else:
315
                self.regie.service_options[name] = form.get_widget(name).parse()
316
        self.regie.store()
317
        return True
318

    
319
class RegiesDirectory(Directory):
320
    _q_exports = ['', 'new']
321

    
322
    def _q_traverse(self, path):
323
        get_response().breadcrumb.append(('regie/', _('Regies')))
324
        return Directory._q_traverse(self, path)
325

    
326
    def _q_index [html] (self):
327
        return redirect('..')
328

    
329
    def new [html] (self):
330
        regie_ui = RegieDirectory(Regie())
331

    
332
        form = regie_ui.form()
333
        if form.get_submit() == 'cancel':
334
            return redirect('.')
335

    
336
        if form.is_submitted() and not form.has_errors():
337
            regie_ui.submit(form)
338
            return redirect('%s/' % regie_ui.regie.id)
339

    
340
        get_response().breadcrumb.append(('new', _('New Regie')))
341
        html_top('payments', title = _('New Regie'))
342
        '<h2>%s</h2>' % _('New Regie')
343
        form.render()
344

    
345
    def _q_lookup(self, component):
346
        try:
347
            regie = Regie.get(component)
348
        except KeyError:
349
            raise errors.TraversalError()
350
        get_response().breadcrumb.append((str(regie.id), regie.label))
351
        return RegieDirectory(regie)
352

    
353

    
354
class PaymentsDirectory(AccessControlled, Directory):
355
    _q_exports = ['', 'regie']
356
    label = N_('Payments')
357

    
358
    regie = RegiesDirectory()
359

    
360
    def _q_access(self):
361
        user = get_request().user
362
        if not user:
363
            raise errors.AccessUnauthorizedError()
364
        admin_role = get_cfg('aq-permissions', {}).get('payments', None)
365
        if not (user.is_admin or admin_role in (user.roles or [])):
366
            raise errors.AccessForbiddenError(
367
                    public_msg = _('You are not allowed to access Payments Management'),
368
                    location_hint = 'backoffice')
369

    
370
        get_response().breadcrumb.append(('payments/', _('Payments')))
371

    
372

    
373
    def _q_index [html] (self):
374
        html_top('payments', _('Payments'))
375

    
376
        '<ul id="main-actions">'
377
        '  <li><a class="new-item" href="regie/new">%s</a></li>' % _('New Regie')
378
        '</ul>'
379

    
380
        if not is_payment_supported:
381
            '<p class="infonotice">'
382
            _('Payment is not supported.')
383
            '</p>'
384

    
385
        regies = Regie.select()
386
        '<h2>%s</h2>' % _('Regies')
387
        if not regies:
388
            '<p>'
389
            _('There are no regies defined at the moment.')
390
            '</p>'
391
        '<ul class="biglist" id="regies-list">'
392
        for l in regies:
393
            regie_id = l.id
394
            '<li class="biglistitem" id="itemId_%s">' % regie_id
395
            '<strong class="label"><a href="regie/%s/">%s</a></strong>' % (regie_id, l.label)
396
            '</li>'
397
        '</ul>'
398

    
399

    
400
TextsDirectory.register('aq-invoice',
401
        N_('Message on top of an invoice'),
402
        category = N_('Invoices'))
(27-27/32)