source: main/waeup.sirp/trunk/src/waeup/sirp/applicants/browser.py @ 6357

Last change on this file since 6357 was 6357, checked in by Henrik Bettermann, 13 years ago

Implement pdf slip demo version.

File size: 22.7 KB
RevLine 
[5273]1##
2## browser.py
3## Login : <uli@pu.smp.net>
[6153]4## Started on  Sun Jun 27 11:03:10 2010 Uli Fouquet & Henrik Bettermann
[5273]5## $Id$
[6078]6##
[6063]7## Copyright (C) 2010 Uli Fouquet & Henrik Bettermann
[5273]8## This program is free software; you can redistribute it and/or modify
9## it under the terms of the GNU General Public License as published by
10## the Free Software Foundation; either version 2 of the License, or
11## (at your option) any later version.
[6078]12##
[5273]13## This program is distributed in the hope that it will be useful,
14## but WITHOUT ANY WARRANTY; without even the implied warranty of
15## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16## GNU General Public License for more details.
[6078]17##
[5273]18## You should have received a copy of the GNU General Public License
19## along with this program; if not, write to the Free Software
20## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21##
[5824]22"""UI components for basic applicants and related components.
[5273]23"""
[6082]24import sys
[5273]25import grok
26
[6305]27from datetime import datetime
[6081]28from zope.formlib.widget import CustomWidgetFactory
[5937]29from zope.securitypolicy.interfaces import IPrincipalRoleManager
[6153]30from zope.traversing.browser import absoluteURL
[6081]31
[6303]32from hurry.workflow.interfaces import IWorkflowInfo, IWorkflowState
33
[6357]34from reportlab.pdfgen import canvas
35
[5273]36from waeup.sirp.browser import (
[6321]37    WAeUPPage, WAeUPEditFormPage, WAeUPAddFormPage, WAeUPDisplayFormPage)
[6081]38from waeup.sirp.browser.breadcrumbs import Breadcrumb
[6103]39from waeup.sirp.browser.layout import NullValidator
[6321]40from waeup.sirp.browser.pages import add_local_role, del_local_roles
[6013]41from waeup.sirp.browser.resources import datepicker, tabs, datatable
[6153]42from waeup.sirp.browser.viewlets import (
43    ManageActionButton, PrimaryNavTab, LeftSidebarLink
44    )
[6081]45from waeup.sirp.image.browser.widget import (
46    ThumbnailWidget, EncodingImageFileWidget,
[5822]47    )
[6184]48from waeup.sirp.interfaces import IWAeUPObject, ILocalRolesAssignable
[6321]49from waeup.sirp.permissions import get_users_with_local_roles
[6254]50from waeup.sirp.university.interfaces import ICertificate
[6054]51from waeup.sirp.widgets.datewidget import (
52    FriendlyDateWidget, FriendlyDateDisplayWidget)
[6084]53from waeup.sirp.widgets.restwidget import ReSTDisplayWidget
[5303]54from waeup.sirp.widgets.objectwidget import (
[5301]55    WAeUPObjectWidget, WAeUPObjectDisplayWidget)
[5303]56from waeup.sirp.widgets.multilistwidget import (
[5273]57    MultiListWidget, MultiListDisplayWidget)
[6153]58from waeup.sirp.applicants import ResultEntry, Applicant, get_applicant_data
[6081]59from waeup.sirp.applicants.interfaces import (
[6321]60    IApplicant, IApplicantPrincipal,IApplicantEdit, IApplicantsRoot,
61    IApplicantsContainer, IApplicantsContainerAdd, application_types_vocab
[5686]62    )
[6353]63from waeup.sirp.applicants.workflow import INITIALIZED, STARTED
[5320]64
[5273]65results_widget = CustomWidgetFactory(
[5301]66    WAeUPObjectWidget, ResultEntry)
[5273]67
68results_display_widget = CustomWidgetFactory(
[5301]69    WAeUPObjectDisplayWidget, ResultEntry)
[5273]70
71list_results_widget = CustomWidgetFactory(
72    MultiListWidget, subwidget=results_widget)
73
74list_results_display_widget = CustomWidgetFactory(
75    MultiListDisplayWidget, subwidget=results_display_widget)
76
[6353]77#TRANSITION_OBJECTS = create_workflow()
[6305]78
[6322]79#TRANSITION_DICT = dict([
80#    (transition_object.transition_id,transition_object.title)
81#    for transition_object in TRANSITION_OBJECTS])
[6305]82
[6067]83class ApplicantsRootPage(WAeUPPage):
[5822]84    grok.context(IApplicantsRoot)
85    grok.name('index')
[6153]86    grok.require('waeup.Public')
[5822]87    title = 'Applicants'
[6069]88    label = 'Application Section'
[5843]89    pnav = 3
[6012]90
91    def update(self):
[6067]92        super(ApplicantsRootPage, self).update()
[6012]93        datatable.need()
94        return
95
[5828]96class ManageApplicantsRootActionButton(ManageActionButton):
97    grok.context(IApplicantsRoot)
[6067]98    grok.view(ApplicantsRootPage)
[6198]99    grok.require('waeup.manageApplications')
[6069]100    text = 'Manage application section'
[5828]101
[6069]102class ApplicantsRootManageFormPage(WAeUPEditFormPage):
[5828]103    grok.context(IApplicantsRoot)
104    grok.name('manage')
[6107]105    grok.template('applicantsrootmanagepage')
[6069]106    title = 'Applicants'
107    label = 'Manage application section'
[5843]108    pnav = 3
[6198]109    grok.require('waeup.manageApplications')
[6069]110    taboneactions = ['Add applicants container', 'Remove selected','Cancel']
[6184]111    tabtwoactions1 = ['Remove selected local roles']
112    tabtwoactions2 = ['Add local role']
[6069]113    subunits = 'Applicants Containers'
[6078]114
[6069]115    def update(self):
116        tabs.need()
[6108]117        datatable.need()
[6069]118        return super(ApplicantsRootManageFormPage, self).update()
[5828]119
[6184]120    def getLocalRoles(self):
121        roles = ILocalRolesAssignable(self.context)
122        return roles()
123
124    def getUsers(self):
125        """Get a list of all users.
126        """
127        for key, val in grok.getSite()['users'].items():
128            url = self.url(val)
129            yield(dict(url=url, name=key, val=val))
130
131    def getUsersWithLocalRoles(self):
132        return get_users_with_local_roles(self.context)
133
[6069]134    # ToDo: Show warning message before deletion
135    @grok.action('Remove selected')
136    def delApplicantsContainers(self, **data):
137        form = self.request.form
138        child_id = form['val_id']
139        if not isinstance(child_id, list):
140            child_id = [child_id]
141        deleted = []
142        for id in child_id:
143            try:
144                del self.context[id]
145                deleted.append(id)
146            except:
147                self.flash('Could not delete %s: %s: %s' % (
148                        id, sys.exc_info()[0], sys.exc_info()[1]))
149        if len(deleted):
150            self.flash('Successfully removed: %s' % ', '.join(deleted))
[6078]151        self.redirect(self.url(self.context, '@@manage')+'#tab-1')
152        return
[5828]153
[6069]154    @grok.action('Add applicants container', validator=NullValidator)
155    def addApplicantsContainer(self, **data):
156        self.redirect(self.url(self.context, '@@add'))
[6078]157        return
158
[6069]159    @grok.action('Cancel', validator=NullValidator)
160    def cancel(self, **data):
161        self.redirect(self.url(self.context))
[6078]162        return
163
[6184]164    @grok.action('Add local role', validator=NullValidator)
165    def addLocalRole(self, **data):
166        return add_local_role(self,2, **data)
167
168    @grok.action('Remove selected local roles')
169    def delLocalRoles(self, **data):
170        return del_local_roles(self,2,**data)
171
[6069]172class ApplicantsContainerAddFormPage(WAeUPAddFormPage):
[5822]173    grok.context(IApplicantsRoot)
[6198]174    grok.require('waeup.manageApplications')
[5822]175    grok.name('add')
[6107]176    grok.template('applicantscontaineraddpage')
[6069]177    title = 'Applicants'
178    label = 'Add applicants container'
[5843]179    pnav = 3
[6078]180
[6103]181    form_fields = grok.AutoFields(
182        IApplicantsContainerAdd).omit('code').omit('title')
[6083]183    form_fields['startdate'].custom_widget = FriendlyDateWidget('le')
184    form_fields['enddate'].custom_widget = FriendlyDateWidget('le')
[6078]185
[6083]186    def update(self):
187        datepicker.need() # Enable jQuery datepicker in date fields.
188        return super(ApplicantsContainerAddFormPage, self).update()
189
[6069]190    @grok.action('Add applicants container')
191    def addApplicantsContainer(self, **data):
[6103]192        year = data['year']
193        code = u'%s%s' % (data['prefix'], year)
194        prefix = application_types_vocab.getTerm(data['prefix'])
195        title = u'%s %s/%s' % (prefix.title, year, year + 1)
[6087]196        if code in self.context.keys():
[6105]197            self.flash(
198                'An applicants container for the same application '
199                'type and entrance year exists already in the database.')
[5822]200            return
201        # Add new applicants container...
[6083]202        provider = data['provider'][1]
[5822]203        container = provider.factory()
[6069]204        self.applyData(container, **data)
[6087]205        container.code = code
206        container.title = title
207        self.context[code] = container
[6105]208        self.flash('Added: "%s".' % code)
[6069]209        self.redirect(self.url(self.context, u'@@manage')+'#tab-1')
[5822]210        return
[6078]211
[6103]212    @grok.action('Cancel', validator=NullValidator)
[6069]213    def cancel(self, **data):
[6103]214        self.redirect(self.url(self.context, '@@manage') + '#tab-1')
[6078]215
[5845]216class ApplicantsRootBreadcrumb(Breadcrumb):
217    """A breadcrumb for applicantsroot.
218    """
219    grok.context(IApplicantsRoot)
[6153]220    title = u'Application Section'
[6078]221
[5845]222class ApplicantsContainerBreadcrumb(Breadcrumb):
223    """A breadcrumb for applicantscontainers.
224    """
225    grok.context(IApplicantsContainer)
[6319]226
[6153]227class ApplicantBreadcrumb(Breadcrumb):
228    """A breadcrumb for applicants.
229    """
230    grok.context(IApplicant)
[6319]231
[6153]232    @property
233    def title(self):
234        """Get a title for a context.
235        """
236        return self.context.access_code
[5828]237
238class ApplicantsTab(PrimaryNavTab):
[6153]239    """Applicants tab in primary navigation.
[5828]240    """
[6078]241
[5828]242    grok.context(IWAeUPObject)
243    grok.order(3)
[6336]244    grok.require('waeup.Public')
[5828]245    grok.template('primarynavtab')
246
[5843]247    pnav = 3
[5828]248    tab_title = u'Applicants'
249
250    @property
251    def link_target(self):
252        return self.view.application_url('applicants')
253
[6029]254class ApplicantsContainerPage(WAeUPDisplayFormPage):
[5830]255    """The standard view for regular applicant containers.
256    """
257    grok.context(IApplicantsContainer)
258    grok.name('index')
[6153]259    grok.require('waeup.Public')
[6029]260    grok.template('applicantscontainerpage')
[5850]261    pnav = 3
[6053]262
[6105]263    form_fields = grok.AutoFields(IApplicantsContainer).omit('title')
[6054]264    form_fields['startdate'].custom_widget = FriendlyDateDisplayWidget('le')
265    form_fields['enddate'].custom_widget = FriendlyDateDisplayWidget('le')
[6084]266    form_fields['description'].custom_widget = ReSTDisplayWidget
[6053]267
[5837]268    @property
269    def title(self):
[6087]270        return "Applicants Container: %s" % self.context.title
[5837]271
272    @property
273    def label(self):
[6087]274        return self.context.title
[5830]275
[6107]276class ApplicantsContainerManageActionButton(ManageActionButton):
[6336]277    grok.order(1)
[5832]278    grok.context(IApplicantsContainer)
279    grok.view(ApplicantsContainerPage)
[6198]280    grok.require('waeup.manageApplications')
[6070]281    text = 'Manage applicants container'
[5832]282
[6336]283class LoginApplicantActionButton(ManageActionButton):
284    grok.order(2)
285    grok.context(IApplicantsContainer)
286    grok.view(ApplicantsContainerPage)
287    grok.require('waeup.Anonymous')
288    icon = 'login.png'
289    text = 'Login for applicants'
290    target = 'login'
[5832]291
[6107]292class ApplicantsContainerManageFormPage(WAeUPEditFormPage):
[5837]293    grok.context(IApplicantsContainer)
[5850]294    grok.name('manage')
[6107]295    grok.template('applicantscontainermanagepage')
[6105]296    form_fields = grok.AutoFields(IApplicantsContainer).omit('title')
297    taboneactions = ['Save','Cancel']
298    tabtwoactions = ['Add applicant', 'Remove selected','Cancel']
[6184]299    tabthreeactions1 = ['Remove selected local roles']
300    tabthreeactions2 = ['Add local role']
[5844]301    # Use friendlier date widget...
[6054]302    form_fields['startdate'].custom_widget = FriendlyDateWidget('le')
303    form_fields['enddate'].custom_widget = FriendlyDateWidget('le')
[6198]304    grok.require('waeup.manageApplications')
[5850]305
306    @property
307    def title(self):
[6087]308        return "Applicants Container: %s" % self.context.title
[6078]309
[5850]310    @property
311    def label(self):
[6087]312        return 'Manage applicants container'
[5850]313
[5845]314    pnav = 3
[5837]315
316    def update(self):
[5850]317        datepicker.need() # Enable jQuery datepicker in date fields.
[5982]318        tabs.need()
[6015]319        datatable.need()  # Enable jQurey datatables for contents listing
[6107]320        return super(ApplicantsContainerManageFormPage, self).update()
[5837]321
[6184]322    def getLocalRoles(self):
323        roles = ILocalRolesAssignable(self.context)
324        return roles()
325
326    def getUsers(self):
327        """Get a list of all users.
328        """
329        for key, val in grok.getSite()['users'].items():
330            url = self.url(val)
331            yield(dict(url=url, name=key, val=val))
332
333    def getUsersWithLocalRoles(self):
334        return get_users_with_local_roles(self.context)
335
[5850]336    @grok.action('Save')
[5837]337    def apply(self, **data):
338        self.applyData(self.context, **data)
339        self.flash('Data saved.')
340        return
[6078]341
[6105]342    # ToDo: Show warning message before deletion
343    @grok.action('Remove selected')
344    def delApplicant(self, **data):
[6189]345        form = self.request.form
346        if form.has_key('val_id'):
347            child_id = form['val_id']
348        else:
349            self.flash('No applicant selected!')
350            self.redirect(self.url(self.context, '@@manage')+'#tab-2')
351            return
352        if not isinstance(child_id, list):
353            child_id = [child_id]
354        deleted = []
355        for id in child_id:
356            try:
357                del self.context[id]
358                deleted.append(id)
359            except:
360                self.flash('Could not delete %s: %s: %s' % (
361                        id, sys.exc_info()[0], sys.exc_info()[1]))
362        if len(deleted):
363            self.flash('Successfully removed: %s' % ', '.join(deleted))
364        self.redirect(self.url(self.context, u'@@manage')+'#tab-2')
365        return
[6105]366
367    @grok.action('Add applicant', validator=NullValidator)
368    def addApplicant(self, **data):
[6327]369        self.redirect(self.url(self.context, 'addapplicant'))
370        return
[6105]371
372    @grok.action('Cancel', validator=NullValidator)
[5837]373    def cancel(self, **data):
374        self.redirect(self.url(self.context))
375        return
[5886]376
[6184]377    @grok.action('Add local role', validator=NullValidator)
378    def addLocalRole(self, **data):
379        return add_local_role(self,3, **data)
[6105]380
[6184]381    @grok.action('Remove selected local roles')
382    def delLocalRoles(self, **data):
383        return del_local_roles(self,3,**data)
384
[5886]385class LoginApplicant(WAeUPPage):
386    grok.context(IApplicantsContainer)
387    grok.name('login')
[6153]388    grok.require('waeup.Public')
[5886]389
[6110]390    @property
391    def title(self):
392        return u"Applicant Login: %s" % self.context.title
[6078]393
[5886]394    @property
395    def label(self):
[6110]396        return u'Login for applicants only'
[5886]397
398    pnav = 3
[6319]399
[6110]400    @property
401    def ac_prefix(self):
402        return self.context.ac_prefix
[6078]403
[5896]404    def update(self, SUBMIT=None):
405        self.ac_series = self.request.form.get('form.ac_series', None)
406        self.ac_number = self.request.form.get('form.ac_number', None)
[5886]407        if SUBMIT is None:
408            return
[5894]409        if self.request.principal.id == 'zope.anybody':
[6105]410            self.flash('Entered credentials are invalid.')
[5886]411            return
[5894]412        if not IApplicantPrincipal.providedBy(self.request.principal):
413            # Don't care if user is already authenticated as non-applicant
414            return
[5905]415        pin = self.request.principal.access_code
416        if pin not in self.context.keys():
417            # Create applicant record
418            applicant = Applicant()
419            applicant.access_code = pin
420            self.context[pin] = applicant
[5937]421        # Assign current principal the owner role on created applicant
422        # record
[6184]423        role_manager = IPrincipalRoleManager(self.context[pin])
[5937]424        role_manager.assignRoleToPrincipal(
[6043]425            'waeup.local.ApplicationOwner', self.request.principal.id)
[6325]426        # Assign current principal the PortalUser role
427        role_manager = IPrincipalRoleManager(grok.getSite()['faculties'])
428        role_manager.assignRoleToPrincipal(
429            'waeup.PortalUser', self.request.principal.id)
[6349]430        # XXX: disable for now. Pins will get a different workflow.
431        #state = IWorkflowState(self.context[pin]).getState()
432        #if state == INITIALIZED:
433        #    IWorkflowInfo(self.context[pin]).fireTransition('start')
[5937]434        self.redirect(self.url(self.context[pin], 'edit'))
[5886]435        return
[6319]436
[6327]437class ApplicantAddFormPage(WAeUPAddFormPage):
438    """Add-form to add certificate to a department.
439    """
440    grok.context(IApplicantsContainer)
441    grok.require('waeup.manageApplications')
442    grok.name('addapplicant')
443    grok.template('applicantaddpage')
444    title = 'Applicants'
445    label = 'Add applicant'
446    pnav = 3
447
448    @property
449    def title(self):
450        return "Applicants Container: %s" % self.context.title
451
452    @property
453    def ac_prefix(self):
454        return self.context.ac_prefix
455
456    @grok.action('Create application record')
457    def addApplicant(self, **data):
458        ac_series = self.request.form.get('form.ac_series', None)
459        ac_number = self.request.form.get('form.ac_number', None)
460        pin = '%s-%s-%s' % (self.ac_prefix,ac_series,ac_number)
461        if pin not in self.context.keys():
462            # Create applicant record
463            applicant = Applicant()
464            applicant.access_code = pin
465            self.context[pin] = applicant
466        self.redirect(self.url(self.context[pin], 'edit'))
467        return
468
[6153]469class AccessCodeLink(LeftSidebarLink):
470    grok.order(1)
471    grok.require('waeup.Public')
[5886]472
[6153]473    def render(self):
474        if not IApplicantPrincipal.providedBy(self.request.principal):
475            return ''
476        access_code = getattr(self.request.principal,'access_code',None)
477        if access_code:
478            applicant_object = get_applicant_data(access_code)
479            url = absoluteURL(applicant_object, self.request)
[6198]480            return u'<div class="portlet"><a href="%s/edit">%s</a></div>' % (
[6153]481                url,access_code)
482        return ''
483
[5273]484class DisplayApplicant(WAeUPDisplayFormPage):
485    grok.context(IApplicant)
486    grok.name('index')
[6198]487    grok.require('waeup.handleApplication')
[6320]488    form_fields = grok.AutoFields(IApplicant).omit(
489        'locked').omit('course_admitted')
[6196]490    #form_fields['fst_sit_results'].custom_widget = list_results_display_widget
[5919]491    form_fields['passport'].custom_widget = ThumbnailWidget
[6054]492    form_fields['date_of_birth'].custom_widget = FriendlyDateDisplayWidget('le')
[5273]493    label = 'Applicant'
[6254]494    grok.template('form_display')
[5843]495    pnav = 3
[5273]496
[6196]497    @property
498    def title(self):
499        return '%s' % self.context.access_code
500
501    @property
502    def label(self):
503        container_title = self.context.__parent__.title
504        return '%s Application Record' % container_title
505
[6254]506    def getCourseAdmitted(self):
[6355]507        """Return link, title and code in html format to the certificate
508           admitted.
[6351]509        """
[6254]510        course_admitted = self.context.course_admitted
511        if ICertificate.providedBy(course_admitted):
512            url = self.url(course_admitted)
513            title = course_admitted.title
514            code = course_admitted.code
515            return '<a href="%s">%s (%s)</a>' %(url,title,code)
516        return 'not yet admitted'
517
[6198]518class ApplicantsManageActionButton(ManageActionButton):
519    grok.context(IApplicant)
520    grok.view(DisplayApplicant)
521    grok.require('waeup.manageApplications')
522    text = 'Edit application record'
523    target = 'edit_full'
524
[6196]525class EditApplicantFull(WAeUPEditFormPage):
526    """A full edit view for applicant data.
527    """
528    grok.context(IApplicant)
529    grok.name('edit_full')
[6198]530    grok.require('waeup.manageApplications')
[6196]531    form_fields = grok.AutoFields(IApplicant)   #.omit('locked')
532    form_fields['passport'].custom_widget = EncodingImageFileWidget
533    form_fields['date_of_birth'].custom_widget = FriendlyDateWidget('le-year')
534    grok.template('form_edit')
[6322]535    manage_applications = True
[6196]536    pnav = 3
537
538    def update(self):
539        datepicker.need() # Enable jQuery datepicker in date fields.
540        super(EditApplicantFull, self).update()
[6353]541        self.wf_info = IWorkflowInfo(self.context)
[6196]542        return
543
544    @property
545    def title(self):
546        return self.context.access_code
547
548    @property
549    def label(self):
550        container_title = self.context.__parent__.title
551        return '%s Application Form' % container_title
552
[6303]553    def getTransitions(self):
[6351]554        """Return a list of dicts of allowed transition ids and titles.
[6353]555
556        Each list entry provides keys ``name`` and ``title`` for
557        internal name and (human readable) title of a single
558        transition.
[6349]559        """
[6353]560        allowed_transitions = self.wf_info.getManualTransitions()
[6355]561        return [dict(name='', title='No transition')] +[
562            dict(name=x, title=y) for x, y in allowed_transitions]
[6303]563
[6196]564    @grok.action('Save')
565    def save(self, **data):
566        self.applyData(self.context, **data)
567        self.context._p_changed = True
[6303]568        form = self.request.form
569        if form.has_key('transition') and form['transition']:
[6305]570            transition_id = form['transition']
[6353]571            self.wf_info.fireTransition(transition_id)
[6196]572        self.flash('Form has been saved.')
[6348]573        self.context.getApplicantsRootLogger().info('Saved')
[6196]574        return
575
[6357]576class PDFActionButton(ManageActionButton):
577    grok.context(IApplicant)
578    grok.view(DisplayApplicant)
579    grok.require('waeup.handleApplication')
580    icon = 'actionicon_pdf.png'
581    text = 'Download pdf slip'
582    target = 'application_slip.pdf'
583
584class ExportPDFPage(grok.View):
585    """Deliver a PDF slip of the context.
586    """
587    grok.context(IApplicant)
588    grok.name('application_slip.pdf')
589    grok.require('waeup.handleApplication')
590
591    # Render a demo pdf pagge
592    def render(self):
593        #exporter = IWAeUPXMLExporter(self.context)
594        #xml = exporter.export().read()
595        pdf = canvas.Canvas("application_slip.pdf")
596        pdf.drawString(100,750,"Welcome to Reportlab!")
597        self.response.setHeader(
598            'Content-Type', 'application/pdf')
599        return pdf.getpdfdata()
600
[6196]601class EditApplicantStudent(EditApplicantFull):
[5982]602    """An applicant-centered edit view for applicant data.
603    """
[6196]604    grok.context(IApplicantEdit)
[5273]605    grok.name('edit')
[6198]606    grok.require('waeup.handleApplication')
[6196]607    form_fields = grok.AutoFields(IApplicantEdit).omit('locked')
[5686]608    form_fields['passport'].custom_widget = EncodingImageFileWidget
[6054]609    form_fields['date_of_birth'].custom_widget = FriendlyDateWidget('le-year')
[6196]610    grok.template('form_edit')
[6322]611    manage_applications = False
[5484]612
[6322]613
[5941]614    def emitLockMessage(self):
[6105]615        self.flash('The requested form is locked (read-only).')
[5941]616        self.redirect(self.url(self.context))
617        return
[6078]618
[5686]619    def update(self):
[5941]620        if self.context.locked:
[6198]621            self.redirect(self.url(self.context))
[5941]622            return
[6040]623        datepicker.need() # Enable jQuery datepicker in date fields.
[5982]624        super(EditApplicantStudent, self).update()
[5686]625        return
[5952]626
[6196]627    def dataNotComplete(self):
[6322]628        if not self.request.form.get('confirm_passport', False):
[6196]629            return 'Passport confirmation box not ticked.'
630        if len(self.errors) > 0:
631            return 'Form has errors.'
632        return False
[5952]633
[5273]634    @grok.action('Save')
635    def save(self, **data):
[5941]636        if self.context.locked:
637            self.emitLockMessage()
638            return
[5273]639        self.applyData(self.context, **data)
640        self.context._p_changed = True
[6196]641        self.flash('Form has been saved.')
[5273]642        return
643
[5484]644    @grok.action('Final Submit')
645    def finalsubmit(self, **data):
[5941]646        if self.context.locked:
647            self.emitLockMessage()
648            return
[5273]649        self.applyData(self.context, **data)
[5484]650        self.context._p_changed = True
[6196]651        if self.dataNotComplete():
652            self.flash(self.dataNotComplete())
[5941]653            return
[6303]654        state = IWorkflowState(self.context).getState()
[6322]655        # This shouldn't happen, but the application officer
656        # might have forgotten to lock the form after changing the state
[6303]657        if state != STARTED:
[6322]658            self.flash('This form cannot be submitted. Wrong state!')
[6303]659            return
660        IWorkflowInfo(self.context).fireTransition('submit')
[5941]661        self.context.locked = True
[6196]662        self.flash('Form has been submitted.')
663        self.redirect(self.url(self.context))
[5273]664        return
[5941]665
Note: See TracBrowser for help on using the repository browser.