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

Last change on this file since 6335 was 6332, checked in by uli, 14 years ago

Rename 'getApplicationState' to 'state'. Properties are always named like
attributes (lowe_case_with_underscores; they appear as attributes in the

interface) and not like methods (camelCase).

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