source: main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser.py @ 12486

Last change on this file since 12486 was 12486, checked in by Henrik Bettermann, 10 years ago

Rename interface.

  • Property svn:keywords set to Id
File size: 53.2 KB
Line 
1## $Id: browser.py 12486 2015-01-18 09:38:57Z henrik $
2##
3## Copyright (C) 2014 Uli Fouquet & Henrik Bettermann
4## This program is free software; you can redistribute it and/or modify
5## it under the terms of the GNU General Public License as published by
6## the Free Software Foundation; either version 2 of the License, or
7## (at your option) any later version.
8##
9## This program is distributed in the hope that it will be useful,
10## but WITHOUT ANY WARRANTY; without even the implied warranty of
11## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12## GNU General Public License for more details.
13##
14## You should have received a copy of the GNU General Public License
15## along with this program; if not, write to the Free Software
16## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17##
18"""UI components for customers and related components.
19"""
20
21import sys
22import grok
23import pytz
24import os
25from urllib import urlencode
26from datetime import datetime
27from zope.event import notify
28from zope.i18n import translate
29from zope.catalog.interfaces import ICatalog
30from zope.component import queryUtility, getUtility, createObject
31from zope.schema.interfaces import ConstraintNotSatisfied, RequiredMissing
32from zope.formlib.textwidgets import BytesDisplayWidget
33from zope.security import checkPermission
34from hurry.workflow.interfaces import (
35    IWorkflowInfo, IWorkflowState, InvalidTransitionError)
36from waeup.ikoba.interfaces import MessageFactory as _
37from waeup.ikoba.interfaces import (
38    IContactForm, IObjectHistory, IIkobaObject, IIkobaUtils,
39    IPasswordValidator, IUserAccount,
40    VERIFIED, REJECTED, EXPIRED, REQUESTED, APPROVED)
41from waeup.ikoba.browser.layout import (
42    IkobaPage, IkobaEditFormPage, IkobaAddFormPage, IkobaDisplayFormPage,
43    IkobaForm, NullValidator, jsaction, action, UtilityView)
44from waeup.ikoba.widgets.datewidget import (
45    FriendlyDateWidget, FriendlyDateDisplayWidget,
46    FriendlyDatetimeDisplayWidget)
47from waeup.ikoba.browser.pages import ContactAdminForm
48from waeup.ikoba.browser.breadcrumbs import Breadcrumb
49from waeup.ikoba.browser.interfaces import ICaptchaManager
50from waeup.ikoba.mandates.mandate import PasswordMandate
51from waeup.ikoba.widgets.hrefwidget import HREFDisplayWidget
52from waeup.ikoba.utils.helpers import get_current_principal, to_timezone, now
53from waeup.ikoba.customers.interfaces import (
54    ICustomer, ICustomersContainer, ICustomerRequestPW, ICustomersUtils,
55    ICustomerDocument, ICustomerDocumentsContainer, ICustomerCreate,
56    ICustomerPDFDocument, IContractsContainer, IContract,
57    IContractSelectProduct, ISampleContract,
58    )
59from waeup.ikoba.customers.catalog import search
60
61grok.context(IIkobaObject)
62
63WARNING_CUST = _('You can not edit some data after final submission.'
64            ' You really want to submit?')
65
66WARNING_DOC = _('You can not edit your document after final submission.'
67            ' You really want to submit?')
68
69WARNING_CON = _('You can not edit your contract after final submission.'
70            ' You really want to submit?')
71
72
73# Save function used for save methods in pages
74def msave(view, **data):
75    changed_fields = view.applyData(view.context, **data)
76    # Turn list of lists into single list
77    if changed_fields:
78        changed_fields = reduce(lambda x,y: x+y, changed_fields.values())
79    if 'product_object' in changed_fields and data['product_object'] is not None:
80        view.context.last_product_id = data['product_object'].product_id
81        notify(grok.ObjectModifiedEvent(view.context))
82    fields_string = ' + '.join(changed_fields)
83    view.flash(_('Form has been saved.'))
84    if fields_string:
85        view.context.writeLogMessage(
86            view, '%s - saved: %s' % (view.context.__name__, fields_string))
87    return
88
89
90def emit_lock_message(view):
91    """Flash a lock message.
92    """
93    view.flash(_('The requested form is locked (read-only).'), type="warning")
94    view.redirect(view.url(view.context))
95    return
96
97def isCustomer(principal):
98    return getattr(principal, 'user_type', None) == 'customer'
99
100
101class CustomersBreadcrumb(Breadcrumb):
102    """A breadcrumb for the customers container.
103    """
104    grok.context(ICustomersContainer)
105    title = _('Customers')
106
107    @property
108    def target(self):
109        user = get_current_principal()
110        if getattr(user, 'user_type', None) == 'customer':
111            return None
112        return self.viewname
113
114
115class CustomerBreadcrumb(Breadcrumb):
116    """A breadcrumb for the customer container.
117    """
118    grok.context(ICustomer)
119
120    def title(self):
121        return self.context.display_fullname
122
123
124class CustomersContainerPage(IkobaPage):
125    """The standard view for customer containers.
126    """
127    grok.context(ICustomersContainer)
128    grok.name('index')
129    grok.require('waeup.viewCustomersContainer')
130    grok.template('containerpage')
131    label = _('Find customers')
132    search_button = _('Find customer(s)')
133    pnav = 4
134
135    def update(self, *args, **kw):
136        form = self.request.form
137        self.hitlist = []
138        if form.get('searchtype', None) == 'suspended':
139            self.searchtype = form['searchtype']
140            self.searchterm = None
141        elif 'searchterm' in form and form['searchterm']:
142            self.searchterm = form['searchterm']
143            self.searchtype = form['searchtype']
144        elif 'old_searchterm' in form:
145            self.searchterm = form['old_searchterm']
146            self.searchtype = form['old_searchtype']
147        else:
148            if 'search' in form:
149                self.flash(_('Empty search string'), type="warning")
150            return
151        if self.searchtype == 'current_session':
152            try:
153                self.searchterm = int(self.searchterm)
154            except ValueError:
155                self.flash(_('Only year dates allowed (e.g. 2011).'),
156                           type="danger")
157                return
158        self.hitlist = search(query=self.searchterm,
159            searchtype=self.searchtype, view=self)
160        if not self.hitlist:
161            self.flash(_('No customer found.'), type="warning")
162        return
163
164
165class CustomersContainerManagePage(IkobaPage):
166    """The manage page for customer containers.
167    """
168    grok.context(ICustomersContainer)
169    grok.name('manage')
170    grok.require('waeup.manageCustomer')
171    grok.template('containermanagepage')
172    pnav = 4
173    label = _('Manage customer section')
174    search_button = _('Find customer(s)')
175    remove_button = _('Remove selected')
176
177    def update(self, *args, **kw):
178        form = self.request.form
179        self.hitlist = []
180        if form.get('searchtype', None) == 'suspended':
181            self.searchtype = form['searchtype']
182            self.searchterm = None
183        elif 'searchterm' in form and form['searchterm']:
184            self.searchterm = form['searchterm']
185            self.searchtype = form['searchtype']
186        elif 'old_searchterm' in form:
187            self.searchterm = form['old_searchterm']
188            self.searchtype = form['old_searchtype']
189        else:
190            if 'search' in form:
191                self.flash(_('Empty search string'), type="warning")
192            return
193        if self.searchtype == 'current_session':
194            try:
195                self.searchterm = int(self.searchterm)
196            except ValueError:
197                self.flash(_('Only year dates allowed (e.g. 2011).'),
198                           type="danger")
199                return
200        if not 'entries' in form:
201            self.hitlist = search(query=self.searchterm,
202                searchtype=self.searchtype, view=self)
203            if not self.hitlist:
204                self.flash(_('No customer found.'), type="warning")
205            if 'remove' in form:
206                self.flash(_('No item selected.'), type="warning")
207            return
208        entries = form['entries']
209        if isinstance(entries, basestring):
210            entries = [entries]
211        deleted = []
212        for entry in entries:
213            if 'remove' in form:
214                del self.context[entry]
215                deleted.append(entry)
216        self.hitlist = search(query=self.searchterm,
217            searchtype=self.searchtype, view=self)
218        if len(deleted):
219            self.flash(_('Successfully removed: ${a}',
220                mapping={'a': ','.join(deleted)}))
221        return
222
223
224class CustomerAddFormPage(IkobaAddFormPage):
225    """Add-form to add a customer.
226    """
227    grok.context(ICustomersContainer)
228    grok.require('waeup.manageCustomer')
229    grok.name('addcustomer')
230    form_fields = grok.AutoFields(ICustomer).select(
231        'firstname', 'middlename', 'lastname', 'reg_number')
232    label = _('Add customer')
233    pnav = 4
234
235    @action(_('Create customer record'), style='primary')
236    def addCustomer(self, **data):
237        customer = createObject(u'waeup.Customer')
238        self.applyData(customer, **data)
239        self.context.addCustomer(customer)
240        self.flash(_('Customer created.'))
241        self.redirect(self.url(self.context[customer.customer_id], 'index'))
242        return
243
244
245class LoginAsCustomerStep1(IkobaEditFormPage):
246    """ View to temporarily set a customer password.
247    """
248    grok.context(ICustomer)
249    grok.name('loginasstep1')
250    grok.require('waeup.loginAsCustomer')
251    grok.template('loginasstep1')
252    pnav = 4
253
254    def label(self):
255        return _(u'Set temporary password for ${a}',
256            mapping={'a': self.context.display_fullname})
257
258    @action('Set password now', style='primary')
259    def setPassword(self, *args, **data):
260        ikoba_utils = getUtility(IIkobaUtils)
261        password = ikoba_utils.genPassword()
262        self.context.setTempPassword(self.request.principal.id, password)
263        self.context.writeLogMessage(
264            self, 'temp_password generated: %s' % password)
265        args = {'password': password}
266        self.redirect(self.url(self.context) +
267            '/loginasstep2?%s' % urlencode(args))
268        return
269
270
271class LoginAsCustomerStep2(IkobaPage):
272    """ View to temporarily login as customer with a temporary password.
273    """
274    grok.context(ICustomer)
275    grok.name('loginasstep2')
276    grok.require('waeup.Public')
277    grok.template('loginasstep2')
278    login_button = _('Login now')
279    pnav = 4
280
281    def label(self):
282        return _(u'Login as ${a}',
283            mapping={'a': self.context.customer_id})
284
285    def update(self, SUBMIT=None, password=None):
286        self.password = password
287        if SUBMIT is not None:
288            self.flash(_('You successfully logged in as customer.'))
289            self.redirect(self.url(self.context))
290        return
291
292
293class CustomerBaseDisplayFormPage(IkobaDisplayFormPage):
294    """ Page to display customer base data
295    """
296    grok.context(ICustomer)
297    grok.name('index')
298    grok.require('waeup.viewCustomer')
299    grok.template('basepage')
300    pnav = 4
301
302    @property
303    def form_fields(self):
304        return grok.AutoFields(
305            self.context.form_fields_interface).omit(
306            'password', 'suspended', 'suspended_comment')
307
308    @property
309    def label(self):
310        if self.context.suspended:
311            return _('${a}: Base Data (account deactivated)',
312                mapping={'a': self.context.display_fullname})
313        return  _('${a}: Base Data',
314            mapping={'a': self.context.display_fullname})
315
316    @property
317    def hasPassword(self):
318        if self.context.password:
319            return _('set')
320        return _('unset')
321
322    @property
323    def is_requestable(self):
324        if self.context.state in (REQUESTED, APPROVED):
325            return False
326        return True
327
328
329class ContactCustomerForm(ContactAdminForm):
330    grok.context(ICustomer)
331    grok.name('contactcustomer')
332    grok.require('waeup.viewCustomer')
333    pnav = 4
334    form_fields = grok.AutoFields(IContactForm).select('subject', 'body')
335
336
337    def update(self, subject=u'', body=u''):
338        super(ContactCustomerForm, self).update()
339        self.form_fields.get('subject').field.default = subject
340        self.form_fields.get('body').field.default = body
341        return
342
343    def label(self):
344        return _(u'Send message to ${a}',
345            mapping={'a': self.context.display_fullname})
346
347    @action('Send message now', style='primary')
348    def send(self, *args, **data):
349        try:
350            email = self.request.principal.email
351        except AttributeError:
352            email = self.config.email_admin
353        usertype = getattr(self.request.principal,
354                           'user_type', 'system').title()
355        ikoba_utils = getUtility(IIkobaUtils)
356        success = ikoba_utils.sendContactForm(
357                self.request.principal.title, email,
358                self.context.display_fullname, self.context.email,
359                self.request.principal.id,usertype,
360                self.config.name,
361                data['body'], data['subject'])
362        if success:
363            self.flash(_('Your message has been sent.'))
364        else:
365            self.flash(_('An smtp server error occurred.'), type="danger")
366        return
367
368
369class CustomerBaseManageFormPage(IkobaEditFormPage):
370    """ View to manage customer base data
371    """
372    grok.context(ICustomer)
373    grok.name('manage_base')
374    grok.require('waeup.manageCustomer')
375    grok.template('basemanagepage')
376    label = _('Manage base data')
377    pnav = 4
378
379    @property
380    def form_fields(self):
381        return grok.AutoFields(
382            self.context.form_fields_interface).omit(
383            'customer_id', 'adm_code', 'suspended')
384
385    def update(self):
386        super(CustomerBaseManageFormPage, self).update()
387        self.wf_info = IWorkflowInfo(self.context)
388        return
389
390    @action(_('Save'), style='primary')
391    def save(self, **data):
392        form = self.request.form
393        password = form.get('password', None)
394        password_ctl = form.get('control_password', None)
395        if password:
396            validator = getUtility(IPasswordValidator)
397            errors = validator.validate_password(password, password_ctl)
398            if errors:
399                self.flash(' '.join(errors), type="danger")
400                return
401        changed_fields = self.applyData(self.context, **data)
402        # Turn list of lists into single list
403        if changed_fields:
404            changed_fields = reduce(lambda x,y: x+y, changed_fields.values())
405        else:
406            changed_fields = []
407        if password:
408            # Now we know that the form has no errors and can set password
409            IUserAccount(self.context).setPassword(password)
410            changed_fields.append('password')
411        fields_string = ' + '.join(changed_fields)
412        self.flash(_('Form has been saved.'))
413        if fields_string:
414            self.context.writeLogMessage(self, 'saved: % s' % fields_string)
415        return
416
417
418class CustomerTriggerTransitionFormPage(IkobaEditFormPage):
419    """ View to trigger customer workflow transitions
420    """
421    grok.context(ICustomer)
422    grok.name('trigtrans')
423    grok.require('waeup.triggerTransition')
424    grok.template('trigtrans')
425    label = _('Trigger registration transition')
426    pnav = 4
427
428    def getTransitions(self):
429        """Return a list of dicts of allowed transition ids and titles.
430
431        Each list entry provides keys ``name`` and ``title`` for
432        internal name and (human readable) title of a single
433        transition.
434        """
435        wf_info = IWorkflowInfo(self.context)
436        allowed_transitions = [t for t in wf_info.getManualTransitions()]
437        return [dict(name='', title=_('No transition'))] +[
438            dict(name=x, title=y) for x, y in allowed_transitions]
439
440    @action(_('Apply'), style='primary')
441    def apply(self, **data):
442        form = self.request.form
443        if 'transition' in form and form['transition']:
444            transition_id = form['transition']
445            wf_info = IWorkflowInfo(self.context)
446            wf_info.fireTransition(transition_id)
447            self.flash(_("Transition '%s' executed." % transition_id))
448            self.redirect(self.url(self.context))
449        return
450
451
452class CustomerActivatePage(UtilityView, grok.View):
453    """ Activate customer account
454    """
455    grok.context(ICustomer)
456    grok.name('activate')
457    grok.require('waeup.manageCustomer')
458
459    def update(self):
460        self.context.suspended = False
461        self.context.writeLogMessage(self, 'account activated')
462        history = IObjectHistory(self.context)
463        history.addMessage('Customer account activated')
464        self.flash(_('Customer account has been activated.'))
465        self.redirect(self.url(self.context))
466        return
467
468    def render(self):
469        return
470
471
472class CustomerDeactivatePage(UtilityView, grok.View):
473    """ Deactivate customer account
474    """
475    grok.context(ICustomer)
476    grok.name('deactivate')
477    grok.require('waeup.manageCustomer')
478
479    def update(self):
480        self.context.suspended = True
481        self.context.writeLogMessage(self, 'account deactivated')
482        history = IObjectHistory(self.context)
483        history.addMessage('Customer account deactivated')
484        self.flash(_('Customer account has been deactivated.'))
485        self.redirect(self.url(self.context))
486        return
487
488    def render(self):
489        return
490
491
492class CustomerHistoryPage(IkobaPage):
493    """ Page to display customer history
494    """
495    grok.context(ICustomer)
496    grok.name('history')
497    grok.require('waeup.viewCustomer')
498    grok.template('customerhistory')
499    pnav = 4
500
501    @property
502    def label(self):
503        return _('${a}: History', mapping={'a':self.context.display_fullname})
504
505
506class CustomerRequestPasswordPage(IkobaAddFormPage):
507    """Captcha'd password request page for customers.
508    """
509    grok.name('requestpw')
510    grok.require('waeup.Anonymous')
511    grok.template('requestpw')
512    form_fields = grok.AutoFields(ICustomerRequestPW)
513    label = _('Request password for first-time login')
514
515    def update(self):
516        # Handle captcha
517        self.captcha = getUtility(ICaptchaManager).getCaptcha()
518        self.captcha_result = self.captcha.verify(self.request)
519        self.captcha_code = self.captcha.display(self.captcha_result.error_code)
520        return
521
522    def _redirect(self, email, password, customer_id):
523        # Forward only email address to landing page in base package.
524        self.redirect(self.url(self.context, 'requestpw_complete',
525            data=dict(email=email)))
526        return
527
528    def _pw_used(self):
529        # XXX: False if password has not been used. We need an extra
530        #      attribute which remembers if customer logged in.
531        return True
532
533    @action(_('Send login credentials to email address'), style='primary')
534    def get_credentials(self, **data):
535        if not self.captcha_result.is_valid:
536            # Captcha will display error messages automatically.
537            # No need to flash something.
538            return
539        number = data.get('number','')
540        firstname = data.get('firstname','')
541        cat = getUtility(ICatalog, name='customers_catalog')
542        results = list(
543            cat.searchResults(reg_number=(number, number)))
544        if results:
545            customer = results[0]
546            if getattr(customer,'firstname',None) is None:
547                self.flash(_('An error occurred.'), type="danger")
548                return
549            elif customer.firstname.lower() != firstname.lower():
550                # Don't tell the truth here. Anonymous must not
551                # know that a record was found and only the firstname
552                # verification failed.
553                self.flash(_('No customer found.'), type="warning")
554                return
555            elif customer.password is not None and self._pw_used:
556                self.flash(_('Your password has already been set and used. '
557                             'Please proceed to the login page.'),
558                           type="warning")
559                return
560            # Store email address but nothing else.
561            customer.email = data['email']
562            notify(grok.ObjectModifiedEvent(customer))
563        else:
564            # No record found, this is the truth.
565            self.flash(_('No customer found.'), type="warning")
566            return
567
568        ikoba_utils = getUtility(IIkobaUtils)
569        password = ikoba_utils.genPassword()
570        mandate = PasswordMandate()
571        mandate.params['password'] = password
572        mandate.params['user'] = customer
573        site = grok.getSite()
574        site['mandates'].addMandate(mandate)
575        # Send email with credentials
576        args = {'mandate_id':mandate.mandate_id}
577        mandate_url = self.url(site) + '/mandate?%s' % urlencode(args)
578        url_info = u'Confirmation link: %s' % mandate_url
579        msg = _('You have successfully requested a password for the')
580        if ikoba_utils.sendCredentials(IUserAccount(customer),
581            password, url_info, msg):
582            email_sent = customer.email
583        else:
584            email_sent = None
585        self._redirect(email=email_sent, password=password,
586            customer_id=customer.customer_id)
587        ob_class = self.__implemented__.__name__.replace('waeup.ikoba.','')
588        self.context.logger.info(
589            '%s - %s (%s) - %s' % (ob_class, number, customer.customer_id, email_sent))
590        return
591
592
593class CustomerCreateAccountPage(IkobaAddFormPage):
594    """Captcha'd account creation page for customers.
595    """
596    grok.name('createaccount')
597    grok.require('waeup.Anonymous')
598    grok.template('createaccount')
599    form_fields = grok.AutoFields(ICustomerCreate)
600    label = _('Create customer account')
601
602    def update(self):
603        # Handle captcha
604        self.captcha = getUtility(ICaptchaManager).getCaptcha()
605        self.captcha_result = self.captcha.verify(self.request)
606        self.captcha_code = self.captcha.display(self.captcha_result.error_code)
607        return
608
609    def _redirect(self, email, password, customer_id):
610        # Forward only email address to landing page in base package.
611        self.redirect(self.url(self.context, 'requestpw_complete',
612            data=dict(email=email)))
613        return
614
615    @action(_('Send login credentials to email address'), style='primary')
616    def create_account(self, **data):
617        if not self.captcha_result.is_valid:
618            # Captcha will display error messages automatically.
619            # No need to flash something.
620            return
621        customer = createObject(u'waeup.Customer')
622        customer.firstname = data.get('firstname','')
623        customer.middlename = data.get('middlename','')
624        customer.lastname = data.get('lastname','')
625        customer.email = data.get('email','')
626        self.context['customers'].addCustomer(customer)
627        ikoba_utils = getUtility(IIkobaUtils)
628        password = ikoba_utils.genPassword()
629        mandate = PasswordMandate()
630        mandate.params['password'] = password
631        mandate.params['user'] = customer
632        site = grok.getSite()
633        site['mandates'].addMandate(mandate)
634        # Send email with credentials
635        args = {'mandate_id':mandate.mandate_id}
636        mandate_url = self.url(site) + '/mandate?%s' % urlencode(args)
637        url_info = u'Confirmation link: %s' % mandate_url
638        msg = _('You have successfully created a customer account for the')
639        if ikoba_utils.sendCredentials(IUserAccount(customer),
640            password, url_info, msg):
641            email_sent = customer.email
642        else:
643            email_sent = None
644        self._redirect(email=email_sent, password=password,
645            customer_id=customer.customer_id)
646        ob_class = self.__implemented__.__name__.replace('waeup.ikoba.','')
647        self.context.logger.info(
648            '%s - %s - %s' % (ob_class, customer.customer_id, email_sent))
649        return
650
651
652class CustomerRequestPasswordEmailSent(IkobaPage):
653    """Landing page after successful password request.
654
655    """
656    grok.name('requestpw_complete')
657    grok.require('waeup.Public')
658    grok.template('requestpwmailsent')
659    label = _('Your request was successful.')
660
661    def update(self, email=None, customer_id=None, password=None):
662        self.email = email
663        self.password = password
664        self.customer_id = customer_id
665        return
666
667
668class CustomerFilesUploadPage(IkobaPage):
669    """ View to upload files by customer
670
671    We use this page only to upload a passport picture (portrait).
672    """
673    grok.context(ICustomer)
674    grok.name('change_portrait')
675    grok.require('waeup.handleCustomer')
676    grok.template('filesuploadpage')
677    label = _('Change portrait')
678    pnav = 4
679
680    def update(self, CANCEL=None):
681        CUSTMANAGE_STATES = getUtility(
682            ICustomersUtils).CUSTMANAGE_CUSTOMER_STATES
683        if self.context.customer.state not in CUSTMANAGE_STATES:
684            emit_lock_message(self)
685            return
686        if CANCEL is not None:
687            self.redirect(self.url(self.context))
688            return
689        super(CustomerFilesUploadPage, self).update()
690        return
691
692# Pages for customers
693
694
695class CustomerBaseEditFormPage(IkobaEditFormPage):
696    """ View to edit customer base data
697    """
698    grok.context(ICustomer)
699    grok.name('edit_base')
700    grok.require('waeup.handleCustomer')
701    pnav = 4
702
703    @property
704    def label(self):
705        if self.is_requestable():
706            return _('Edit base data and request registration')
707        return _('Edit base data')
708
709    @property
710    def form_fields(self):
711        if self.context.state in (REQUESTED, APPROVED):
712            return grok.AutoFields(ICustomer).select('email', 'phone')
713        return grok.AutoFields(ICustomer).omit(
714            'suspended', 'suspended_comment', 'reg_number', 'customer_id')
715
716    @action(_('Save'), style='primary')
717    def save(self, **data):
718        msave(self, **data)
719        return
720
721    def is_requestable(self, action=None):
722        if self.context.state in (REQUESTED, APPROVED):
723            return False
724        return True
725
726    @action(_('Request registration now'),
727            warning=WARNING_CUST, condition=is_requestable)
728    def finalsubmit(self, **data):
729        msave(self, **data)
730        IWorkflowInfo(self.context).fireTransition('request')
731        self.flash(_('Registration form has been submitted.'))
732        self.redirect(self.url(self.context))
733        return
734
735    @action(_('Cancel'), validator=NullValidator)
736    def cancel(self, **data):
737        self.redirect(self.url(self.context))
738
739
740class CustomerChangePasswordPage(IkobaEditFormPage):
741    """ View to edit customer passords
742    """
743    grok.context(ICustomer)
744    grok.name('changepassword')
745    grok.require('waeup.handleCustomer')
746    grok.template('changepassword')
747    label = _('Change password')
748    pnav = 4
749
750    @action(_('Save'), style='primary')
751    def save(self, **data):
752        form = self.request.form
753        password = form.get('change_password', None)
754        password_ctl = form.get('change_password_repeat', None)
755        if password:
756            validator = getUtility(IPasswordValidator)
757            errors = validator.validate_password(password, password_ctl)
758            if not errors:
759                IUserAccount(self.context).setPassword(password)
760                self.context.writeLogMessage(self, 'saved: password')
761                self.flash(_('Password changed.'))
762            else:
763                self.flash(' '.join(errors), type="warning")
764        return
765
766    @action(_('Cancel'), validator=NullValidator)
767    def cancel(self, **data):
768        self.redirect(self.url(self.context))
769
770
771class CustomerBasePDFFormPage(IkobaDisplayFormPage):
772    """ Page to display customer base data in pdf files.
773    """
774
775    def __init__(self, context, request, omit_fields=()):
776        self.omit_fields = omit_fields
777        super(CustomerBasePDFFormPage, self).__init__(context, request)
778
779    @property
780    def form_fields(self):
781        form_fields = grok.AutoFields(ICustomer)
782        for field in self.omit_fields:
783            form_fields = form_fields.omit(field)
784        return form_fields
785
786# Pages for customer documents
787
788class DocumentsBreadcrumb(Breadcrumb):
789    """A breadcrumb for the documents container.
790    """
791    grok.context(ICustomerDocumentsContainer)
792    title = _('Documents')
793
794
795class DocumentBreadcrumb(Breadcrumb):
796    """A breadcrumb for the customer container.
797    """
798    grok.context(ICustomerDocument)
799
800    @property
801    def title(self):
802        return "%s..." % self.context.document_id[:9]
803
804
805class DocumentsManageFormPage(IkobaEditFormPage):
806    """ Page to manage the customer documents
807
808    This manage form page is for both customers and customers officers.
809    """
810    grok.context(ICustomerDocumentsContainer)
811    grok.name('index')
812    grok.require('waeup.viewCustomer')
813    form_fields = grok.AutoFields(ICustomerDocumentsContainer)
814    grok.template('documentsmanagepage')
815    pnav = 4
816
817    @property
818    def manage_documents_allowed(self):
819        return checkPermission('waeup.editCustomerDocuments', self.context)
820
821    def unremovable(self, document):
822        usertype = getattr(self.request.principal, 'user_type', None)
823        if not usertype:
824            return False
825        if not self.manage_documents_allowed:
826            return True
827        return (self.request.principal.user_type == 'customer' and \
828            document.state in (VERIFIED, REJECTED, EXPIRED))
829
830    @property
831    def label(self):
832        return _('${a}: Documents',
833            mapping = {'a':self.context.__parent__.display_fullname})
834
835    @action(_('Add document'), validator=NullValidator, style='primary')
836    def addDocument(self, **data):
837        self.redirect(self.url(self.context, 'adddoc'))
838        return
839
840    @jsaction(_('Remove selected documents'))
841    def delDocument(self, **data):
842        form = self.request.form
843        if 'val_id' in form:
844            child_id = form['val_id']
845        else:
846            self.flash(_('No document selected.'), type="warning")
847            self.redirect(self.url(self.context))
848            return
849        if not isinstance(child_id, list):
850            child_id = [child_id]
851        deleted = []
852        for id in child_id:
853            # Customers are not allowed to remove used documents
854            document = self.context.get(id, None)
855            if document is not None and not self.unremovable(document):
856                del self.context[id]
857                deleted.append(id)
858        if len(deleted):
859            self.flash(_('Successfully removed: ${a}',
860                mapping = {'a': ', '.join(deleted)}))
861            self.context.writeLogMessage(
862                self,'removed: %s' % ', '.join(deleted))
863        self.redirect(self.url(self.context))
864        return
865
866
867class DocumentAddFormPage(IkobaAddFormPage):
868    """ Page to add a document
869
870    This add form page is for both customers and customers officers.
871    """
872    grok.context(ICustomerDocumentsContainer)
873    grok.name('adddoc')
874    grok.template('documentaddpage')
875    grok.require('waeup.editCustomerDocuments')
876    label = _('Add document')
877    pnav = 4
878
879    form_fields = grok.AutoFields(ICustomerDocument).omit('document_id')
880
881    @property
882    def selectable_doctypes(self):
883        doctypes = getUtility(ICustomersUtils).SELECTABLE_DOCTYPES_DICT
884        return sorted(doctypes.items())
885
886    @property
887    def edit_documents_allowed(self):
888        right_customer_state = self.context.customer.state in getUtility(
889            ICustomersUtils).DOCMANAGE_CUSTOMER_STATES
890        if isCustomer(self.request.principal) and not right_customer_state:
891            return False
892        return True
893
894    def update(self):
895        if not self.edit_documents_allowed:
896            emit_lock_message(self)
897            return
898        return super(DocumentAddFormPage, self).update()
899
900    @action(_('Add document'), style='primary')
901    def createDocument(self, **data):
902        form = self.request.form
903        customer = self.context.__parent__
904        doctype = form.get('doctype', None)
905        # Here we can create various instances of CustomerDocument derived
906        # classes depending on the doctype parameter given in form.
907        document = createObject('waeup.%s' % doctype)
908        self.applyData(document, **data)
909        self.context.addDocument(document)
910        doctype = getUtility(ICustomersUtils).SELECTABLE_DOCTYPES_DICT[doctype]
911        self.flash(_('${a} added.', mapping = {'a': doctype}))
912        self.context.writeLogMessage(
913            self,'added: %s %s' % (doctype, document.document_id))
914        isCustomer = getattr(
915            self.request.principal, 'user_type', None) == 'customer'
916        if isCustomer:
917            self.redirect(self.url(document, 'edit') + '#tab2')
918        else:
919            self.redirect(self.url(document, 'manage') + '#tab2')
920        return
921
922    @action(_('Cancel'), validator=NullValidator)
923    def cancel(self, **data):
924        self.redirect(self.url(self.context))
925
926
927class DocumentDisplayFormPage(IkobaDisplayFormPage):
928    """ Page to view a document
929    """
930    grok.context(ICustomerDocument)
931    grok.name('index')
932    grok.require('waeup.viewCustomer')
933    grok.template('documentpage')
934    pnav = 4
935    label = None  # We render the context title in the documentpage template
936
937    @property
938    def form_fields(self):
939        return grok.AutoFields(self.context.form_fields_interface)
940
941class DocumentManageFormPage(IkobaEditFormPage):
942    """ Page to edit a document
943    """
944    grok.context(ICustomerDocument)
945    grok.name('manage')
946    grok.require('waeup.manageCustomer')
947    grok.template('documenteditpage')
948    pnav = 4
949    deletion_warning = _('Are you sure?')
950
951    @property
952    def form_fields(self):
953        return grok.AutoFields(
954            self.context.form_fields_interface).omit('document_id')
955
956    def update(self):
957        if not self.context.is_editable_by_manager:
958            emit_lock_message(self)
959            return
960        return super(DocumentManageFormPage, self).update()
961
962    @property
963    def label(self):
964        return self.context.title
965
966    @action(_('Save'), style='primary')
967    def save(self, **data):
968        msave(self, **data)
969        return
970
971
972class DocumentEditFormPage(DocumentManageFormPage):
973    """ Page to edit a document
974    """
975    grok.name('edit')
976    grok.require('waeup.handleCustomer')
977
978    def update(self):
979        if not self.context.is_editable_by_customer:
980            emit_lock_message(self)
981            return
982        return super(DocumentEditFormPage, self).update()
983
984    @action(_('Save'), style='primary')
985    def save(self, **data):
986        msave(self, **data)
987        return
988
989    @action(_('Final Submit'), warning=WARNING_DOC)
990    def finalsubmit(self, **data):
991        msave(self, **data)
992        IWorkflowInfo(self.context).fireTransition('submit')
993        self.flash(_('Form has been submitted.'))
994        self.redirect(self.url(self.context))
995        return
996
997
998class DocumentTriggerTransitionFormPage(IkobaEditFormPage):
999    """ View to trigger customer document transitions
1000    """
1001    grok.context(ICustomerDocument)
1002    grok.name('trigtrans')
1003    grok.require('waeup.triggerTransition')
1004    grok.template('trigtrans')
1005    label = _('Trigger document transition')
1006    pnav = 4
1007
1008    def update(self):
1009        return super(IkobaEditFormPage, self).update()
1010
1011    def getTransitions(self):
1012        """Return a list of dicts of allowed transition ids and titles.
1013
1014        Each list entry provides keys ``name`` and ``title`` for
1015        internal name and (human readable) title of a single
1016        transition.
1017        """
1018        wf_info = IWorkflowInfo(self.context)
1019        allowed_transitions = [t for t in wf_info.getManualTransitions()]
1020        return [dict(name='', title=_('No transition'))] +[
1021            dict(name=x, title=y) for x, y in allowed_transitions]
1022
1023    @action(_('Apply'), style='primary')
1024    def apply(self, **data):
1025        form = self.request.form
1026        if 'transition' in form and form['transition']:
1027            transition_id = form['transition']
1028            wf_info = IWorkflowInfo(self.context)
1029            try:
1030                wf_info.fireTransition(transition_id)
1031                self.flash(_("Transition '%s' executed." % transition_id))
1032            except InvalidTransitionError, error:
1033                self.flash(error, type="warning")
1034            self.redirect(self.url(self.context))
1035        return
1036
1037class PDFDocumentsOverviewPage(UtilityView, grok.View):
1038    """Deliver an overview slip.
1039    """
1040    grok.context(ICustomerDocumentsContainer)
1041    grok.name('documents_overview_slip.pdf')
1042    grok.require('waeup.viewCustomer')
1043    prefix = 'form'
1044
1045    omit_fields = ('suspended', 'sex',
1046                   'suspended_comment',)
1047
1048    form_fields = None
1049
1050    @property
1051    def label(self):
1052        portal_language = getUtility(IIkobaUtils).PORTAL_LANGUAGE
1053        return translate(_('Documents of'),
1054            'waeup.ikoba', target_language=portal_language) \
1055            + ' %s' % self.context.customer.display_fullname
1056
1057    @property
1058    def tabletitle(self):
1059        portal_language = getUtility(IIkobaUtils).PORTAL_LANGUAGE
1060        tabletitle = []
1061        tabletitle.append(translate(_('Customer Documents'), 'waeup.ikoba',
1062            target_language=portal_language))
1063        return tabletitle
1064
1065    def render(self):
1066        portal_language = getUtility(IIkobaUtils).PORTAL_LANGUAGE
1067        Id = translate(_('Id'), 'waeup.ikoba', target_language=portal_language)
1068        Title = translate(_('Title'), 'waeup.ikoba', target_language=portal_language)
1069        Type = translate(_('Type'), 'waeup.ikoba', target_language=portal_language)
1070        State = translate(_('State'), 'waeup.ikoba', target_language=portal_language)
1071        LT = translate(_('Last Transition'), 'waeup.ikoba', target_language=portal_language)
1072        tableheader = []
1073        tabledata = []
1074        contenttitle = []
1075        for i in range(1,3):
1076            tabledata.append(sorted(
1077                [value for value in self.context.values()]))
1078            tableheader.append([(Id, 'document_id', 2),
1079                             (Title, 'title', 6),
1080                             (Type, 'translated_class_name', 6),
1081                             (State, 'translated_state', 2),
1082                             (LT, 'formatted_transition_date', 3),
1083                             ])
1084        customerview = CustomerBasePDFFormPage(self.context.customer,
1085            self.request, self.omit_fields)
1086        customers_utils = getUtility(ICustomersUtils)
1087        return customers_utils.renderPDF(
1088            self, 'overview_slip.pdf',
1089            self.context.customer, customerview,
1090            tableheader=tableheader,
1091            tabledata=tabledata,
1092            omit_fields=self.omit_fields)
1093
1094
1095class PDFDocumentSlipPage(UtilityView, grok.View):
1096    """Deliver pdf file including metadata.
1097    """
1098    grok.context(ICustomerDocument)
1099    grok.name('document_slip.pdf')
1100    grok.require('waeup.viewCustomer')
1101    prefix = 'form'
1102
1103    omit_fields = ('suspended', 'sex',
1104                   'suspended_comment',)
1105
1106    form_fields =()
1107
1108    @property
1109    def label(self):
1110        portal_language = getUtility(IIkobaUtils).PORTAL_LANGUAGE
1111        return '%s of %s\nTitle: %s' % (
1112            self.context.translated_class_name,
1113            self.context.customer.display_fullname,
1114            self.context.title)
1115
1116    def render(self):
1117        portal_language = getUtility(IIkobaUtils).PORTAL_LANGUAGE
1118        customerview = CustomerBasePDFFormPage(self.context.customer,
1119            self.request, self.omit_fields)
1120        customers_utils = getUtility(ICustomersUtils)
1121        return customers_utils.renderPDF(
1122            self, 'document_slip.pdf',
1123            self.context.customer, customerview,
1124            omit_fields=self.omit_fields)
1125
1126
1127class PDFMergeDocumentSlipPage(PDFDocumentSlipPage):
1128    """Deliver pdf file including metadata.
1129    """
1130    grok.context(ICustomerPDFDocument)
1131
1132    def render(self):
1133        portal_language = getUtility(IIkobaUtils).PORTAL_LANGUAGE
1134        customerview = CustomerBasePDFFormPage(self.context.customer,
1135            self.request, self.omit_fields)
1136        customers_utils = getUtility(ICustomersUtils)
1137        if self.context.state == VERIFIED:
1138            watermark_path = os.path.join(
1139                os.path.dirname(__file__), 'static', 'verified.pdf')
1140        else:
1141            watermark_path = os.path.join(
1142                os.path.dirname(__file__), 'static', 'unverified.pdf')
1143        watermark = open(watermark_path, 'rb')
1144        return customers_utils.renderPDF(
1145            self, 'pdfdocument_slip.pdf',
1146            self.context.customer, customerview,
1147            omit_fields=self.omit_fields,
1148            mergefiles=self.context.connected_files,
1149            watermark=watermark)
1150
1151# Pages for customer contracts
1152
1153class ContractsBreadcrumb(Breadcrumb):
1154    """A breadcrumb for the contracts container.
1155    """
1156    grok.context(IContractsContainer)
1157    title = _('Contracts')
1158
1159
1160class ContractBreadcrumb(Breadcrumb):
1161    """A breadcrumb for the customer container.
1162    """
1163    grok.context(IContract)
1164
1165    @property
1166    def title(self):
1167        return "%s..." % self.context.contract_id[:9]
1168
1169
1170class ContractsFormPage(IkobaEditFormPage):
1171    """ Page to display, edit or manage customer contracts
1172
1173    This form page is for both customers and officers.
1174    """
1175    grok.context(IContractsContainer)
1176    grok.name('index')
1177    grok.require('waeup.viewCustomer')
1178    form_fields = grok.AutoFields(IContractsContainer)
1179    grok.template('contractsmanagepage')
1180    pnav = 4
1181
1182    @property
1183    def edit_contracts_allowed(self):
1184        right_customer_state = self.context.customer.state in getUtility(
1185            ICustomersUtils).CONMANAGE_CUSTOMER_STATES
1186        if isCustomer(self.request.principal) and not right_customer_state:
1187            return False
1188        return checkPermission('waeup.editContracts', self.context)
1189
1190    def remove_contract_allowed(self, contract):
1191        if isCustomer(self.request.principal):
1192            right_customer_state = self.context.customer.state in getUtility(
1193                ICustomersUtils).CONMANAGE_CUSTOMER_STATES
1194            if not right_customer_state:
1195                return False
1196            if contract.state in (APPROVED, REJECTED, EXPIRED):
1197                return False
1198        return checkPermission('waeup.editContracts', self.context)
1199
1200    @property
1201    def label(self):
1202        return _('${a}: Contracts',
1203            mapping = {'a':self.context.__parent__.display_fullname})
1204
1205    @action(_('Add contract'), validator=NullValidator, style='primary')
1206    def addContract(self, **data):
1207        self.redirect(self.url(self.context, 'addcontract'))
1208        return
1209
1210    @jsaction(_('Remove selected contracts'))
1211    def delContract(self, **data):
1212        form = self.request.form
1213        if 'val_id' in form:
1214            child_id = form['val_id']
1215        else:
1216            self.flash(_('No contract selected.'), type="warning")
1217            self.redirect(self.url(self.context))
1218            return
1219        if not isinstance(child_id, list):
1220            child_id = [child_id]
1221        deleted = []
1222        for id in child_id:
1223            # Customers are not allowed to remove used contracts
1224            contract = self.context.get(id, None)
1225            if contract is not None and self.remove_contract_allowed(contract):
1226                del self.context[id]
1227                deleted.append(id)
1228        if len(deleted):
1229            self.flash(_('Successfully removed: ${a}',
1230                mapping = {'a': ', '.join(deleted)}))
1231            self.context.writeLogMessage(
1232                self,'removed: %s' % ', '.join(deleted))
1233        self.redirect(self.url(self.context))
1234        return
1235
1236
1237class ContractAddFormPage(IkobaAddFormPage):
1238    """ Page to add an contract
1239
1240    This page is for both customers and officers.
1241    """
1242    grok.context(IContractsContainer)
1243    grok.name('addcontract')
1244    grok.template('contractaddpage')
1245    grok.require('waeup.editContracts')
1246    label = _('Add contract')
1247    pnav = 4
1248
1249    form_fields = grok.AutoFields(IContract).omit(
1250        'product_object', 'contract_id', 'product_options')
1251
1252    @property
1253    def edit_contracts_allowed(self):
1254        right_customer_state = self.context.customer.state in getUtility(
1255            ICustomersUtils).CONMANAGE_CUSTOMER_STATES
1256        if right_customer_state:
1257            return True
1258        return False
1259
1260    def update(self):
1261        if not self.edit_contracts_allowed:
1262            emit_lock_message(self)
1263            return
1264        return super(ContractAddFormPage, self).update()
1265
1266    @property
1267    def selectable_contypes(self):
1268        contypes = getUtility(ICustomersUtils).SELECTABLE_CONTYPES_DICT
1269        return sorted(contypes.items())
1270
1271    @action(_('Add contract'), style='primary')
1272    def createContract(self, **data):
1273        form = self.request.form
1274        customer = self.context.__parent__
1275        contype = form.get('contype', None)
1276        # Here we can create various instances of Contract derived
1277        # classes depending on the contype parameter given in form.
1278        contract = createObject('waeup.%s' % contype)
1279        self.applyData(contract, **data)
1280        self.context.addContract(contract)
1281        contype = getUtility(ICustomersUtils).SELECTABLE_CONTYPES_DICT[contype]
1282        self.flash(_('${a} added.', mapping = {'a': contype}))
1283        self.context.writeLogMessage(
1284            self,'added: %s %s' % (contype, contract.contract_id))
1285        self.redirect(self.url(contract, 'selectproduct'))
1286        return
1287
1288    @action(_('Cancel'), validator=NullValidator)
1289    def cancel(self, **data):
1290        self.redirect(self.url(self.context))
1291
1292
1293class ContractSelectProductPage(IkobaAddFormPage):
1294    """ Page to select a contract product
1295
1296    This page is for both customers and officers.
1297    """
1298    grok.context(IContract)
1299    grok.name('selectproduct')
1300    grok.require('waeup.editContracts')
1301    label = _('Select product')
1302    pnav = 4
1303
1304    form_fields = grok.AutoFields(IContractSelectProduct)
1305
1306    def update(self):
1307        if self.context.product_object is not None:
1308            emit_lock_message(self)
1309            return
1310        return super(ContractSelectProductPage, self).update()
1311
1312    @action(_('Save and proceed'), style='primary')
1313    def save(self, **data):
1314        msave(self, **data)
1315        self.context.tc_dict = self.context.product_object.tc_dict
1316        isCustomer = getattr(
1317            self.request.principal, 'user_type', None) == 'customer'
1318        if isCustomer:
1319            self.redirect(self.url(self.context, 'edit'))
1320        else:
1321            self.redirect(self.url(self.context, 'manage'))
1322        return
1323
1324
1325class ContractDisplayFormPage(IkobaDisplayFormPage):
1326    """ Page to view a contract
1327    """
1328    grok.context(IContract)
1329    grok.name('index')
1330    grok.require('waeup.viewCustomer')
1331    grok.template('contractpage')
1332    pnav = 4
1333    label = None  # We render the context title in the contractpage template
1334
1335    @property
1336    def form_fields(self):
1337        form_fields = grok.AutoFields(self.context.form_fields_interface)
1338        for field in form_fields:
1339            if field.__name__.endswith('_object'):
1340                form_fields[field.__name__].custom_widget = HREFDisplayWidget
1341        return form_fields
1342
1343    @property
1344    def terms_and_conditions(self):
1345        lang = self.request.cookies.get('ikoba.language')
1346        html = self.context.tc_dict.get(lang,'')
1347        if html =='':
1348            portal_language = getUtility(IIkobaUtils).PORTAL_LANGUAGE
1349            html = self.context.tc_dict.get(portal_language,'')
1350        return html
1351
1352
1353class ContractManageFormPage(IkobaEditFormPage):
1354    """ Page to manage a contract
1355    """
1356    grok.context(IContract)
1357    grok.name('manage')
1358    grok.require('waeup.manageCustomer')
1359    grok.template('contracteditpage')
1360    pnav = 4
1361    deletion_warning = _('Are you sure?')
1362
1363    def update(self):
1364        if not self.context.is_editable:
1365            emit_lock_message(self)
1366            return
1367        return super(ContractManageFormPage, self).update()
1368
1369    @property
1370    def form_fields(self):
1371        return grok.AutoFields(self.context.form_fields_interface).omit(
1372            'contract_id', 'product_object')
1373
1374    @property
1375    def label(self):
1376        return self.context.title
1377
1378    @action(_('Save'), style='primary')
1379    def save(self, **data):
1380        msave(self, **data)
1381        return
1382
1383
1384class ContractEditFormPage(ContractManageFormPage):
1385    """ Page to edit a contract by customer only
1386    """
1387    grok.name('edit')
1388    grok.require('waeup.handleCustomer')
1389
1390    @property
1391    def form_fields(self):
1392        return grok.AutoFields(self.context.edit_form_fields_interface).omit(
1393            'contract_id', 'product_object')
1394
1395    @action(_('Save'), style='primary')
1396    def save(self, **data):
1397        msave(self, **data)
1398        return
1399
1400    @action(_('Apply now (final submit)'), warning=WARNING_CON)
1401    def finalsubmit(self, **data):
1402        msave(self, **data)
1403        IWorkflowInfo(self.context).fireTransition('submit')
1404        self.flash(_('Form has been submitted.'))
1405        self.redirect(self.url(self.context))
1406        return
1407
1408
1409class ContractTriggerTransitionFormPage(IkobaEditFormPage):
1410    """ View to trigger customer contract transitions
1411    """
1412    grok.context(IContract)
1413    grok.name('trigtrans')
1414    grok.require('waeup.triggerTransition')
1415    grok.template('trigtrans')
1416    label = _('Trigger contract transition')
1417    pnav = 4
1418
1419    def update(self):
1420        return super(IkobaEditFormPage, self).update()
1421
1422    def getTransitions(self):
1423        """Return a list of dicts of allowed transition ids and titles.
1424
1425        Each list entry provides keys ``name`` and ``title`` for
1426        internal name and (human readable) title of a single
1427        transition.
1428        """
1429        wf_info = IWorkflowInfo(self.context)
1430        allowed_transitions = [t for t in wf_info.getManualTransitions()]
1431        return [dict(name='', title=_('No transition'))] +[
1432            dict(name=x, title=y) for x, y in allowed_transitions]
1433
1434    @action(_('Apply'), style='primary')
1435    def apply(self, **data):
1436        form = self.request.form
1437        if 'transition' in form and form['transition']:
1438            transition_id = form['transition']
1439            wf_info = IWorkflowInfo(self.context)
1440            try:
1441                wf_info.fireTransition(transition_id)
1442                self.flash(_("Transition '%s' executed." % transition_id))
1443            except InvalidTransitionError, error:
1444                self.flash(error, type="warning")
1445            self.redirect(self.url(self.context))
1446        return
1447
1448class PDFContractsOverviewPage(UtilityView, grok.View):
1449    """Deliver an overview slip.
1450    """
1451    grok.context(IContractsContainer)
1452    grok.name('contracts_overview_slip.pdf')
1453    grok.require('waeup.viewCustomer')
1454    prefix = 'form'
1455
1456    omit_fields = ('suspended', 'sex',
1457                   'suspended_comment',)
1458
1459    form_fields = None
1460
1461    @property
1462    def label(self):
1463        portal_language = getUtility(IIkobaUtils).PORTAL_LANGUAGE
1464        return translate(_('Contracts of'),
1465            'waeup.ikoba', target_language=portal_language) \
1466            + ' %s' % self.context.customer.display_fullname
1467
1468    @property
1469    def tabletitle(self):
1470        portal_language = getUtility(IIkobaUtils).PORTAL_LANGUAGE
1471        tabletitle = []
1472        tabletitle.append(translate(_('Customer Contracts'), 'waeup.ikoba',
1473            target_language=portal_language))
1474        return tabletitle
1475
1476    def render(self):
1477        portal_language = getUtility(IIkobaUtils).PORTAL_LANGUAGE
1478        #Id = translate(_('Id'), 'waeup.ikoba', target_language=portal_language)
1479        Title = translate(_('Title'), 'waeup.ikoba', target_language=portal_language)
1480        Type = translate(_('Type'), 'waeup.ikoba', target_language=portal_language)
1481        State = translate(_('State'), 'waeup.ikoba', target_language=portal_language)
1482        LT = translate(_('Last Transition'), 'waeup.ikoba', target_language=portal_language)
1483        tableheader = []
1484        tabledata = []
1485        contenttitle = []
1486        for i in range(1,3):
1487            tabledata.append(sorted(
1488                [value for value in self.context.values()]))
1489            tableheader.append([
1490                             #(Id, 'contract_id', 2),
1491                             (Title, 'title', 6),
1492                             (Type, 'translated_class_name', 6),
1493                             (State, 'translated_state', 2),
1494                             (LT, 'formatted_transition_date', 3),
1495                             ])
1496        customerview = CustomerBasePDFFormPage(self.context.customer,
1497            self.request, self.omit_fields)
1498        customers_utils = getUtility(ICustomersUtils)
1499        return customers_utils.renderPDF(
1500            self, 'overview_slip.pdf',
1501            self.context.customer, customerview,
1502            tableheader=tableheader,
1503            tabledata=tabledata,
1504            omit_fields=self.omit_fields)
1505
1506
1507class PDFContractSlipPage(UtilityView, grok.View):
1508    """Deliver pdf file including metadata.
1509    """
1510    grok.context(IContract)
1511    grok.name('contract_slip.pdf')
1512    grok.require('waeup.viewCustomer')
1513    prefix = 'form'
1514
1515    omit_fields = ('suspended', 'sex',
1516                   'suspended_comment',)
1517
1518    @property
1519    def form_fields(self):
1520        return grok.AutoFields(self.context.form_fields_interface)
1521
1522    @property
1523    def terms_and_conditions(self):
1524        lang = self.request.cookies.get('ikoba.language')
1525        html = self.context.tc_dict.get(lang,'')
1526        if html =='':
1527            portal_language = getUtility(IIkobaUtils).PORTAL_LANGUAGE
1528            html = self.context.tc_dict.get(portal_language,'')
1529        return html
1530
1531    @property
1532    def label(self):
1533        portal_language = getUtility(IIkobaUtils).PORTAL_LANGUAGE
1534        return '%s of %s\nTitle: %s' % (
1535            self.context.translated_class_name,
1536            self.context.customer.display_fullname,
1537            self.context.title)
1538
1539    def render(self):
1540        portal_language = getUtility(IIkobaUtils).PORTAL_LANGUAGE
1541        customerview = CustomerBasePDFFormPage(self.context.customer,
1542            self.request, self.omit_fields)
1543        customers_utils = getUtility(ICustomersUtils)
1544        return customers_utils.renderPDF(
1545            self, 'contract_slip.pdf',
1546            self.context.customer, customerview,
1547            omit_fields=self.omit_fields)
Note: See TracBrowser for help on using the repository browser.