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

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

Add more browser components for document editing. Editing is allowed only under certain conditions.

  • work in progress -
  • Property svn:keywords set to Id
File size: 27.3 KB
RevLine 
[12015]1## $Id: browser.py 12018 2014-11-21 08:07:15Z henrik $
[11958]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
[11967]21import sys
[11958]22import grok
[11967]23import pytz
24from urllib import urlencode
25from datetime import datetime
26from zope.event import notify
27from zope.i18n import translate
28from zope.catalog.interfaces import ICatalog
29from zope.component import queryUtility, getUtility, createObject
30from zope.schema.interfaces import ConstraintNotSatisfied, RequiredMissing
31from zope.formlib.textwidgets import BytesDisplayWidget
32from zope.security import checkPermission
33from hurry.workflow.interfaces import IWorkflowInfo, IWorkflowState
[11958]34from waeup.ikoba.interfaces import MessageFactory as _
[11971]35from waeup.ikoba.interfaces import (
36    IContactForm, IObjectHistory, IIkobaObject, IIkobaUtils,
37    IPasswordValidator, IUserAccount)
[11958]38from waeup.ikoba.browser.layout import (
39    IkobaPage, IkobaEditFormPage, IkobaAddFormPage, IkobaDisplayFormPage,
[11967]40    IkobaForm, NullValidator, jsaction, action, UtilityView)
41from waeup.ikoba.browser.pages import ContactAdminForm
[11958]42from waeup.ikoba.browser.breadcrumbs import Breadcrumb
[11971]43from waeup.ikoba.browser.interfaces import ICaptchaManager
[11977]44from waeup.ikoba.mandates.mandate import PasswordMandate
[12018]45from waeup.ikoba.documents.workflow import VERIFIED, REJECTED, OUTDATED
[11958]46from waeup.ikoba.utils.helpers import get_current_principal, to_timezone, now
47from waeup.ikoba.customers.interfaces import (
[12015]48    ICustomer, ICustomersContainer, ICustomerRequestPW, ICustomersUtils,
49    ICustomerDocument, ICustomerDocumentsContainer
[11958]50    )
51from waeup.ikoba.customers.catalog import search
52
[11967]53grok.context(IIkobaObject)
54
[11985]55
[11986]56# Save function used for save methods in pages
57def msave(view, **data):
58    changed_fields = view.applyData(view.context, **data)
59    # Turn list of lists into single list
60    if changed_fields:
61        changed_fields = reduce(lambda x,y: x+y, changed_fields.values())
62    fields_string = ' + '.join(changed_fields)
63    view.flash(_('Form has been saved.'))
64    if fields_string:
65        view.context.writeLogMessage(view, 'saved: %s' % fields_string)
66    return
67
68
69def emit_lock_message(view):
70    """Flash a lock message.
71    """
72    view.flash(_('The requested form is locked (read-only).'), type="warning")
73    view.redirect(view.url(view.context))
74    return
75
76
[11958]77class CustomersBreadcrumb(Breadcrumb):
78    """A breadcrumb for the customers container.
79    """
80    grok.context(ICustomersContainer)
81    title = _('Customers')
82
83    @property
84    def target(self):
85        user = get_current_principal()
86        if getattr(user, 'user_type', None) == 'customer':
87            return None
88        return self.viewname
89
[11967]90
91class CustomerBreadcrumb(Breadcrumb):
92    """A breadcrumb for the customer container.
93    """
94    grok.context(ICustomer)
95
96    def title(self):
97        return self.context.display_fullname
98
[11985]99
[11958]100class CustomersContainerPage(IkobaPage):
101    """The standard view for customer containers.
102    """
103    grok.context(ICustomersContainer)
104    grok.name('index')
105    grok.require('waeup.viewCustomersContainer')
106    grok.template('containerpage')
107    label = _('Find customers')
108    search_button = _('Find customer(s)')
109    pnav = 4
110
111    def update(self, *args, **kw):
112        form = self.request.form
113        self.hitlist = []
114        if form.get('searchtype', None) == 'suspended':
115            self.searchtype = form['searchtype']
116            self.searchterm = None
117        elif 'searchterm' in form and form['searchterm']:
118            self.searchterm = form['searchterm']
119            self.searchtype = form['searchtype']
120        elif 'old_searchterm' in form:
121            self.searchterm = form['old_searchterm']
122            self.searchtype = form['old_searchtype']
123        else:
124            if 'search' in form:
125                self.flash(_('Empty search string'), type="warning")
126            return
127        if self.searchtype == 'current_session':
128            try:
129                self.searchterm = int(self.searchterm)
130            except ValueError:
131                self.flash(_('Only year dates allowed (e.g. 2011).'),
132                           type="danger")
133                return
134        self.hitlist = search(query=self.searchterm,
135            searchtype=self.searchtype, view=self)
136        if not self.hitlist:
137            self.flash(_('No customer found.'), type="warning")
138        return
139
[11985]140
[11958]141class CustomersContainerManagePage(IkobaPage):
142    """The manage page for customer containers.
143    """
144    grok.context(ICustomersContainer)
145    grok.name('manage')
146    grok.require('waeup.manageCustomer')
147    grok.template('containermanagepage')
148    pnav = 4
149    label = _('Manage customer section')
150    search_button = _('Find customer(s)')
151    remove_button = _('Remove selected')
152
153    def update(self, *args, **kw):
154        form = self.request.form
155        self.hitlist = []
156        if form.get('searchtype', None) == 'suspended':
157            self.searchtype = form['searchtype']
158            self.searchterm = None
159        elif 'searchterm' in form and form['searchterm']:
160            self.searchterm = form['searchterm']
161            self.searchtype = form['searchtype']
162        elif 'old_searchterm' in form:
163            self.searchterm = form['old_searchterm']
164            self.searchtype = form['old_searchtype']
165        else:
166            if 'search' in form:
167                self.flash(_('Empty search string'), type="warning")
168            return
169        if self.searchtype == 'current_session':
170            try:
171                self.searchterm = int(self.searchterm)
172            except ValueError:
173                self.flash(_('Only year dates allowed (e.g. 2011).'),
174                           type="danger")
175                return
176        if not 'entries' in form:
177            self.hitlist = search(query=self.searchterm,
178                searchtype=self.searchtype, view=self)
179            if not self.hitlist:
180                self.flash(_('No customer found.'), type="warning")
181            if 'remove' in form:
182                self.flash(_('No item selected.'), type="warning")
183            return
184        entries = form['entries']
185        if isinstance(entries, basestring):
186            entries = [entries]
187        deleted = []
188        for entry in entries:
189            if 'remove' in form:
190                del self.context[entry]
191                deleted.append(entry)
192        self.hitlist = search(query=self.searchterm,
193            searchtype=self.searchtype, view=self)
194        if len(deleted):
195            self.flash(_('Successfully removed: ${a}',
[11985]196                mapping={'a': ','.join(deleted)}))
[11967]197        return
198
[11985]199
[11967]200class CustomerAddFormPage(IkobaAddFormPage):
201    """Add-form to add a customer.
202    """
203    grok.context(ICustomersContainer)
204    grok.require('waeup.manageCustomer')
205    grok.name('addcustomer')
206    form_fields = grok.AutoFields(ICustomer).select(
207        'firstname', 'middlename', 'lastname', 'reg_number')
208    label = _('Add customer')
209    pnav = 4
210
211    @action(_('Create customer record'), style='primary')
212    def addCustomer(self, **data):
213        customer = createObject(u'waeup.Customer')
214        self.applyData(customer, **data)
215        self.context.addCustomer(customer)
216        self.flash(_('Customer record created.'))
217        self.redirect(self.url(self.context[customer.customer_id], 'index'))
218        return
219
[11985]220
[11967]221class LoginAsCustomerStep1(IkobaEditFormPage):
222    """ View to temporarily set a customer password.
223    """
224    grok.context(ICustomer)
225    grok.name('loginasstep1')
226    grok.require('waeup.loginAsCustomer')
227    grok.template('loginasstep1')
228    pnav = 4
229
230    def label(self):
231        return _(u'Set temporary password for ${a}',
[11985]232            mapping={'a': self.context.display_fullname})
[11967]233
234    @action('Set password now', style='primary')
235    def setPassword(self, *args, **data):
[11979]236        ikoba_utils = getUtility(IIkobaUtils)
237        password = ikoba_utils.genPassword()
[11967]238        self.context.setTempPassword(self.request.principal.id, password)
239        self.context.writeLogMessage(
240            self, 'temp_password generated: %s' % password)
[11985]241        args = {'password': password}
[11967]242        self.redirect(self.url(self.context) +
243            '/loginasstep2?%s' % urlencode(args))
244        return
245
[11985]246
[11967]247class LoginAsCustomerStep2(IkobaPage):
248    """ View to temporarily login as customer with a temporary password.
249    """
250    grok.context(ICustomer)
251    grok.name('loginasstep2')
252    grok.require('waeup.Public')
253    grok.template('loginasstep2')
254    login_button = _('Login now')
255    pnav = 4
256
257    def label(self):
258        return _(u'Login as ${a}',
[11985]259            mapping={'a': self.context.customer_id})
[11967]260
261    def update(self, SUBMIT=None, password=None):
262        self.password = password
263        if SUBMIT is not None:
264            self.flash(_('You successfully logged in as customer.'))
265            self.redirect(self.url(self.context))
266        return
267
[11985]268
[11967]269class CustomerBaseDisplayFormPage(IkobaDisplayFormPage):
270    """ Page to display customer base data
271    """
272    grok.context(ICustomer)
273    grok.name('index')
274    grok.require('waeup.viewCustomer')
275    grok.template('basepage')
276    form_fields = grok.AutoFields(ICustomer).omit(
277        'password', 'suspended', 'suspended_comment')
278    pnav = 4
279
280    @property
281    def label(self):
282        if self.context.suspended:
283            return _('${a}: Base Data (account deactivated)',
[11985]284                mapping={'a': self.context.display_fullname})
[11967]285        return  _('${a}: Base Data',
[11985]286            mapping={'a': self.context.display_fullname})
[11967]287
288    @property
289    def hasPassword(self):
290        if self.context.password:
291            return _('set')
292        return _('unset')
293
[11985]294
[11967]295class ContactCustomerForm(ContactAdminForm):
296    grok.context(ICustomer)
297    grok.name('contactcustomer')
298    grok.require('waeup.viewCustomer')
299    pnav = 4
300    form_fields = grok.AutoFields(IContactForm).select('subject', 'body')
301
302    def update(self, subject=u'', body=u''):
303        super(ContactCustomerForm, self).update()
304        self.form_fields.get('subject').field.default = subject
305        self.form_fields.get('body').field.default = body
306        return
307
308    def label(self):
309        return _(u'Send message to ${a}',
[11985]310            mapping={'a': self.context.display_fullname})
[11967]311
312    @action('Send message now', style='primary')
313    def send(self, *args, **data):
314        try:
315            email = self.request.principal.email
316        except AttributeError:
317            email = self.config.email_admin
318        usertype = getattr(self.request.principal,
319                           'user_type', 'system').title()
[11979]320        ikoba_utils = getUtility(IIkobaUtils)
321        success = ikoba_utils.sendContactForm(
[11985]322                self.request.principal.title, email,
323                self.context.display_fullname, self.context.email,
[11967]324                self.request.principal.id,usertype,
325                self.config.name,
[11985]326                data['body'], data['subject'])
[11967]327        if success:
328            self.flash(_('Your message has been sent.'))
329        else:
330            self.flash(_('An smtp server error occurred.'), type="danger")
331        return
332
[11985]333
[11967]334class CustomerBaseManageFormPage(IkobaEditFormPage):
335    """ View to manage customer base data
336    """
337    grok.context(ICustomer)
338    grok.name('manage_base')
339    grok.require('waeup.manageCustomer')
340    form_fields = grok.AutoFields(ICustomer).omit(
341        'customer_id', 'adm_code', 'suspended')
342    grok.template('basemanagepage')
343    label = _('Manage base data')
344    pnav = 4
345
346    def update(self):
347        super(CustomerBaseManageFormPage, self).update()
348        self.wf_info = IWorkflowInfo(self.context)
349        return
350
351    @action(_('Save'), style='primary')
352    def save(self, **data):
353        form = self.request.form
354        password = form.get('password', None)
355        password_ctl = form.get('control_password', None)
356        if password:
357            validator = getUtility(IPasswordValidator)
358            errors = validator.validate_password(password, password_ctl)
359            if errors:
[11985]360                self.flash(' '.join(errors), type="danger")
[11967]361                return
362        changed_fields = self.applyData(self.context, **data)
363        # Turn list of lists into single list
364        if changed_fields:
365            changed_fields = reduce(lambda x,y: x+y, changed_fields.values())
366        else:
367            changed_fields = []
368        if password:
369            # Now we know that the form has no errors and can set password
370            IUserAccount(self.context).setPassword(password)
371            changed_fields.append('password')
372        fields_string = ' + '.join(changed_fields)
373        self.flash(_('Form has been saved.'))
374        if fields_string:
375            self.context.writeLogMessage(self, 'saved: % s' % fields_string)
376        return
377
[11985]378
[11967]379class CustomerTriggerTransitionFormPage(IkobaEditFormPage):
380    """ View to manage customer base data
381    """
382    grok.context(ICustomer)
383    grok.name('trigtrans')
384    grok.require('waeup.triggerTransition')
385    grok.template('trigtrans')
386    label = _('Trigger registration transition')
387    pnav = 4
388
389    def getTransitions(self):
390        """Return a list of dicts of allowed transition ids and titles.
391
392        Each list entry provides keys ``name`` and ``title`` for
393        internal name and (human readable) title of a single
394        transition.
395        """
396        wf_info = IWorkflowInfo(self.context)
397        allowed_transitions = [t for t in wf_info.getManualTransitions()]
398        return [dict(name='', title=_('No transition'))] +[
399            dict(name=x, title=y) for x, y in allowed_transitions]
400
401    @action(_('Save'), style='primary')
402    def save(self, **data):
403        form = self.request.form
404        if 'transition' in form and form['transition']:
405            transition_id = form['transition']
406            wf_info = IWorkflowInfo(self.context)
407            wf_info.fireTransition(transition_id)
408        return
409
[11985]410
[11967]411class CustomerActivatePage(UtilityView, grok.View):
412    """ Activate customer account
413    """
414    grok.context(ICustomer)
415    grok.name('activate')
416    grok.require('waeup.manageCustomer')
417
418    def update(self):
419        self.context.suspended = False
420        self.context.writeLogMessage(self, 'account activated')
421        history = IObjectHistory(self.context)
422        history.addMessage('Customer account activated')
423        self.flash(_('Customer account has been activated.'))
424        self.redirect(self.url(self.context))
425        return
426
427    def render(self):
428        return
429
[11985]430
[11967]431class CustomerDeactivatePage(UtilityView, grok.View):
432    """ Deactivate customer account
433    """
434    grok.context(ICustomer)
435    grok.name('deactivate')
436    grok.require('waeup.manageCustomer')
437
438    def update(self):
439        self.context.suspended = True
440        self.context.writeLogMessage(self, 'account deactivated')
441        history = IObjectHistory(self.context)
442        history.addMessage('Customer account deactivated')
443        self.flash(_('Customer account has been deactivated.'))
444        self.redirect(self.url(self.context))
445        return
446
447    def render(self):
448        return
449
[11985]450
[11967]451class CustomerHistoryPage(IkobaPage):
452    """ Page to display customer history
453    """
454    grok.context(ICustomer)
455    grok.name('history')
456    grok.require('waeup.viewCustomer')
457    grok.template('customerhistory')
458    pnav = 4
459
460    @property
461    def label(self):
[11985]462        return _('${a}: History', mapping={'a':self.context.display_fullname})
[11967]463
[11985]464
[11967]465class CustomerRequestPasswordPage(IkobaAddFormPage):
466    """Captcha'd registration page for applicants.
467    """
468    grok.name('requestpw')
469    grok.require('waeup.Anonymous')
470    grok.template('requestpw')
471    form_fields = grok.AutoFields(ICustomerRequestPW).select(
472        'firstname','number','email')
473    label = _('Request password for first-time login')
474
475    def update(self):
476        # Handle captcha
477        self.captcha = getUtility(ICaptchaManager).getCaptcha()
478        self.captcha_result = self.captcha.verify(self.request)
479        self.captcha_code = self.captcha.display(self.captcha_result.error_code)
480        return
481
482    def _redirect(self, email, password, customer_id):
483        # Forward only email to landing page in base package.
484        self.redirect(self.url(self.context, 'requestpw_complete',
[11985]485            data=dict(email=email)))
[11967]486        return
487
488    def _pw_used(self):
489        # XXX: False if password has not been used. We need an extra
490        #      attribute which remembers if customer logged in.
491        return True
492
493    @action(_('Send login credentials to email address'), style='primary')
494    def get_credentials(self, **data):
495        if not self.captcha_result.is_valid:
496            # Captcha will display error messages automatically.
497            # No need to flash something.
498            return
499        number = data.get('number','')
500        firstname = data.get('firstname','')
501        cat = getUtility(ICatalog, name='customers_catalog')
502        results = list(
503            cat.searchResults(reg_number=(number, number)))
504        if results:
505            customer = results[0]
506            if getattr(customer,'firstname',None) is None:
507                self.flash(_('An error occurred.'), type="danger")
508                return
509            elif customer.firstname.lower() != firstname.lower():
510                # Don't tell the truth here. Anonymous must not
511                # know that a record was found and only the firstname
512                # verification failed.
513                self.flash(_('No customer record found.'), type="warning")
514                return
515            elif customer.password is not None and self._pw_used:
516                self.flash(_('Your password has already been set and used. '
517                             'Please proceed to the login page.'),
518                           type="warning")
519                return
520            # Store email address but nothing else.
521            customer.email = data['email']
522            notify(grok.ObjectModifiedEvent(customer))
523        else:
524            # No record found, this is the truth.
525            self.flash(_('No customer record found.'), type="warning")
526            return
527
[11979]528        ikoba_utils = getUtility(IIkobaUtils)
529        password = ikoba_utils.genPassword()
[11967]530        mandate = PasswordMandate()
531        mandate.params['password'] = password
532        mandate.params['user'] = customer
533        site = grok.getSite()
534        site['mandates'].addMandate(mandate)
535        # Send email with credentials
536        args = {'mandate_id':mandate.mandate_id}
537        mandate_url = self.url(site) + '/mandate?%s' % urlencode(args)
538        url_info = u'Confirmation link: %s' % mandate_url
539        msg = _('You have successfully requested a password for the')
[11979]540        if ikoba_utils.sendCredentials(IUserAccount(customer),
[11967]541            password, url_info, msg):
542            email_sent = customer.email
543        else:
544            email_sent = None
545        self._redirect(email=email_sent, password=password,
546            customer_id=customer.customer_id)
[11977]547        ob_class = self.__implemented__.__name__.replace('waeup.ikoba.','')
[11967]548        self.context.logger.info(
549            '%s - %s (%s) - %s' % (ob_class, number, customer.customer_id, email_sent))
550        return
551
[11985]552
[11967]553class CustomerRequestPasswordEmailSent(IkobaPage):
554    """Landing page after successful password request.
555
556    """
557    grok.name('requestpw_complete')
558    grok.require('waeup.Public')
559    grok.template('requestpwmailsent')
560    label = _('Your password request was successful.')
561
562    def update(self, email=None, customer_id=None, password=None):
563        self.email = email
564        self.password = password
565        self.customer_id = customer_id
[11971]566        return
567
[11985]568
[11971]569class CustomerFilesUploadPage(IkobaPage):
570    """ View to upload files by customer
571    """
572    grok.context(ICustomer)
573    grok.name('change_portrait')
574    grok.require('waeup.uploadCustomerFile')
575    grok.template('filesuploadpage')
576    label = _('Upload files')
577    pnav = 4
578
579    def update(self):
[12018]580        CUSTMANAGE_STATES = getUtility(ICustomersUtils).CUSTMANAGE_STATES
581        if self.context.customer.state not in CUSTMANAGE_STATES:
[11971]582            emit_lock_message(self)
583            return
584        super(CustomerFilesUploadPage, self).update()
585        return
586
[12015]587# Pages for customers
[11971]588
[11985]589
[11971]590class CustomerBaseEditFormPage(IkobaEditFormPage):
591    """ View to edit customer base data
592    """
593    grok.context(ICustomer)
594    grok.name('edit_base')
595    grok.require('waeup.handleCustomer')
596    form_fields = grok.AutoFields(ICustomer).select(
597        'email', 'phone')
598    label = _('Edit base data')
599    pnav = 4
600
601    @action(_('Save'), style='primary')
602    def save(self, **data):
603        msave(self, **data)
604        return
605
[11985]606
[11971]607class CustomerChangePasswordPage(IkobaEditFormPage):
608    """ View to edit customer passords
609    """
610    grok.context(ICustomer)
[11977]611    grok.name('changepassword')
[11971]612    grok.require('waeup.handleCustomer')
[11977]613    grok.template('changepassword')
[11971]614    label = _('Change password')
615    pnav = 4
616
617    @action(_('Save'), style='primary')
618    def save(self, **data):
619        form = self.request.form
620        password = form.get('change_password', None)
621        password_ctl = form.get('change_password_repeat', None)
622        if password:
623            validator = getUtility(IPasswordValidator)
624            errors = validator.validate_password(password, password_ctl)
625            if not errors:
626                IUserAccount(self.context).setPassword(password)
627                self.context.writeLogMessage(self, 'saved: password')
628                self.flash(_('Password changed.'))
629            else:
[11985]630                self.flash(' '.join(errors), type="warning")
[11971]631        return
[12015]632
633# Pages for customer documents
634
635class DocumentsBreadcrumb(Breadcrumb):
636    """A breadcrumb for the documents container.
637    """
638    grok.context(ICustomerDocumentsContainer)
639    title = _('Documents')
640
641
642class DocumentBreadcrumb(Breadcrumb):
643    """A breadcrumb for the customer container.
644    """
645    grok.context(ICustomerDocument)
646
647    @property
648    def title(self):
649        return self.context.document_id
650
651
652class DocumentsManageFormPage(IkobaEditFormPage):
653    """ Page to manage the customer documents
654
655    This manage form page is for both customers and customers officers.
656    """
657    grok.context(ICustomerDocumentsContainer)
658    grok.name('index')
659    grok.require('waeup.viewCustomer')
660    form_fields = grok.AutoFields(ICustomerDocumentsContainer)
661    grok.template('documentsmanagepage')
662    pnav = 4
663
664    @property
665    def manage_documents_allowed(self):
666        return checkPermission('waeup.editCustomerDocuments', self.context)
667
668    def unremovable(self, document):
669        usertype = getattr(self.request.principal, 'user_type', None)
670        if not usertype:
671            return False
672        if not self.manage_documents_allowed:
673            return True
674        return (self.request.principal.user_type == 'customer' and \
675            document.state in (VERIFIED, REJECTED, OUTDATED))
676
677    @property
678    def label(self):
679        return _('${a}: Documents',
680            mapping = {'a':self.context.__parent__.display_fullname})
681
682    @jsaction(_('Remove selected documents'))
683    def delDocument(self, **data):
684        form = self.request.form
685        if 'val_id' in form:
686            child_id = form['val_id']
687        else:
688            self.flash(_('No document selected.'), type="warning")
689            self.redirect(self.url(self.context))
690            return
691        if not isinstance(child_id, list):
692            child_id = [child_id]
693        deleted = []
694        for id in child_id:
695            # Customers are not allowed to remove used documents
696            document = self.context.get(id, None)
697            if document is not None and not self.unremovable(document):
698                del self.context[id]
699                deleted.append(id)
700        if len(deleted):
701            self.flash(_('Successfully removed: ${a}',
702                mapping = {'a': ', '.join(deleted)}))
703            self.context.writeLogMessage(
704                self,'removed: %s' % ', '.join(deleted))
705        self.redirect(self.url(self.context))
706        return
707
708
709class DocumentAddFormPage(IkobaAddFormPage):
710    """ Page to add an document
711    """
712    grok.context(ICustomerDocumentsContainer)
713    grok.name('adddoc')
714    grok.template('documentaddform')
715    grok.require('waeup.editCustomerDocuments')
716    form_fields = grok.AutoFields(ICustomerDocument)
717    label = _('Add document')
718    pnav = 4
719
720    @property
721    def selectable_doctypes(self):
722        doctypes = getUtility(IIkobaUtils).DOCUMENT_TYPES
723        return sorted(doctypes.items())
724
725    @action(_('Create document'), style='primary')
726    def createDocument(self, **data):
727        form = self.request.form
728        customer = self.context.__parent__
729        doctype = form.get('doctype', None)
730        # Here we can create various instances of CustomerDocument derived
731        # classes depending on the doctype parameter given in form.
732        # So far we only have one CustomerDocument class and no derived
733        # classes.
734        document = createObject(u'waeup.CustomerDocument')
735        self.context.addDocument(document)
736        doctype = getUtility(IIkobaUtils).DOCUMENT_TYPES[doctype]
737        self.flash(_('${a} created.',
738            mapping = {'a': doctype}))
739        self.context.writeLogMessage(
740            self,'added: %s %s' % (doctype, document.document_id))
741        self.redirect(self.url(self.context))
742        return
743
744    @action(_('Cancel'), validator=NullValidator)
745    def cancel(self, **data):
746        self.redirect(self.url(self.context))
747
748
749class DocumentDisplayFormPage(IkobaDisplayFormPage):
750    """ Page to view a document
751    """
752    grok.context(ICustomerDocument)
753    grok.name('index')
754    grok.require('waeup.viewCustomer')
[12016]755    grok.template('documentpage')
[12015]756    form_fields = grok.AutoFields(ICustomerDocument)
757    pnav = 4
758
[12018]759    #@property
760    #def label(self):
761    #    return _('${a}: Document ${b}', mapping = {
762    #        'a':self.context.customer.display_fullname,
763    #        'b':self.context.document_id})
764
[12015]765    @property
766    def label(self):
[12018]767        return _('${a}', mapping = {'a':self.context.title})
[12015]768
769
770class DocumentManageFormPage(IkobaEditFormPage):
771    """ Page to edit a document
772    """
773    grok.context(ICustomerDocument)
774    grok.name('manage')
[12016]775    grok.require('waeup.manageCustomer')
[12018]776    grok.template('documenteditpage')
[12015]777    form_fields = grok.AutoFields(ICustomerDocument)
778    pnav = 4
779
[12018]780    #@property
781    #def label(self):
782    #    return _('${a}: Document ${b}', mapping = {
783    #        'a':self.context.customer.display_fullname,
784    #        'b':self.context.document_id})
785
[12015]786    @property
787    def label(self):
[12018]788        return _('${a}', mapping = {'a':self.context.title})
[12016]789
790    @action(_('Save'), style='primary')
791    def save(self, **data):
792        msave(self, **data)
[12018]793        return
794
795class DocumentEditFormPage(DocumentManageFormPage):
796    """ Page to edit a document
797    """
798    grok.context(ICustomerDocument)
799    grok.name('edit')
800    grok.require('waeup.handleCustomer')
801    form_fields = grok.AutoFields(ICustomerDocument)
802    pnav = 4
803
804    def update(self):
805        if not self.context.is_editable:
806            emit_lock_message(self)
807            return
808        return super(DocumentEditFormPage, self).update()
Note: See TracBrowser for help on using the repository browser.