Ignore:
Timestamp:
21 Sep 2012, 08:19:35 (12 years ago)
Author:
uli
Message:

Rollback r9209. Looks like multiple merges from trunk confuse svn when merging back into trunk.

Location:
main/waeup.kofa/branches/uli-zc-async
Files:
1 deleted
29 edited
1 copied

Legend:

Unmodified
Added
Removed
  • main/waeup.kofa/branches/uli-zc-async

  • main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/students/authentication.py

    r9209 r9211  
    102102    def checkPassword(self, password):
    103103        """Check whether the given `password` matches the one stored.
    104 
    105         We additionally check if student account has been suspended.
    106104        """
    107105        if not isinstance(password, basestring):
     
    109107        if not getattr(self.context, 'password', None):
    110108            # unset/empty passwords do never match
    111             return False
    112         if self.context.suspended == True:
    113109            return False
    114110        passwordmanager = getUtility(IPasswordManager, 'SSHA')
  • main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/students/batching.py

    r9209 r9211  
    2626import grok
    2727import csv
    28 from time import time
    2928from zope.interface import Interface
    3029from zope.schema import getFields
     
    4342    IStudentOnlinePayment, IStudentVerdictUpdate)
    4443from waeup.kofa.students.workflow import  (
    45     IMPORTABLE_STATES, IMPORTABLE_TRANSITIONS,
    46     FORBIDDEN_POSTGRAD_TRANS, FORBIDDEN_POSTGRAD_STATES)
     44    IMPORTABLE_STATES, IMPORTABLE_TRANSITIONS)
    4745from waeup.kofa.utils.batching import BatchProcessor
    4846
     
    172170            if transition not in allowed_transitions:
    173171                return 'Transition not allowed.'
    174             if transition in FORBIDDEN_POSTGRAD_TRANS and \
    175                 obj.is_postgrad:
    176                 return 'Transition not allowed (pg student).'
    177         state = row.get('state', IGNORE_MARKER)
    178         if state not in (IGNORE_MARKER, ''):
    179             if state in FORBIDDEN_POSTGRAD_STATES and \
    180                 obj.is_postgrad:
    181                 return 'State not allowed (pg student).'
    182172        return None
    183173
     
    193183
    194184        # Update password
    195         # XXX: Tale DELETION_MARKER into consideration
    196185        if row.has_key('password'):
    197186            passwd = row.get('password', IGNORE_MARKER)
     
    233222        parent = self.getParent(row, site)
    234223        if hasattr(obj,'student_id'):
    235             # Update mode: the student exists and we can get the student_id.
    236             # Create mode: the record contains the student_id
     224            # Update mode: the student exists and we can get the student_id
    237225            parent.logger.info(
    238226                '%s - Student record updated: %s'
     
    271259        errs, inv_errs, conv_dict =  converter.fromStringDict(
    272260            row, self.factory_name, mode=mode)
    273         if row.has_key('transition'):
    274             if row['transition'] not in IMPORTABLE_TRANSITIONS:
    275                 if row['transition'] not in (IGNORE_MARKER, ''):
    276                     errs.append(('transition','not allowed'))
    277         if row.has_key('state'):
    278             if row['state'] not in IMPORTABLE_STATES:
    279                 if row['state'] not in (IGNORE_MARKER, ''):
    280                     errs.append(('state','not allowed'))
    281                 else:
    282                     # State is an attribute of Student and must not
    283                     # be changed if empty.
    284                     conv_dict['state'] = IGNORE_MARKER
     261        if row.has_key('transition') and \
     262            not row['transition'] in IMPORTABLE_TRANSITIONS:
     263            if row['transition'] not in (IGNORE_MARKER, ''):
     264                errs.append(('transition','not allowed'))
     265        if row.has_key('state') and \
     266            not row['state'] in IMPORTABLE_STATES:
     267            if row['state'] not in (IGNORE_MARKER, ''):
     268                errs.append(('state','not allowed'))
     269            else:
     270                # state is an attribute of Student and must not
     271                # be changed if empty
     272                conv_dict['state'] = IGNORE_MARKER
     273
    285274        try:
    286275            # Correct stud_id counter. As the IConverter for students
     
    302291    grok.baseclass()
    303292
    304     # additional available  fields
    305     # beside 'student_id', 'reg_number' and 'matric_number'
     293    #: required fields beside 'student_id', 'reg_number' and 'matric_number'
    306294    additional_fields = []
    307295
    308     #: header fields additionally required
     296    #: header fields additional required
    309297    additional_headers = []
    310298
     
    373361        return errs, inv_errs, conv_dict
    374362
    375     def getMapping(self, path, headerfields, mode):
    376         """Get a mapping from CSV file headerfields to actually used fieldnames.
    377         """
    378         result = dict()
    379         reader = csv.reader(open(path, 'rb'))
    380         raw_header = reader.next()
    381         for num, field in enumerate(headerfields):
    382             if field not in ['student_id', 'reg_number', 'matric_number',
    383                              'p_id', 'code', 'level'
    384                              ] and mode == 'remove':
    385                 continue
    386             if field == u'--IGNORE--':
    387                 # Skip ignored columns in failed and finished data files.
    388                 continue
    389             result[raw_header[num]] = field
    390         return result
    391 
    392363
    393364class StudentStudyCourseProcessor(StudentProcessorBase):
     
    435406            StudentStudyCourseProcessor, self).checkConversion(row, mode=mode)
    436407        # We have to check if current_level is in range of certificate.
    437         if conv_dict.has_key('certificate') and \
    438             conv_dict.has_key('current_level'):
    439             cert = conv_dict['certificate']
    440             level = conv_dict['current_level']
    441             if level < cert.start_level or level > cert.end_level+120:
    442                 errs.append(('current_level','not in range'))
     408        if conv_dict.has_key('certificate'):
     409          cert = conv_dict['certificate']
     410          if conv_dict['current_level'] < cert.start_level or \
     411              conv_dict['current_level'] > cert.end_level+120:
     412              errs.append(('current_level','not in range'))
    443413        return errs, inv_errs, conv_dict
    444 
    445     def checkUpdateRequirements(self, obj, row, site):
    446         """Checks requirements the object must fulfill when being updated.
    447 
    448         Returns error messages as strings in case of requirement
    449         problems.
    450         """
    451         current_level = row.get('current_level', None)
    452         if current_level == 999 and \
    453             obj.__parent__.state in FORBIDDEN_POSTGRAD_STATES:
    454             return 'Not a pg student.'
    455         return None
    456414
    457415class StudentStudyLevelProcessor(StudentProcessorBase):
     
    469427
    470428    location_fields = []
    471 
    472429    additional_fields = ['level']
    473430    additional_headers = ['level']
     
    552509        items_changed = super(CourseTicketProcessor, self).updateEntry(
    553510            obj, row, site)
    554         parent = self.getParent(row, site)
    555511        student = self.getParent(row, site).__parent__.__parent__
    556512        student.__parent__.logger.info(
    557             '%s - Course ticket in %s updated: %s'
    558             % (student.student_id,  parent.level, items_changed))
     513            '%s - Course ticket updated: %s'
     514            % (student.student_id, items_changed))
    559515        return
    560516
     
    572528        return
    573529
    574     def delEntry(self, row, site):
    575         ticket = self.getEntry(row, site)
    576         parent = self.getParent(row, site)
    577         if ticket is not None:
    578             student = self._getStudent(row, site)
    579             student.__parent__.logger.info('%s - Course ticket in %s removed: %s'
    580                 % (student.student_id, parent.level, ticket.code))
    581             del parent[ticket.code]
    582         return
    583 
    584530    def checkConversion(self, row, mode='ignore'):
    585531        """Validates all values in row.
     
    606552    grok.name(util_name)
    607553
    608     name = u'Student Payment Processor'
     554    name = u'Payment Processor'
    609555    iface = IStudentOnlinePayment
    610556    factory_name = 'waeup.StudentOnlinePayment'
     
    612558    location_fields = []
    613559    additional_fields = ['p_id']
    614     additional_headers = []
    615 
    616     def checkHeaders(self, headerfields, mode='ignore'):
    617         super(StudentOnlinePaymentProcessor, self).checkHeaders(headerfields)
    618         if mode in ('update', 'remove') and not 'p_id' in headerfields:
    619             raise FatalCSVError(
    620                 "Need p_id for import in update and remove modes!")
    621         return True
     560    additional_headers = ['p_id']
    622561
    623562    def parentsExist(self, row, site):
     
    634573        if payments is None:
    635574            return None
    636         p_id = row.get('p_id', None)
    637         if p_id is None:
    638             return None
    639575        # We can use the hash symbol at the end of p_id in import files
    640576        # to avoid annoying automatic number transformation
    641577        # by Excel or Calc
    642         p_id = p_id.strip('#')
    643         if not p_id.startswith('p'):
    644             # For data migration from old SRP only
    645             p_id = 'p' + p_id[7:] + '0'
    646         entry = payments.get(p_id)
     578        p_id = row['p_id'].strip('#')
     579        if p_id.startswith('p'):
     580            entry = payments.get(p_id)
     581        else:
     582            # For data migration from old SRP
     583            entry = payments.get('p' + p_id[6:])
    647584        return entry
    648585
     
    663600        if not p_id.startswith('p'):
    664601            # For data migration from old SRP
    665             obj.p_id = 'p' + p_id[7:] + '0'
     602            obj.p_id = 'p' + p_id[6:]
    666603            parent[obj.p_id] = obj
    667604        else:
     
    669606        return
    670607
    671     def delEntry(self, row, site):
    672         payment = self.getEntry(row, site)
    673         parent = self.getParent(row, site)
    674         if payment is not None:
    675             student = self._getStudent(row, site)
    676             student.__parent__.logger.info('%s - Payment ticket removed: %s'
    677                 % (student.student_id, payment.p_id))
    678             del parent[payment.p_id]
    679         return
    680 
    681608    def checkConversion(self, row, mode='ignore'):
    682609        """Validates all values in row.
     
    686613
    687614        # We have to check p_id.
    688         p_id = row.get('p_id', None)
    689         if not p_id:
    690             timestamp = ("%d" % int(time()*10000))[1:]
    691             p_id = "p%s" % timestamp
    692             conv_dict['p_id'] = p_id
    693             return errs, inv_errs, conv_dict
    694         else:
    695             p_id = p_id.strip('#')
     615        p_id = row['p_id'].strip('#')
    696616        if p_id.startswith('p'):
    697617            if not len(p_id) == 14:
  • main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/students/browser.py

    r9209 r9211  
    4343from waeup.kofa.interfaces import (
    4444    IKofaObject, IUserAccount, IExtFileStore, IPasswordValidator, IContactForm,
    45     IKofaUtils, IUniversity, IObjectHistory)
     45    IKofaUtils, IUniversity)
    4646from waeup.kofa.interfaces import MessageFactory as _
    4747from waeup.kofa.widgets.datewidget import (
     
    5353    IUGStudentClearance,IPGStudentClearance,
    5454    IStudentPersonal, IStudentBase, IStudentStudyCourse,
    55     IStudentStudyCourseTransfer,
    5655    IStudentAccommodation, IStudentStudyLevel,
    5756    ICourseTicket, ICourseTicketAdd, IStudentPaymentsContainer,
    58     IStudentOnlinePayment, IStudentPreviousPayment,
    59     IBedTicket, IStudentsUtils, IStudentRequestPW
     57    IStudentOnlinePayment, IBedTicket, IStudentsUtils, IStudentRequestPW
    6058    )
    6159from waeup.kofa.students.catalog import search
    6260from waeup.kofa.students.workflow import (CREATED, ADMITTED, PAID,
    63     CLEARANCE, REQUESTED, RETURNING, CLEARED, REGISTERED, VALIDATED,
    64     FORBIDDEN_POSTGRAD_TRANS)
     61    CLEARANCE, REQUESTED, RETURNING, CLEARED, REGISTERED, VALIDATED)
    6562from waeup.kofa.students.studylevel import StudentStudyLevel, CourseTicket
    6663from waeup.kofa.students.vocabularies import StudyLevelSource
     
    6865from waeup.kofa.hostels.hostel import NOT_OCCUPIED
    6966from waeup.kofa.utils.helpers import get_current_principal, to_timezone
    70 from waeup.kofa.mandates.mandate import PasswordMandate
    7167
    7268grok.context(IKofaObject) # Make IKofaObject the default context
     
    9591    return
    9692
    97 def translated_values(view):
    98     lang = view.request.cookies.get('kofa.language')
    99     for value in view.context.values():
    100         value_dict = dict([i for i in value.__dict__.items()])
    101         value_dict['mandatory_bool'] = value.mandatory
    102         value_dict['mandatory'] = translate(str(value.mandatory), 'zope',
    103             target_language=lang)
    104         value_dict['carry_over'] = translate(str(value.carry_over), 'zope',
    105             target_language=lang)
    106         value_dict['automatic'] = translate(str(value.automatic), 'zope',
    107             target_language=lang)
    108         yield value_dict
    109 
    11093class StudentsBreadcrumb(Breadcrumb):
    11194    """A breadcrumb for the students container.
     
    133116    """
    134117    grok.context(IStudentStudyCourse)
    135 
    136     def title(self):
    137         if self.context.is_current:
    138             return _('Study Course')
    139         else:
    140             return _('Previous Study Course')
     118    title = _('Study Course')
    141119
    142120class PaymentsBreadcrumb(Breadcrumb):
     
    301279    grok.require('waeup.viewStudent')
    302280    grok.template('basepage')
    303     form_fields = grok.AutoFields(IStudentBase).omit('password', 'suspended')
     281    form_fields = grok.AutoFields(IStudentBase).omit('password')
    304282    pnav = 4
    305283
    306284    @property
    307285    def label(self):
    308         if self.context.suspended:
    309             return _('${a}: Base Data (account deactivated)',
    310                 mapping = {'a':self.context.display_fullname})
    311         return  _('${a}: Base Data',
     286        return _('${a}: Base Data',
    312287            mapping = {'a':self.context.display_fullname})
    313288
     
    317292            return _('set')
    318293        return _('unset')
    319 
    320 class StudentBasePDFFormPage(KofaDisplayFormPage):
    321     """ Page to display student base data in pdf files.
    322     """
    323     form_fields = grok.AutoFields(IStudentBase).omit(
    324         'password', 'suspended', 'phone', 'adm_code', 'sex')
    325294
    326295class ContactStudentForm(ContactAdminForm):
     
    361330        return
    362331
    363 class ExportPDFAdmissionSlipPage(UtilityView, grok.View):
    364     """Deliver a PDF Admission slip.
    365     """
    366     grok.context(IStudent)
    367     grok.name('admission_slip.pdf')
    368     grok.require('waeup.viewStudent')
    369     prefix = 'form'
    370 
    371     form_fields = grok.AutoFields(IStudentBase).select('student_id', 'reg_number')
    372 
    373     @property
    374     def label(self):
    375         portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
    376         return translate(_('Admission Letter of'),
    377             'waeup.kofa', target_language=portal_language) \
    378             + ' %s' % self.context.display_fullname
    379 
    380     def render(self):
    381         students_utils = getUtility(IStudentsUtils)
    382         return students_utils.renderPDFAdmissionLetter(self,
    383             self.context.student)
    384 
    385332class StudentBaseManageFormPage(KofaEditFormPage):
    386333    """ View to manage student base data
     
    389336    grok.name('manage_base')
    390337    grok.require('waeup.manageStudent')
    391     form_fields = grok.AutoFields(IStudentBase).omit(
    392         'student_id', 'adm_code', 'suspended')
     338    form_fields = grok.AutoFields(IStudentBase).omit('student_id')
    393339    grok.template('basemanagepage')
    394340    label = _('Manage base data')
     
    416362        allowed_transitions = [t for t in self.wf_info.getManualTransitions()
    417363            if not t[0].startswith('pay')]
    418         if self.context.is_postgrad:
    419             allowed_transitions = [t for t in allowed_transitions
    420                 if not t[0] in FORBIDDEN_POSTGRAD_TRANS]
    421364        return [dict(name='', title=_('No transition'))] +[
    422365            dict(name=x, title=y) for x, y in allowed_transitions]
     
    453396        return
    454397
    455 class StudentActivatePage(UtilityView, grok.View):
    456     """ Activate student account
    457     """
    458     grok.context(IStudent)
    459     grok.name('activate')
    460     grok.require('waeup.manageStudent')
    461 
    462     def update(self):
    463         self.context.suspended = False
    464         self.context.writeLogMessage(self, 'account activated')
    465         history = IObjectHistory(self.context)
    466         history.addMessage('Student account activated')
    467         self.flash(_('Student account has been activated.'))
    468         self.redirect(self.url(self.context))
    469         return
    470 
    471     def render(self):
    472         return
    473 
    474 class StudentDeactivatePage(UtilityView, grok.View):
    475     """ Deactivate student account
    476     """
    477     grok.context(IStudent)
    478     grok.name('deactivate')
    479     grok.require('waeup.manageStudent')
    480 
    481     def update(self):
    482         self.context.suspended = True
    483         self.context.writeLogMessage(self, 'account deactivated')
    484         history = IObjectHistory(self.context)
    485         history.addMessage('Student account deactivated')
    486         self.flash(_('Student account has been deactivated.'))
    487         self.redirect(self.url(self.context))
    488         return
    489 
    490     def render(self):
    491         return
    492 
    493398class StudentClearanceDisplayFormPage(KofaDisplayFormPage):
    494399    """ Page to display student clearance data
     
    506411    def form_fields(self):
    507412        if self.context.is_postgrad:
    508             form_fields = grok.AutoFields(
    509                 IPGStudentClearance).omit('clearance_locked')
    510         else:
    511             form_fields = grok.AutoFields(
    512                 IUGStudentClearance).omit('clearance_locked')
     413            form_fields = grok.AutoFields(IPGStudentClearance).omit('clearance_locked')
     414        else:
     415            form_fields = grok.AutoFields(IUGStudentClearance).omit('clearance_locked')
    513416        return form_fields
    514417
     
    529432    def form_fields(self):
    530433        if self.context.is_postgrad:
    531             form_fields = grok.AutoFields(
    532                 IPGStudentClearance).omit('clearance_locked')
    533         else:
    534             form_fields = grok.AutoFields(
    535                 IUGStudentClearance).omit('clearance_locked')
     434            form_fields = grok.AutoFields(IPGStudentClearance).omit('clearance_locked')
     435        else:
     436            form_fields = grok.AutoFields(IUGStudentClearance).omit('clearance_locked')
    536437        return form_fields
    537438
     
    545446    def label(self):
    546447        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
    547         return translate(_('Clearance Slip of'),
     448        return translate(_('Clearance Slip of '),
    548449            'waeup.kofa', target_language=portal_language) \
    549450            + ' %s' % self.context.display_fullname
    550451
    551     def _signatures(self):
    552         if self.context.state == CLEARED:
    553             return (_('Student Signature'), _('Clearance Officer Signature'))
    554         return
    555 
    556452    def render(self):
    557         studentview = StudentBasePDFFormPage(self.context.student,
     453        studentview = StudentBaseDisplayFormPage(self.context.student,
    558454            self.request)
    559455        students_utils = getUtility(IStudentsUtils)
    560456        return students_utils.renderPDF(
    561457            self, 'clearance.pdf',
    562             self.context.student, studentview, signatures=self._signatures())
     458            self.context.student, studentview)
    563459
    564460class StudentClearanceManageFormPage(KofaEditFormPage):
     
    579475    def form_fields(self):
    580476        if self.context.is_postgrad:
    581             form_fields = grok.AutoFields(IPGStudentClearance).omit('clr_code')
    582         else:
    583             form_fields = grok.AutoFields(IUGStudentClearance).omit('clr_code')
     477            form_fields = grok.AutoFields(IPGStudentClearance)
     478        else:
     479            form_fields = grok.AutoFields(IUGStudentClearance)
    584480        return form_fields
    585481
     
    661557            mapping = {'a':self.context.display_fullname})
    662558
    663 class StudentPersonalManageFormPage(KofaEditFormPage):
    664     """ Page to manage personal data
     559class StudentPersonalEditFormPage(KofaEditFormPage):
     560    """ Page to edit personal data
    665561    """
    666562    grok.context(IStudent)
    667     grok.name('manage_personal')
    668     grok.require('waeup.manageStudent')
     563    grok.name('edit_personal')
     564    grok.require('waeup.handleStudent')
    669565    form_fields = grok.AutoFields(IStudentPersonal)
    670     label = _('Manage personal data')
     566    label = _('Edit personal data')
    671567    pnav = 4
    672568
     
    676572        return
    677573
    678 class StudentPersonalEditFormPage(StudentPersonalManageFormPage):
    679     """ Page to edit personal data
    680     """
    681     grok.name('edit_personal')
    682     grok.require('waeup.handleStudent')
    683     label = _('Edit personal data')
    684     pnav = 4
    685 
    686574class StudyCourseDisplayFormPage(KofaDisplayFormPage):
    687575    """ Page to display the student study course data
     
    690578    grok.name('index')
    691579    grok.require('waeup.viewStudent')
     580    form_fields = grok.AutoFields(IStudentStudyCourse)
    692581    grok.template('studycoursepage')
    693582    pnav = 4
    694583
    695584    @property
    696     def form_fields(self):
    697         if self.context.is_postgrad:
    698             form_fields = grok.AutoFields(IStudentStudyCourse).omit(
    699                 'current_verdict', 'previous_verdict')
    700         else:
    701             form_fields = grok.AutoFields(IStudentStudyCourse)
    702         return form_fields
    703 
    704     @property
    705585    def label(self):
    706         if self.context.is_current:
    707             return _('${a}: Study Course',
    708                 mapping = {'a':self.context.__parent__.display_fullname})
    709         else:
    710             return _('${a}: Previous Study Course',
    711                 mapping = {'a':self.context.__parent__.display_fullname})
     586        return _('${a}: Study Course',
     587            mapping = {'a':self.context.__parent__.display_fullname})
    712588
    713589    @property
     
    730606        return
    731607
    732     @property
    733     def prev_studycourses(self):
    734         if self.context.is_current:
    735             if self.context.__parent__.get('studycourse_2', None) is not None:
    736                 return (
    737                         {'href':self.url(self.context.student) + '/studycourse_1',
    738                         'title':_('First Study Course, ')},
    739                         {'href':self.url(self.context.student) + '/studycourse_2',
    740                         'title':_('Second Study Course')}
    741                         )
    742             if self.context.__parent__.get('studycourse_1', None) is not None:
    743                 return (
    744                         {'href':self.url(self.context.student) + '/studycourse_1',
    745                         'title':_('First Study Course')},
    746                         )
    747         return
    748 
    749608class StudyCourseManageFormPage(KofaEditFormPage):
    750609    """ Page to edit the student study course data
     
    754613    grok.require('waeup.manageStudent')
    755614    grok.template('studycoursemanagepage')
     615    form_fields = grok.AutoFields(IStudentStudyCourse)
    756616    label = _('Manage study course')
    757617    pnav = 4
     
    760620    tabthreeactions = [_('Add study level')]
    761621
    762     @property
    763     def form_fields(self):
    764         if self.context.is_postgrad:
    765             form_fields = grok.AutoFields(IStudentStudyCourse).omit(
    766                 'current_verdict', 'previous_verdict')
    767         else:
    768             form_fields = grok.AutoFields(IStudentStudyCourse)
    769         return form_fields
    770 
    771622    def update(self):
    772         if not self.context.is_current:
    773             emit_lock_message(self)
    774             return
    775623        super(StudyCourseManageFormPage, self).update()
    776624        tabs.need()
     
    837685        return
    838686
    839 class StudentTransferFormPage(KofaAddFormPage):
    840     """Page to transfer the student.
    841     """
    842     grok.context(IStudent)
    843     grok.name('transfer')
    844     grok.require('waeup.manageStudent')
    845     label = _('Transfer student')
    846     form_fields = grok.AutoFields(IStudentStudyCourseTransfer).omit(
    847         'entry_mode', 'entry_session')
    848     pnav = 4
    849 
    850     def update(self):
    851         super(StudentTransferFormPage, self).update()
    852         warning.need()
    853         return
    854 
    855     @jsaction(_('Transfer'))
    856     def transferStudent(self, **data):
    857         error = self.context.transfer(**data)
    858         if error == -1:
    859             self.flash(_('Current level does not match certificate levels.'))
    860         elif error == -2:
    861             self.flash(_('Former study course record incomplete.'))
    862         elif error == -3:
    863             self.flash(_('Maximum number of transfers exceeded.'))
    864         else:
    865             self.flash(_('Successfully transferred.'))
    866         return
    867 
    868687class StudyLevelDisplayFormPage(KofaDisplayFormPage):
    869688    """ Page to display student study levels
     
    873692    grok.require('waeup.viewStudent')
    874693    form_fields = grok.AutoFields(IStudentStudyLevel)
    875     form_fields[
    876         'validation_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
    877694    grok.template('studylevelpage')
    878695    pnav = 4
     
    885702    @property
    886703    def translated_values(self):
    887         return translated_values(self)
     704        lang = self.request.cookies.get('kofa.language')
     705        for value in self.context.values():
     706            value_dict = dict([i for i in value.__dict__.items()])
     707            value_dict['mandatory'] = translate(str(value.mandatory), 'zope',
     708                target_language=lang)
     709            value_dict['carry_over'] = translate(str(value.carry_over), 'zope',
     710                target_language=lang)
     711            value_dict['automatic'] = translate(str(value.automatic), 'zope',
     712                target_language=lang)
     713            yield value_dict
    888714
    889715    @property
     
    945771        Mand = translate(_('Mand.'), 'waeup.kofa', target_language=portal_language)
    946772        Score = translate(_('Score'), 'waeup.kofa', target_language=portal_language)
    947         studentview = StudentBasePDFFormPage(self.context.student,
     773        studentview = StudentBaseDisplayFormPage(self.context.student,
    948774            self.request)
    949775        students_utils = getUtility(IStudentsUtils)
     
    970796    grok.require('waeup.manageStudent')
    971797    grok.template('studylevelmanagepage')
    972     form_fields = grok.AutoFields(IStudentStudyLevel).omit(
    973         'validation_date', 'validated_by')
     798    form_fields = grok.AutoFields(IStudentStudyLevel)
    974799    pnav = 4
    975800    taboneactions = [_('Save'),_('Cancel')]
     
    978803
    979804    def update(self):
    980         if not self.context.__parent__.is_current:
    981             emit_lock_message(self)
    982             return
    983805        super(StudyLevelManageFormPage, self).update()
    984806        tabs.need()
     
    991813        datatable.need()
    992814        return
    993 
    994     @property
    995     def translated_values(self):
    996         return translated_values(self)
    997815
    998816    @property
     
    1043861
    1044862    def update(self):
    1045         if not self.context.__parent__.is_current:
    1046             emit_lock_message(self)
    1047             return
    1048863        if str(self.context.__parent__.current_level) != self.context.__name__:
    1049864            self.flash(_('This level does not correspond current level.'))
     
    1068883
    1069884    def update(self):
    1070         if not self.context.__parent__.is_current:
    1071             emit_lock_message(self)
    1072             return
    1073885        if str(self.context.__parent__.current_level) != self.context.__name__:
    1074886            self.flash(_('This level does not correspond current level.'))
     
    1106918    pnav = 4
    1107919
    1108     def update(self):
    1109         if not self.context.__parent__.is_current:
    1110             emit_lock_message(self)
    1111             return
    1112         super(CourseTicketAddFormPage, self).update()
    1113         return
    1114 
    1115920    @action(_('Add course ticket'))
    1116921    def addCourseTicket(self, **data):
     
    1119924        ticket.automatic = False
    1120925        ticket.carry_over = False
     926        ticket.code = course.code
     927        ticket.title = course.title
     928        ticket.fcode = course.__parent__.__parent__.__parent__.code
     929        ticket.dcode = course.__parent__.__parent__.code
     930        ticket.credits = course.credits
     931        ticket.passmark = course.passmark
     932        ticket.semester = course.semester
    1121933        try:
    1122             self.context.addCourseTicket(ticket, course)
     934            self.context.addCourseTicket(ticket)
    1123935        except KeyError:
    1124936            self.flash(_('The ticket exists.'))
     
    12181030                mapping = {'a': ', '.join(deleted)}))
    12191031            self.context.writeLogMessage(
    1220                 self,'removed: %s' % ', '.join(deleted))
     1032                self,'removed: % s' % ', '.join(deleted))
    12211033        self.redirect(self.url(self.context))
    12221034        return
     
    12401052    def createTicket(self, **data):
    12411053        p_category = data['p_category']
    1242         previous_session = data.get('p_session', None)
    1243         previous_level = data.get('p_level', None)
    12441054        student = self.context.__parent__
    12451055        if p_category == 'bed_allocation' and student[
     
    12521062                return
    12531063        students_utils = getUtility(IStudentsUtils)
    1254         error, payment = students_utils.setPaymentDetails(
    1255             p_category, student, previous_session, previous_level)
     1064        error, payment = students_utils.setPaymentDetails(p_category, student)
    12561065        if error is not None:
    12571066            self.flash(error)
    1258             if 'previous session' in error:
    1259                 self.redirect(self.url(self.context) + '/@@addpp')
    1260                 return
    12611067            self.redirect(self.url(self.context))
    12621068            return
     
    12651071        self.redirect(self.url(self.context))
    12661072        return
    1267 
    1268 class PreviousPaymentAddFormPage(OnlinePaymentAddFormPage):
    1269     """ Page to add an online payment ticket for previous sessions
    1270     """
    1271     grok.context(IStudentPaymentsContainer)
    1272     grok.name('addpp')
    1273     grok.require('waeup.payStudent')
    1274     form_fields = grok.AutoFields(IStudentPreviousPayment).select(
    1275         'p_category', 'p_session', 'p_level')
    1276     label = _('Add previous session online payment')
    1277     pnav = 4
    12781073
    12791074class OnlinePaymentDisplayFormPage(KofaDisplayFormPage):
     
    13541149        #    self.redirect(self.url(self.context))
    13551150        #    return
    1356         studentview = StudentBasePDFFormPage(self.context.student,
     1151        studentview = StudentBaseDisplayFormPage(self.context.student,
    13571152            self.request)
    13581153        students_utils = getUtility(IStudentsUtils)
     
    14311226    buttonname = _('Create bed ticket')
    14321227    notice = ''
    1433     with_ac = True
    14341228
    14351229    def update(self, SUBMIT=None):
     
    14721266            self.redirect(self.url(self.context))
    14731267            return
    1474         if self.with_ac:
    1475             self.ac_series = self.request.form.get('ac_series', None)
    1476             self.ac_number = self.request.form.get('ac_number', None)
     1268        self.ac_series = self.request.form.get('ac_series', None)
     1269        self.ac_number = self.request.form.get('ac_number', None)
    14771270        if SUBMIT is None:
    14781271            return
    1479         if self.with_ac:
    1480             pin = '%s-%s-%s' % (self.ac_prefix, self.ac_series, self.ac_number)
    1481             code = get_access_code(pin)
    1482             if not code:
    1483                 self.flash(_('Activation code is invalid.'))
    1484                 return
     1272        pin = '%s-%s-%s' % (self.ac_prefix, self.ac_series, self.ac_number)
     1273        code = get_access_code(pin)
     1274        if not code:
     1275            self.flash(_('Activation code is invalid.'))
     1276            return
    14851277        # Search and book bed
    14861278        cat = queryUtility(ICatalog, name='beds_catalog', default=None)
     
    14881280            owner=(student.student_id,student.student_id))
    14891281        if len(entries):
    1490             # If bed space has been manually allocated use this bed
     1282            # If bed space has bee manually allocated use this bed
    14911283            bed = [entry for entry in entries][0]
    14921284        else:
     
    15041296                    mapping = {'a':acc_details['bt']}))
    15051297                return
    1506         if self.with_ac:
    1507             # Mark pin as used (this also fires a pin related transition)
    1508             if code.state == USED:
    1509                 self.flash(_('Activation code has already been used.'))
     1298        # Mark pin as used (this also fires a pin related transition)
     1299        if code.state == USED:
     1300            self.flash(_('Activation code has already been used.'))
     1301            return
     1302        else:
     1303            comment = _(u'invalidated')
     1304            # Here we know that the ac is in state initialized so we do not
     1305            # expect an exception, but the owner might be different
     1306            if not invalidate_accesscode(
     1307                pin,comment,self.context.student.student_id):
     1308                self.flash(_('You are not the owner of this access code.'))
    15101309                return
    1511             else:
    1512                 comment = _(u'invalidated')
    1513                 # Here we know that the ac is in state initialized so we do not
    1514                 # expect an exception, but the owner might be different
    1515                 if not invalidate_accesscode(
    1516                     pin,comment,self.context.student.student_id):
    1517                     self.flash(_('You are not the owner of this access code.'))
    1518                     return
    15191310        # Create bed ticket
    15201311        bedticket = createObject(u'waeup.BedTicket')
    1521         if self.with_ac:
    1522             bedticket.booking_code = pin
     1312        bedticket.booking_code = pin
    15231313        bedticket.booking_session = acc_details['booking_session']
    15241314        bedticket.bed_type = acc_details['bt']
    15251315        bedticket.bed = bed
    15261316        hall_title = bed.__parent__.hostel_name
    1527         coordinates = bed.coordinates[1:]
     1317        coordinates = bed.getBedCoordinates()[1:]
    15281318        block, room_nr, bed_nr = coordinates
    15291319        bc = _('${a}, Block ${b}, Room ${c}, Bed ${d} (${e})', mapping = {
     
    15481338    grok.require('waeup.handleAccommodation')
    15491339    form_fields = grok.AutoFields(IBedTicket)
    1550     form_fields['booking_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')
    15511340    pnav = 4
    15521341
     
    15751364    def label(self):
    15761365        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
    1577         #return translate(_('Bed Allocation: '),
    1578         #    'waeup.kofa', target_language=portal_language) \
    1579         #    + ' %s' % self.context.bed_coordinates
    1580         return translate(_('Bed Allocation Slip'),
     1366        return translate(_('Bed Allocation: '),
    15811367            'waeup.kofa', target_language=portal_language) \
    1582             + ' %s' % self.context.getSessionString()
     1368            + ' %s' % self.context.bed_coordinates
    15831369
    15841370    def render(self):
    1585         studentview = StudentBasePDFFormPage(self.context.student,
     1371        studentview = StudentBaseDisplayFormPage(self.context.student,
    15861372            self.request)
    15871373        students_utils = getUtility(IStudentsUtils)
     
    16451431        self.context.bed = new_bed
    16461432        hall_title = new_bed.__parent__.hostel_name
    1647         coordinates = new_bed.coordinates[1:]
     1433        coordinates = new_bed.getBedCoordinates()[1:]
    16481434        block, room_nr, bed_nr = coordinates
    16491435        bc = _('${a}, Block ${b}, Room ${c}, Bed ${d} (${e})', mapping = {
     
    17831569            self.flash(_('Activation code is invalid.'))
    17841570            return
     1571        # Mark pin as used (this also fires a pin related transition)
     1572        # and fire transition start_clearance
    17851573        if code.state == USED:
    17861574            self.flash(_('Activation code has already been used.'))
    17871575            return
    1788         # Mark pin as used (this also fires a pin related transition)
    1789         # and fire transition start_clearance
    1790         comment = _(u"invalidated")
    1791         # Here we know that the ac is in state initialized so we do not
    1792         # expect an exception, but the owner might be different
    1793         if not invalidate_accesscode(pin, comment, self.context.student_id):
    1794             self.flash(_('You are not the owner of this access code.'))
    1795             return
    1796         self.context.clr_code = pin
     1576        else:
     1577            comment = _(u"invalidated")
     1578            # Here we know that the ac is in state initialized so we do not
     1579            # expect an exception, but the owner might be different
     1580            if not invalidate_accesscode(pin,comment,self.context.student_id):
     1581                self.flash(_('You are not the owner of this access code.'))
     1582                return
     1583            self.context.clr_code = pin
    17971584        IWorkflowInfo(self.context).fireTransition('start_clearance')
    17981585        self.flash(_('Clearance process has been started.'))
     
    18111598    def form_fields(self):
    18121599        if self.context.is_postgrad:
    1813             form_fields = grok.AutoFields(IPGStudentClearance).omit(
    1814                 'clearance_locked', 'clr_code')
    1815         else:
    1816             form_fields = grok.AutoFields(IUGStudentClearance).omit(
    1817                 'clearance_locked', 'clr_code')
     1600            form_fields = grok.AutoFields(IPGStudentClearance).omit('clearance_locked')
     1601        else:
     1602            form_fields = grok.AutoFields(IUGStudentClearance).omit('clearance_locked')
    18181603        return form_fields
    18191604
     
    18421627            return
    18431628        self.flash(_('Clearance form has been saved.'))
    1844         if self.context.clr_code:
    1845             self.redirect(self.url(self.context, 'request_clearance'))
    1846         else:
    1847             # We bypass the request_clearance page if student
    1848             # has been imported in state 'clearance started' and
    1849             # no clr_code was entered before.
    1850             state = IWorkflowState(self.context).getState()
    1851             if state != CLEARANCE:
    1852                 # This shouldn't happen, but the application officer
    1853                 # might have forgotten to lock the form after changing the state
    1854                 self.flash(_('This form cannot be submitted. Wrong state!'))
    1855                 return
    1856             IWorkflowInfo(self.context).fireTransition('request_clearance')
    1857             self.flash(_('Clearance has been requested.'))
    1858             self.redirect(self.url(self.context))
     1629        self.redirect(self.url(self.context,'request_clearance'))
    18591630        return
    18601631
     
    18761647            return
    18771648        pin = '%s-%s-%s' % (self.ac_prefix, self.ac_series, self.ac_number)
    1878         if self.context.clr_code and self.context.clr_code != pin:
     1649        if self.context.clr_code != pin:
    18791650            self.flash(_("This isn't your CLR access code."))
    18801651            return
    18811652        state = IWorkflowState(self.context).getState()
     1653        # This shouldn't happen, but the application officer
     1654        # might have forgotten to lock the form after changing the state
    18821655        if state != CLEARANCE:
    1883             # This shouldn't happen, but the application officer
    1884             # might have forgotten to lock the form after changing the state
    18851656            self.flash(_('This form cannot be submitted. Wrong state!'))
    18861657            return
     
    19021673
    19031674    def update(self, SUBMIT=None):
    1904         if not self.context.is_current:
    1905             emit_lock_message(self)
    1906             return
    1907         super(StartSessionPage, self).update()
    19081675        if not self.context.next_session_allowed:
    19091676            self.flash(_("You are not entitled to start session."))
     
    19631730
    19641731    def update(self):
    1965         if not self.context.is_current:
    1966             emit_lock_message(self)
    1967             return
    19681732        if self.context.student.state != PAID:
    19691733            emit_lock_message(self)
     
    19981762
    19991763    def update(self):
    2000         if not self.context.__parent__.is_current:
    2001             emit_lock_message(self)
    2002             return
    20031764        if self.context.student.state != PAID:
    20041765            emit_lock_message(self)
     
    20151776        level_title = translate(self.context.level_title, 'waeup.kofa',
    20161777            target_language=lang)
    2017         return _('Edit course list of ${a}',
     1778        return _('Add and remove course tickets of study level ${a}',
    20181779            mapping = {'a':level_title})
    20191780
     
    20241785            total_credits += val.credits
    20251786        return total_credits
    2026 
    2027     @property
    2028     def translated_values(self):
    2029         return translated_values(self)
    20301787
    20311788    @action(_('Add course ticket'))
     
    20901847        ticket = createObject(u'waeup.CourseTicket')
    20911848        course = data['course']
     1849        for name in ['code', 'title', 'credits', 'passmark', 'semester']:
     1850            setattr(ticket, name, getattr(course, name))
    20921851        ticket.automatic = False
    2093         ticket.carry_over = False
    20941852        try:
    2095             self.context.addCourseTicket(ticket, course)
     1853            self.context.addCourseTicket(ticket)
    20961854        except KeyError:
    20971855            self.flash(_('The ticket exists.'))
     
    21691927    grok.template('requestpw')
    21701928    form_fields = grok.AutoFields(IStudentRequestPW).select(
    2171         'firstname','number','email')
     1929        'firstname','reg_number','email')
    21721930    label = _('Request password for first-time login')
    21731931
     
    21901948        return True
    21911949
    2192     @action(_('Send login credentials to email address'), style='primary')
     1950    @action(_('Get login credentials'), style='primary')
    21931951    def get_credentials(self, **data):
    21941952        if not self.captcha_result.is_valid:
     
    21961954            # No need to flash something.
    21971955            return
    2198         number = data.get('number','')
     1956        reg_number = data.get('reg_number','')
    21991957        firstname = data.get('firstname','')
    22001958        cat = getUtility(ICatalog, name='students_catalog')
    22011959        results = list(
    2202             cat.searchResults(reg_number=(number, number)))
    2203         if not results:
    2204             results = list(
    2205                 cat.searchResults(matric_number=(number, number)))
     1960            cat.searchResults(reg_number=(reg_number, reg_number)))
    22061961        if results:
    22071962            student = results[0]
     
    22291984        kofa_utils = getUtility(IKofaUtils)
    22301985        password = kofa_utils.genPassword()
    2231         mandate = PasswordMandate()
    2232         mandate.params['password'] = password
    2233         mandate.params['user'] = student
    2234         site = grok.getSite()
    2235         site['mandates'].addMandate(mandate)
     1986        IUserAccount(student).setPassword(password)
    22361987        # Send email with credentials
    2237         args = {'mandate_id':mandate.mandate_id}
    2238         mandate_url = self.url(site) + '/mandate?%s' % urlencode(args)
    2239         url_info = u'Confirmation link: %s' % mandate_url
     1988        login_url = self.url(grok.getSite(), 'login')
    22401989        msg = _('You have successfully requested a password for the')
    22411990        if kofa_utils.sendCredentials(IUserAccount(student),
    2242             password, url_info, msg):
     1991            password, login_url, msg):
    22431992            email_sent = student.email
    22441993        else:
     
    22461995        self._redirect(email=email_sent, password=password,
    22471996            student_id=student.student_id)
    2248         ob_class = self.__implemented__.__name__.replace('waeup.kofa.','')
    2249         self.context.logger.info(
    2250             '%s - %s (%s) - %s' % (ob_class, number, student.student_id, email_sent))
    22511997        return
    22521998
  • main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/students/browser_templates/basepage.pt

    r9209 r9211  
    1818          <tal:password replace="view/hasPassword" />
    1919      </td>
    20     </tr>
     20    <tr>
    2121    <tal:files content="structure provider:files" />
    2222  </tbody>
  • main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/students/browser_templates/requestpw.pt

    r9209 r9211  
    1717  </table>
    1818  <p i18n:translate="">
    19     Your student record will be looked up and
    20     your login credentials will be sent to the email address given above.
    21     To be able to proceed you must provide a valid email address!
     19    Your student record will be looked up and an email with your login
     20    credentials will be sent to the address provided.
    2221  </p>
    2322  <div tal:condition="view/availableActions">
  • main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/students/browser_templates/requestpwmailsent.pt

    r9209 r9211  
    2929    <tr>
    3030  </table>
    31   <p>
    32     <span i18n:translate="">Print this page and proceed to the</span>
     31  <p i18n:translate="">
     32    Print this page and proceed to the
    3333    <a tal:attributes="href python: view.url(layout.site, 'login')">login form</a>.
    34     <span i18n:translate="">Please note that passwords are case-sensitive,
     34    Please note that passwords are case-sensitive,
    3535    <br />when entering your credentials, and keep your password secret!
    36     </span>
    3736  </p>
    3837  <p tal:condition = "view/email">
  • main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/students/browser_templates/studycoursepage.pt

    r9209 r9211  
    4747        </td>
    4848      </tr>
    49       <tr tal:condition="view/prev_studycourses">
    50         <td i18n:translate="">
    51             Previous Study Courses:
    52         </td>
    53         <td>
    54           <span tal:repeat="value view/prev_studycourses">
    55             <a tal:attributes="href value/href" tal:content="value/title">
    56               FACULTY
    57             </a>
    58           </span>
    59         </td>
    60       </tr>
    6149  </tbody>
    6250</table>
  • main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/students/browser_templates/studyleveleditpage.pt

    r9209 r9211  
    2222  </thead>
    2323  <tbody>
    24     <tr tal:repeat="value view/translated_values" class="gradeC">
     24    <tr tal:repeat="value context/values" class="gradeC">
    2525       <td>
    2626        <input type="checkbox" name="val_id"
    2727                  tal:attributes="value value/__name__"
    28         tal:condition="not: value/mandatory_bool" />
     28        tal:condition="not: value/mandatory" />
    2929      </td>
    3030      <td tal:content="value/semester">SEMESTER</td>
     
    3636      <td tal:content="value/fcode">FACULTY</td>
    3737      <td tal:content="value/credits">CREDITS</td>
    38       <td tal:content="value/score|nothing">SCORE</td>
     38      <td tal:content="value/score">SCORE</td>
    3939      <td tal:content="value/carry_over">CO</td>
    4040    </tr>
  • main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/students/browser_templates/studylevelmanagepage.pt

    r9209 r9211  
    4646      </thead>
    4747      <tbody>
    48         <tr tal:repeat="value view/translated_values" class="gradeC">
     48        <tr tal:repeat="value context/values" class="gradeC">
    4949          <td>
    5050            <input type="checkbox" name="val_id"
     
    6060          <td tal:content="value/credits">CREDITS</td>
    6161          <td tal:content="value/mandatory">MANDATORY</td>
    62           <td tal:content="value/score|nothing">SCORE</td>
     62          <td tal:content="value/score">SCORE</td>
    6363          <td tal:content="value/carry_over">CO</td>
    6464          <td tal:content="value/automatic">AUTO</td>
  • main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/students/browser_templates/studylevelpage.pt

    r9209 r9211  
    3434      <th i18n:translate="">Code</th>
    3535      <th i18n:translate="">Title</th>
    36       <th i18n:translate="">Dep.</th>
    37       <th i18n:translate="">Fac.</th>
     36      <th i18n:translate="">Dept.</th>
     37      <th i18n:translate="">Fact.</th>
    3838      <th i18n:translate="">Cred.</th>
    3939      <th i18n:translate="">Mand.</th>
  • main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/students/dynamicroles.py

    r9209 r9211  
    5151        """Get roles for principal with id `principal_id`.
    5252
    53         See waeup.kofa.applicants.dynamicroles.ApplicantPrincipalRoleManager
    54         for further information.
     53        Different to the default implementation, this method also
     54        takes into account local roles set on any department connected
     55        to the context student.
     56
     57        If the given principal has at least one of the
     58        `external_rolenames` roles granted for the external object, it
     59        additionally gets `additional_rolename` role for the context
     60        student.
     61
     62        For the additional roles the `extra_attrib` and all its parent
     63        objects are looked up, because 'role inheritance' does not
     64        work on that basic level of permission handling.
     65
     66        Some advantages of this approach:
     67
     68        - we don't have to store extra local roles for clearance
     69          officers in ZODB for each student
     70
     71        - when local roles on a department change, we don't have to
     72          update thousands of students; the local role is assigned
     73          dynamically.
     74
     75        Disadvantage:
     76
     77        - More expensive role lookups when a clearance officer wants
     78          to see an student form.
     79
     80        This implementation is designed to be usable also for other
     81        contexts than students. You can inherit from it and set
     82        different role names to lookup/set easily via the static class
     83        attributes.
    5584        """
    5685        apr_manager = AnnotationPrincipalRoleManager(self._context)
     
    89118                        result.append(
    90119                            ('waeup.StudentsOfficer', setting))
    91                 elif 'UGClearanceOfficer' in role_id:
    92                     if not self._context.is_postgrad:
    93                         result.append(
    94                             ('waeup.StudentsClearanceOfficer', setting))
    95                     else:
    96                         # Otherwise grant at least view permissions.
    97                         result.append(
    98                             ('waeup.StudentsOfficer', setting))
    99                 elif 'PGClearanceOfficer' in role_id:
    100                     if self._context.is_postgrad:
    101                         result.append(
    102                             ('waeup.StudentsClearanceOfficer', setting))
    103                     else:
    104                         # Otherwise grant at least view permissions.
    105                         result.append(
    106                             ('waeup.StudentsOfficer', setting))
    107120                elif role_id in self.rolename_mapping.keys():
    108121                    # Grant additional role
  • main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/students/export.py

    r9209 r9211  
    113113        if name == 'history':
    114114            value = value.messages
    115         if name == 'phone' and value is not None:
    116             # Append hash '#' to phone numbers to circumvent
    117             # unwanted excel automatic
    118             value = str('%s#' % value)
    119115        return super(
    120116            StudentsExporter, self).mangle_value(
  • main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/students/interfaces.py

    r9209 r9211  
    4343    def getValues(self, context):
    4444        verdicts_dict = getUtility(IStudentsUtils).VERDICTS_DICT
    45         return sorted(verdicts_dict.keys())
     45        return verdicts_dict.keys()
    4646
    4747    def getToken(self, context, value):
     
    5050    def getTitle(self, context, value):
    5151        verdicts_dict = getUtility(IStudentsUtils).VERDICTS_DICT
    52         if value != '0':
    53             return verdicts_dict[value] + ' (%s)' % value
    5452        return verdicts_dict[value]
    5553
     
    6765        """
    6866
    69     def setPaymentDetails(category, student, previous_session=None,
    70             previous_level=None,):
     67    def setPaymentDetails(category, student):
    7168        """Create Payment object and set the payment data of a student for
    7269        the payment category specified.
     
    154151    faccode = Attribute('The faculty code of any chosen study course')
    155152    current_session = Attribute('The current session of the student')
    156     current_level = Attribute('The current level of the student')
    157153    current_mode = Attribute('The current mode of the student')
    158     current_verdict = Attribute('The current verdict of the student')
    159154    fullname = Attribute('All name parts separated by hyphens')
    160155    display_fullname = Attribute('The fullname of an applicant')
    161     is_postgrad = Attribute('True if postgraduate student')
    162 
    163     suspended = schema.Bool(
    164         title = _(u'Account suspended'),
    165         default = False,
    166         required = False,
    167         )
    168156
    169157    student_id = schema.TextLine(
     
    210198        title = _(u'PWD Activation Code'),
    211199        required = False,
    212         readonly = False,
     200        readonly = True,
    213201        )
    214202
     
    224212        )
    225213
    226     def transfer(certificate, current_session,
    227         current_level, current_verdict):
    228         """ Creates a new studycourse and backups the old one.
    229 
    230         """
    231 
    232214class IUGStudentClearance(IKofaObject):
    233215    """Representation of undergraduate student clearance data.
     
    243225        title = _(u'Clearance form locked'),
    244226        default = False,
    245         required = False,
    246227        )
    247228
     
    249230        title = _(u'CLR Activation Code'),
    250231        required = False,
    251         readonly = False,
     232        readonly = True,
    252233        )
    253234
     
    307288    login for the the first time.
    308289    """
    309     number = schema.TextLine(
    310         title = _(u'Registr. or Matric. Number'),
     290    reg_number = schema.TextLine(
     291        title = u'Registration Number',
    311292        required = True,
    312293        )
     
    365346        title = _(u'Current Verdict'),
    366347        source = VerdictSource(),
    367         default = '0',
     348        default = 'NY',
    368349        required = False,
    369350        )
     
    372353        title = _(u'Previous Verdict'),
    373354        source = VerdictSource(),
    374         default = '0',
    375         required = False,
    376         )
    377 
    378 class IStudentStudyCourseTransfer(IStudentStudyCourse):
    379     """An student transfers.
    380 
    381     """
    382 
    383     certificate = schema.Choice(
    384         title = _(u'Certificate'),
    385         source = CertificateSource(),
     355        default = 'NY',
     356        required = False,
     357        )
     358
     359class IStudentVerdictUpdate(IKofaObject):
     360    """A interface for verdict imports.
     361
     362    """
     363
     364    current_verdict = schema.Choice(
     365        title = _(u'Current Verdict'),
     366        source = VerdictSource(),
     367        required = True,
     368        )
     369
     370    current_session = schema.Choice(
     371        title = _(u'Current Session'),
     372        source = academic_sessions_vocab,
    386373        required = True,
    387374        )
     
    391378        source = StudyLevelSource(),
    392379        required = True,
    393         readonly = False,
    394         )
    395 
    396 
    397 IStudentStudyCourseTransfer['certificate'].order = IStudentStudyCourse[
    398     'certificate'].order
    399 IStudentStudyCourseTransfer['current_level'].order = IStudentStudyCourse[
    400     'current_level'].order
    401 
    402 class IStudentVerdictUpdate(IKofaObject):
    403     """A interface for verdict imports.
    404 
    405     """
    406 
    407     current_verdict = schema.Choice(
    408         title = _(u'Current Verdict'),
    409         source = VerdictSource(),
    410         required = True,
    411         )
    412 
    413     current_session = schema.Choice(
    414         title = _(u'Current Session'),
    415         source = academic_sessions_vocab,
    416         required = True,
    417         )
    418 
    419     current_level = schema.Choice(
    420         title = _(u'Current Level'),
    421         source = StudyLevelSource(),
    422         required = True,
    423380        )
    424381
     
    428385    """
    429386    level = Attribute('The level code')
     387    validation_date = Attribute('The date of validation')
     388    validated_by = Attribute('User Id of course adviser')
    430389
    431390    level_session = schema.Choice(
    432391        title = _(u'Session'),
    433392        source = academic_sessions_vocab,
    434         required = False,
     393        required = True,
    435394        )
    436395
     
    438397        title = _(u'Verdict'),
    439398        source = VerdictSource(),
    440         default = '0',
    441         required = False,
    442         )
    443 
    444     validated_by = schema.TextLine(
    445         title = _(u'Validated by'),
    446         default = None,
    447         required = False,
    448         )
    449 
    450     validation_date = schema.Datetime(
    451         title = _(u'Validation Date'),
    452         required = False,
    453         readonly = False,
    454         )
    455 
    456     def addCourseTicket(ticket, course):
     399        default = 'NY',
     400        required = False,
     401        )
     402
     403    def addCourseTicket(courseticket):
    457404        """Add a course ticket object.
    458405        """
     
    573520    """
    574521
    575     p_current = schema.Bool(
    576         title = _(u'Current Session Payment'),
    577         default = True,
    578         required = False,
    579         )
    580 
    581522    p_level = schema.Int(
    582523        title = _(u'Payment Level'),
     
    602543IStudentOnlinePayment['p_level'].order = IStudentOnlinePayment[
    603544    'p_session'].order
    604 
    605 class IStudentPreviousPayment(IOnlinePayment):
    606     """An interface for adding previous session payments.
    607 
    608     """
    609 
    610     p_session = schema.Choice(
    611         title = _(u'Payment Session'),
    612         source = academic_sessions_vocab,
    613         required = True,
    614         )
    615 
    616     p_level = schema.Choice(
    617         title = _(u'Payment Level'),
    618         source = StudyLevelSource(),
    619         required = True,
    620         )
    621545
    622546class ICSVStudentExporter(ICSVExporter):
  • main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/students/payments.py

    r9209 r9211  
    9797        """Process student after payment was made.
    9898        """
    99         if self.p_current:
    100             error = self._createActivationCodes()
    101             if error is not None:
    102                 return False, error, error
     99        error = self._createActivationCodes()
     100        if error is not None:
     101            return False, error, error
    103102        log = 'successful payment: %s' % self.p_id
    104103        msg = _('Successful payment')
     
    108107        """Process student after payment was approved.
    109108        """
    110         if self.p_current:
    111             error = self._createActivationCodes()
    112             if error is not None:
    113                 return False, error, error
     109        error = self._createActivationCodes()
     110        if error is not None:
     111            return False, error, error
    114112        log = 'payment approved: %s' % self.p_id
    115113        msg = _('Payment approved')
  • main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/students/student.py

    r9209 r9211  
    2828from zope.interface import implementedBy
    2929from zope.securitypolicy.interfaces import IPrincipalRoleManager
    30 from zope.schema.interfaces import ConstraintNotSatisfied
    3130
    3231from waeup.kofa.image import KofaImageFile
     
    131130
    132131    @property
    133     def current_level(self):
    134         level = getattr(
    135             self.get('studycourse', None), 'current_level', None)
    136         return level
    137 
    138     @property
    139     def current_verdict(self):
    140         level = getattr(
    141             self.get('studycourse', None), 'current_verdict', None)
    142         return level
    143 
    144     @property
    145132    def current_mode(self):
    146133        certificate = getattr(
     
    155142            self.get('studycourse', None), 'is_postgrad', False)
    156143        return is_postgrad
    157 
    158     def transfer(self, certificate, current_session=None,
    159         current_level=None, current_verdict=None, previous_verdict=None):
    160         """ Creates a new studycourse and backups the old one.
    161 
    162         """
    163         studycourse = createObject(u'waeup.StudentStudyCourse')
    164         try:
    165             studycourse.certificate = certificate
    166             studycourse.entry_mode = 'transfer'
    167             studycourse.current_session = current_session
    168             studycourse.current_level = current_level
    169             studycourse.current_verdict = current_verdict
    170             studycourse.previous_verdict = previous_verdict
    171         except ConstraintNotSatisfied:
    172             return -1
    173         old = self['studycourse']
    174         if getattr(old, 'entry_session', None) is None or\
    175             getattr(old, 'certificate', None) is None:
    176             return -2
    177         studycourse.entry_session = old.entry_session
    178         # Students can be transferred only two times.
    179         if 'studycourse_1' in self.keys():
    180             if 'studycourse_2' in self.keys():
    181                 return -3
    182             self['studycourse_2'] = old
    183         else:
    184             self['studycourse_1'] = old
    185         del self['studycourse']
    186         self['studycourse'] = studycourse
    187         self.__parent__.logger.info(
    188             '%s - transferred from %s to %s' % (
    189             self.student_id, old.certificate.code, studycourse.certificate.code))
    190         history = IObjectHistory(self)
    191         history.addMessage('Transferred from %s to %s' % (
    192             old.certificate.code, studycourse.certificate.code))
    193         return
    194144
    195145
  • main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/students/studycourse.py

    r9209 r9211  
    6161    @property
    6262    def is_postgrad(self):
    63         if self.certificate is None:
    64             return False
    6563        return self.certificate.study_mode.startswith('pg')
    66 
    67     @property
    68     def is_current(self):
    69         if '_' in self.__name__:
    70             return False
    71         return True
     64        #return cert.start_level == 999 or cert.end_level == 999
    7265
    7366    def addStudentStudyLevel(self, cert, studylevel):
  • main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/students/studylevel.py

    r9209 r9211  
    3737        super(StudentStudyLevel, self).__init__()
    3838        self.level = None
     39        self.validation_date = None
     40        self.validated_by = None
    3941        return
    4042
     
    5456        return studylevelsource.factory.getTitle(self.__parent__, self.level)
    5557
    56     def addCourseTicket(self, ticket, course):
     58    def addCourseTicket(self, courseticket):
    5759        """Add a course ticket object.
    5860        """
    59         if not ICourseTicket.providedBy(ticket):
     61        if not ICourseTicket.providedBy(courseticket):
    6062            raise TypeError(
    6163                'StudentStudyLeves contain only ICourseTicket instances')
    62         ticket.code = course.code
    63         ticket.title = course.title
    64         ticket.fcode = course.__parent__.__parent__.__parent__.code
    65         ticket.dcode = course.__parent__.__parent__.code
    66         ticket.credits = course.credits
    67         ticket.passmark = course.passmark
    68         ticket.semester = course.semester
    69         self[ticket.code] = ticket
     64        self[courseticket.code] = courseticket
    7065        return
    7166
     
    9287
    9388    A course ticket contains a copy of the original course and
    94     certificate course data. If the courses and/or the referrin certificate
    95     courses are removed, the corresponding tickets remain unchanged.
    96     So we do not need any event
     89    course referrer data. If the courses and/or their referrers are removed, the
     90    corresponding tickets remain unchanged. So we do not need any event
    9791    triggered actions on course tickets.
    9892    """
  • main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/students/tests/sample_payment_data.csv

    r9209 r9211  
    1 matric_number,p_state,p_category,p_id,reg_number,session_id,r_amount_approved,p_item,amount_auth,r_card_num,r_code,creation_date,type,p_current
    2 ,paid,schoolfee,3816951290797973744#,1,2010,19500,BTECHBDT,19500,0942,00,2010/11/26 19:59:33.744 GMT+1,online,1
    3 100001,unpaid,schoolfee,3816951290712593757,,2010,0,BTECHBDT,19500,0942,Z0,2010-11-25 20:16:33.757 WAT,online,0
    4 ,paid,schoolfee,p1266236341955,3,2009,19500,BTECHBDT,19500,0615,00,2010/02/15 13:19:01,online,1
     1matric_number,p_state,p_category,p_id,reg_number,session_id,r_amount_approved,p_item,amount_auth,r_card_num,r_code,creation_date,type
     2,paid,schoolfee,3816951290797973744#,1,2010,19500,BTECHBDT,19500,0942,00,2010/11/26 19:59:33.744 GMT+1,online
     3100001,unpaid,schoolfee,3816951290712593757,,2010,0,BTECHBDT,19500,0942,Z0,2010-11-25 20:16:33.757 GMT+1,online
     4,paid,schoolfee,p1266236341955,3,2009,19500,BTECHBDT,19500,0615,00,2010/02/15 13:19:01,online
  • main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/students/tests/test_authentication.py

    r9209 r9211  
    6565    email = None
    6666    phone = None
    67     suspended = False
    6867
    6968
  • main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/students/tests/test_batching.py

    r9209 r9211  
    2323import unittest
    2424import datetime
    25 import grok
    2625from time import time
    27 from zope.event import notify
    2826from zope.component import createObject
    2927from zope.component.hooks import setSite, clearSite
    3028from zope.interface.verify import verifyClass, verifyObject
    31 from hurry.workflow.interfaces import IWorkflowState
    3229
    3330from waeup.kofa.app import University
     
    129126    '\n')[0].split(',')
    130127
    131 PAYMENT_CREATE_SAMPLE_DATA = open(
    132     os.path.join(os.path.dirname(__file__), 'sample_create_payment_data.csv'),
    133     'rb').read()
    134 
    135 PAYMENT_CREATE_HEADER_FIELDS = PAYMENT_CREATE_SAMPLE_DATA.split(
    136     '\n')[0].split(',')
    137 
    138128class StudentImportExportSetup(FunctionalTestCase):
    139129
     
    181171    def setup_student(self, student):
    182172        # set predictable values for `student`
    183         student.matric_number = u'234'
     173        student.matric_number = u'M123456'
    184174        student.adm_code = u'my adm code'
    185175        student.clearance_locked = False
    186176        student.clr_code = u'my clr code'
    187177        student.perm_address = u'Studentroad 21\nLagos 123456\n'
    188         student.reg_number = u'123'
     178        student.reg_number = u'123456'
     179        student.student_id = u'A111111'
    189180        student.firstname = u'Anna'
    190181        student.lastname = u'Tester'
     
    220211        ticket.passmark = 100
    221212        ticket.semester = 2
    222         study_level[ticket.code] = ticket
     213        study_level.addCourseTicket(ticket)
    223214        self.add_payment(student)
    224215        return student
     
    241232
    242233
    243 class StudentProcessorTest(StudentImportExportSetup):
     234
     235class StudentProcessorTest(FunctionalTestCase):
    244236
    245237    layer = FunctionalLayer
     
    247239    def setUp(self):
    248240        super(StudentProcessorTest, self).setUp()
     241        # Setup a sample site for each test
     242        app = University()
     243        self.dc_root = tempfile.mkdtemp()
     244        app['datacenter'].setStoragePath(self.dc_root)
     245
     246        # Prepopulate the ZODB...
     247        self.getRootFolder()['app'] = app
     248        # we add the site immediately after creation to the
     249        # ZODB. Catalogs and other local utilities are not setup
     250        # before that step.
     251        self.app = self.getRootFolder()['app']
     252        # Set site here. Some of the following setup code might need
     253        # to access grok.getSite() and should get our new app then
     254        setSite(app)
    249255
    250256        # Add student with subobjects
    251257        student = Student()
     258        student.firstname = u'Anna'
     259        student.lastname = u'Tester'
     260        student.reg_number = u'123'
     261        student.matric_number = u'234'
    252262        self.app['students'].addStudent(student)
    253         student = self.setup_student(student)
    254         notify(grok.ObjectModifiedEvent(student))
    255263        self.student = self.app['students'][student.student_id]
    256 
    257264        self.processor = StudentProcessor()
    258265        self.workdir = tempfile.mkdtemp()
     
    278285        open(self.csv_file_duplicates, 'wb').write(STUDENT_SAMPLE_DATA_DUPLICATES)
    279286
     287    def tearDown(self):
     288        super(StudentProcessorTest, self).tearDown()
     289        shutil.rmtree(self.workdir)
     290        shutil.rmtree(self.dc_root)
     291        clearSite()
     292        return
     293
    280294    def test_interface(self):
    281295        # Make sure we fulfill the interface contracts.
     
    329343        self.assertEqual(initial_stud_id, new_stud_id)
    330344        return
    331 
    332     def test_checkUpdateRequirements(self):
    333         # Make sure that pg students can't be updated with wrong transition.
    334         err = self.processor.checkUpdateRequirements(self.student,
    335             dict(reg_number='1', state='returning'), self.app)
    336         self.assertTrue(err is None)
    337         self.certificate.study_mode = 'pg_ft'
    338         err = self.processor.checkUpdateRequirements(self.student,
    339             dict(reg_number='1', state='returning'), self.app)
    340         self.assertEqual(err, 'State not allowed (pg student).')
    341         IWorkflowState(self.student).setState('school fee paid')
    342         err = self.processor.checkUpdateRequirements(self.student,
    343             dict(reg_number='1', transition='reset6'), self.app)
    344         self.assertEqual(err, 'Transition not allowed (pg student).')
    345         err = self.processor.checkUpdateRequirements(self.student,
    346             dict(reg_number='1', transition='register_courses'), self.app)
    347         self.assertEqual(err, 'Transition not allowed (pg student).')
    348 
    349345
    350346    def test_delEntry(self):
     
    490486        super(StudentStudyCourseProcessorTest, self).setUp()
    491487
    492         # Add student with subobjects
    493         student = Student()
    494         self.app['students'].addStudent(student)
    495         student = self.setup_student(student)
    496         notify(grok.ObjectModifiedEvent(student))
    497         self.student = self.app['students'][student.student_id]
    498 
    499488        # Import students with subobjects
    500489        student_file = os.path.join(self.workdir, 'sample_student_data.csv')
     
    543532            dict(reg_number='1', current_level='100'))
    544533        self.assertEqual(len(errs),0)
    545 
    546     def test_checkUpdateRequirements(self):
    547         # Make sure that pg students can't be updated with wrong transition.
    548         err = self.processor.checkUpdateRequirements(self.student['studycourse'],
    549             dict(reg_number='1', current_level='100'), self.app)
    550         self.assertTrue(err is None)
    551         # Since row has passed the converter, current_level is an integer.
    552         err = self.processor.checkUpdateRequirements(self.student['studycourse'],
    553             dict(reg_number='1', current_level=999), self.app)
    554         self.assertTrue(err is None)
    555         IWorkflowState(self.student).setState('returning')
    556         err = self.processor.checkUpdateRequirements(self.student['studycourse'],
    557             dict(reg_number='1', current_level=999), self.app)
    558         self.assertEqual(err, 'Not a pg student.')
    559534
    560535    def test_import(self):
     
    692667        self.assertEqual(num_warns,2)
    693668        shutil.rmtree(os.path.dirname(fin_file))
     669       
    694670
    695671class CourseTicketProcessorTest(StudentImportExportSetup):
     
    705681        shutil.rmtree(os.path.dirname(fin_file))
    706682
    707         # Add course and certificate course
     683        # Add course and course referrer
    708684        self.course = createObject('waeup.Course')
    709685        self.course.code = 'COURSE1'
     
    713689        self.app['faculties']['fac1']['dep1'].courses.addCourse(
    714690            self.course)
    715         self.app['faculties']['fac1']['dep1'].certificates['CERT1'].addCertCourse(
     691        self.app['faculties']['fac1']['dep1'].certificates['CERT1'].addCourseRef(
    716692            self.course, level=100)
    717693
     
    779755        # Logging message from updateEntry,
    780756        self.assertTrue(
    781             'INFO - system - K1000000 - Course ticket in 100 updated: code=COURSE1, '
     757            'INFO - system - K1000000 - Course ticket updated: code=COURSE1, '
    782758            'mandatory=False, score=3'
    783759            in logcontent)
     
    793769        self.assertEqual(num_warns,2)
    794770        shutil.rmtree(os.path.dirname(fin_file))
    795 
    796     def test_import_remove(self):
    797         # We perform the same import twice,
    798         # the second time in remove mode. The number
    799         # of warnings must be the same.
    800         num, num_warns, fin_file, fail_file = self.processor.doImport(
    801             self.csv_file, COURSETICKET_HEADER_FIELDS,'create')
    802         assert self.processor.entryExists(
    803             dict(reg_number='1', level='100', code='COURSE1'), self.app) is True
    804         num, num_warns, fin_file, fail_file = self.processor.doImport(
    805             self.csv_file, COURSETICKET_HEADER_FIELDS,'remove')
    806         self.assertEqual(num_warns,2)
    807         assert self.processor.entryExists(
    808             dict(reg_number='1', level='100', code='COURSE1'), self.app) is False
    809         shutil.rmtree(os.path.dirname(fin_file))
    810         logcontent = open(self.logfile).read()
    811         self.assertTrue(
    812             'INFO - system - K1000000 - Course ticket in 100 removed: COURSE1'
    813             in logcontent)
    814771
    815772class PaymentProcessorTest(StudentImportExportSetup):
     
    827784        self.student = self.app['students'][student.student_id]
    828785        payment = createObject(u'waeup.StudentOnlinePayment')
    829         payment.p_id = 'p120'
     786        payment.p_id = 'p123'
    830787        self.student['payments'][payment.p_id] = payment
    831788
     
    841798            self.workdir, 'sample_payment_data.csv')
    842799        open(self.csv_file, 'wb').write(PAYMENT_SAMPLE_DATA)
    843         self.csv_file2 = os.path.join(
    844             self.workdir, 'sample_create_payment_data.csv')
    845         open(self.csv_file2, 'wb').write(PAYMENT_CREATE_SAMPLE_DATA)
    846800
    847801    def test_interface(self):
     
    855809            dict(student_id='ID_NONE', p_id='nonsense'), self.app) is None
    856810        assert self.processor.getEntry(
    857             dict(student_id=self.student.student_id, p_id='p120'),
    858             self.app) is self.student['payments']['p120']
     811            dict(student_id=self.student.student_id, p_id='p123'),
     812            self.app) is self.student['payments']['p123']
    859813        assert self.processor.getEntry(
    860             dict(student_id=self.student.student_id, p_id='XXXXXX112'),
    861             self.app) is self.student['payments']['p120']
    862 
    863     def test_delEntry(self):
    864         assert self.processor.getEntry(
    865             dict(student_id=self.student.student_id, p_id='p120'),
    866             self.app) is self.student['payments']['p120']
    867         self.assertEqual(len(self.student['payments'].keys()),1)
    868         self.processor.delEntry(
    869             dict(student_id=self.student.student_id, p_id='p120'),
    870             self.app)
    871         assert self.processor.getEntry(
    872             dict(student_id=self.student.student_id, p_id='p120'),
    873             self.app) is None
    874         self.assertEqual(len(self.student['payments'].keys()),0)
     814            dict(student_id=self.student.student_id, p_id='XXXXXX123'),
     815            self.app) is self.student['payments']['p123']
    875816
    876817    def test_addEntry(self):
     
    890831            self.app)
    891832        self.assertEqual(len(self.student['payments'].keys()),3)
    892         self.assertEqual(self.student['payments']['p560'].p_id, 'p560')
     833        self.assertEqual(self.student['payments']['p456'].p_id, 'p456')
    893834
    894835    def test_checkConversion(self):
    895836        errs, inv_errs, conv_dict = self.processor.checkConversion(
    896             dict(p_id='3816951266236341955'))
     837            dict(reg_number='1', p_id='3816951266236341955'))
    897838        self.assertEqual(len(errs),0)
    898839        errs, inv_errs, conv_dict = self.processor.checkConversion(
    899             dict(p_id='p1266236341955'))
     840            dict(reg_number='1', p_id='p1266236341955'))
    900841        self.assertEqual(len(errs),0)
    901842        errs, inv_errs, conv_dict = self.processor.checkConversion(
    902             dict(p_id='nonsense'))
     843            dict(reg_number='1', p_id='nonsense'))
    903844        self.assertEqual(len(errs),1)
    904         timestamp = ("%d" % int(time()*10000))[1:]
     845        timestamp = "%d" % int(time()*1000)
    905846        p_id = "p%s" % timestamp
    906847        errs, inv_errs, conv_dict = self.processor.checkConversion(
    907             dict(p_id=p_id))
     848            dict(reg_number='1', p_id=p_id))
    908849        self.assertEqual(len(errs),0)
    909850
     
    913854        self.assertEqual(num_warns,0)
    914855        payment = self.processor.getEntry(dict(reg_number='1',
    915             p_id='p2907979737440'), self.app)
    916         self.assertEqual(payment.p_id, 'p2907979737440')
    917         self.assertTrue(payment.p_current)
     856            p_id='p1290797973744'), self.app)
     857        self.assertEqual(payment.p_id, 'p1290797973744')
    918858        cdate = payment.creation_date.strftime("%Y-%m-%d %H:%M:%S")
    919859        self.assertEqual(cdate, "2010-11-26 18:59:33")
    920860        self.assertEqual(str(payment.creation_date.tzinfo),'UTC')
    921         payment = self.processor.getEntry(dict(matric_number='100001',
    922             p_id='p2907125937570'), self.app)
    923         self.assertEqual(payment.p_id, 'p2907125937570')
    924         self.assertFalse(payment.p_current)
    925         cdate = payment.creation_date.strftime("%Y-%m-%d %H:%M:%S")
    926         # Ooooh, still the old problem, see
    927         # http://mail.dzug.org/mailman/archives/zope/2006-August/001153.html.
    928         # WAT is interpreted as GMT-1 and not GMT+1
    929         self.assertEqual(cdate, "2010-11-25 21:16:33")
    930         self.assertEqual(str(payment.creation_date.tzinfo),'UTC')
    931         shutil.rmtree(os.path.dirname(fin_file))
     861        shutil.rmtree(os.path.dirname(fin_file))
     862
    932863        logcontent = open(self.logfile).read()
    933         # Logging message from updateEntry
     864        # Logging message from updateEntry,
    934865        self.assertTrue(
    935866            'INFO - system - K1000001 - Payment ticket updated: '
    936             'p_item=BTECHBDT, creation_date=2010-02-15 13:19:01+00:00, '
    937             'p_category=schoolfee, amount_auth=19500.0, p_current=True, '
    938             'p_id=p1266236341955, r_code=00, r_amount_approved=19500.0, '
    939             'p_state=paid'
     867            'p_id=p1266236341955, p_item=BTECHBDT, '
     868            'creation_date=2010-02-15 13:19:01+00:00, r_code=00, '
     869            'r_amount_approved=19500.0, p_category=schoolfee, '
     870            'amount_auth=19500.0, p_state=paid'
    940871            in logcontent)
    941872
     
    950881        self.assertEqual(num_warns,0)
    951882        shutil.rmtree(os.path.dirname(fin_file))
    952 
    953     def test_import_remove(self):
    954         num, num_warns, fin_file, fail_file = self.processor.doImport(
    955             self.csv_file, PAYMENT_HEADER_FIELDS,'create')
    956         num, num_warns, fin_file, fail_file = self.processor.doImport(
    957             self.csv_file, PAYMENT_HEADER_FIELDS,'remove')
    958         self.assertEqual(num_warns,0)
    959         shutil.rmtree(os.path.dirname(fin_file))
    960         logcontent = open(self.logfile).read()
    961         self.assertTrue(
    962             'INFO - system - K1000001 - Payment ticket removed: p1266236341955'
    963             in logcontent)
    964 
    965     def test_import_wo_pid(self):
    966         num, num_warns, fin_file, fail_file = self.processor.doImport(
    967             self.csv_file2, PAYMENT_CREATE_HEADER_FIELDS,'create')
    968         self.assertEqual(num_warns,0)
    969         shutil.rmtree(os.path.dirname(fin_file))
    970         self.assertEqual(len(self.app['students']['X666666']['payments']), 50)
    971 
    972883
    973884def test_suite():
  • main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/students/tests/test_browser.py

    r9209 r9211  
    118118        self.manage_clearance_path = self.student_path + '/manage_clearance'
    119119        self.edit_personal_path = self.student_path + '/edit_personal'
    120         self.manage_personal_path = self.student_path + '/manage_personal'
    121120        self.studycourse_path = self.student_path + '/studycourse'
    122121        self.payments_path = self.student_path + '/payments'
     
    171170        self.app['faculties']['fac1']['dep1'].courses.addCourse(
    172171            self.course)
    173         self.app['faculties']['fac1']['dep1'].certificates['CERT1'].addCertCourse(
     172        self.app['faculties']['fac1']['dep1'].certificates['CERT1'].addCourseRef(
    174173            self.course, level=100)
    175174
     
    404403    layer = FunctionalLayer
    405404
    406     def test_student_properties(self):
    407         self.student['studycourse'].current_level = 100
    408         self.assertEqual(self.student.current_level, 100)
    409         self.student['studycourse'].current_session = 2011
    410         self.assertEqual(self.student.current_session, 2011)
    411         self.student['studycourse'].current_verdict = 'A'
    412         self.assertEqual(self.student.current_verdict, 'A')
    413         return
    414 
    415405    def test_basic_auth(self):
    416406        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
     
    464454        self.assertEqual(self.browser.headers['Status'], '200 Ok')
    465455        self.assertEqual(self.browser.url, self.personal_path)
    466         self.browser.getLink("Manage").click()
    467         self.assertEqual(self.browser.headers['Status'], '200 Ok')
    468         self.assertEqual(self.browser.url, self.manage_personal_path)
    469         self.browser.open(self.personal_path)
    470456        self.browser.getLink("Edit").click()
    471457        self.assertEqual(self.browser.headers['Status'], '200 Ok')
     
    488474        self.assertEqual(self.browser.headers['Status'], '200 Ok')
    489475        self.assertEqual(self.browser.url, self.history_path)
    490         self.assertMatches('...Admitted by Manager...',
     476        self.assertMatches('...Student admitted by Manager...',
    491477                           self.browser.contents)
    492478        # Only the Application Slip does not exist
     
    768754        self.assertEqual(student['studycourse'].current_session, 2005) # +1
    769755        self.assertEqual(student['studycourse'].current_level, 200) # +100
    770         self.assertEqual(student['studycourse'].current_verdict, '0') # 0 = Zero = not set
     756        self.assertEqual(student['studycourse'].current_verdict, 'NY') # NY = not set
    771757        self.assertEqual(student['studycourse'].previous_verdict, 'A')
    772758        self.browser.getControl(name="transition").value = ['register_courses']
     
    776762        self.browser.getControl(name="transition").value = ['return']
    777763        self.browser.getControl("Save").click()
    778         return
    779 
    780     def test_manage_pg_workflow(self):
    781         # Managers can pass through the whole workflow
    782         IWorkflowState(self.student).setState('school fee paid')
    783         self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
    784         student = self.app['students'][self.student_id]
    785         self.browser.open(self.manage_student_path)
    786         self.assertTrue('<option value="reset6">' in self.browser.contents)
    787         self.assertTrue('<option value="register_courses">' in self.browser.contents)
    788         self.assertTrue('<option value="reset5">' in self.browser.contents)
    789         self.certificate.study_mode = 'pg_ft'
    790         self.browser.open(self.manage_student_path)
    791         self.assertFalse('<option value="reset6">' in self.browser.contents)
    792         self.assertFalse('<option value="register_courses">' in self.browser.contents)
    793         self.assertTrue('<option value="reset5">' in self.browser.contents)
    794764        return
    795765
     
    806776        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
    807777        self.browser.open(datacenter_path)
    808         self.browser.getLink('Upload data').click()
     778        self.browser.getLink('Upload CSV file').click()
    809779        filecontents = StringIO(open('students.csv', 'rb').read())
    810780        filewidget = self.browser.getControl(name='uploadfile:file')
    811781        filewidget.add_file(filecontents, 'text/plain', 'students.csv')
    812782        self.browser.getControl(name='SUBMIT').click()
    813         self.browser.getLink('Process data').click()
     783        self.browser.getLink('Batch processing').click()
    814784        button = lookup_submit_value(
    815785            'select', 'students_zope.mgr.csv', self.browser)
     
    832802""")
    833803        self.browser.open(datacenter_path)
    834         self.browser.getLink('Upload data').click()
     804        self.browser.getLink('Upload CSV file').click()
    835805        filecontents = StringIO(open('studycourses.csv', 'rb').read())
    836806        filewidget = self.browser.getControl(name='uploadfile:file')
    837807        filewidget.add_file(filecontents, 'text/plain', 'studycourses.csv')
    838808        self.browser.getControl(name='SUBMIT').click()
    839         self.browser.getLink('Process data').click()
     809        self.browser.getLink('Batch processing').click()
    840810        button = lookup_submit_value(
    841811            'select', 'studycourses_zope.mgr.csv', self.browser)
     
    947917        self.assertTrue('clearance started' in self.browser.contents)
    948918        self.browser.open(self.history_path)
    949         self.assertTrue("Reset to 'clearance started' by My Public Name" in
     919        self.assertTrue("Reset to 'clearance' by My Public Name" in
    950920            self.browser.contents)
    951921        IWorkflowInfo(self.student).fireTransition('request_clearance')
     
    976946        self.app['users'].addUser('mrsadvise', 'mrsadvisesecret')
    977947        self.app['users']['mrsadvise'].email = 'mradvise@foo.ng'
    978         self.app['users']['mrsadvise'].title = u'Helen Procter'
     948        self.app['users']['mrsadvise'].title = 'Helen Procter'
    979949        # Assign local CourseAdviser100 role for a certificate
    980950        cert = self.app['faculties']['fac1']['dep1'].certificates['CERT1']
     
    1027997        # the 100L CA does see the 'Validate' button
    1028998        self.browser.open(L110_student_path)
    1029         self.assertFalse('Validate courses' in self.browser.contents)
     999        self.assertFalse('Validate' in self.browser.contents)
    10301000        IWorkflowInfo(self.student).fireTransition('register_courses')
    10311001        self.browser.open(L110_student_path)
    1032         self.assertFalse('Validate courses' in self.browser.contents)
     1002        self.assertFalse('Validate' in self.browser.contents)
    10331003        self.student['studycourse'].current_level = 110
    10341004        self.browser.open(L110_student_path)
    1035         self.assertTrue('Validate courses' in self.browser.contents)
     1005        self.assertTrue('Validate' in self.browser.contents)
    10361006        # ... but a 100L CA does not see the button on other levels
    10371007        studylevel2 = StudentStudyLevel()
     
    10411011        L200_student_path = self.studycourse_path + '/200'
    10421012        self.browser.open(L200_student_path)
    1043         self.assertFalse('Validate courses' in self.browser.contents)
     1013        self.assertFalse('Validate' in self.browser.contents)
    10441014        self.browser.open(L110_student_path)
    10451015        self.browser.getLink("Validate courses").click()
    10461016        self.assertTrue('Course list has been validated' in self.browser.contents)
    10471017        self.assertTrue('courses validated' in self.browser.contents)
    1048         self.assertEqual(self.student['studycourse']['110'].validated_by,
    1049             'Helen Procter')
    1050         self.assertMatches(
    1051             '<YYYY-MM-DD hh:mm:ss>',
    1052             self.student['studycourse']['110'].validation_date.strftime(
    1053                 "%Y-%m-%d %H:%M:%S"))
    10541018        self.browser.getLink("Reject courses").click()
    10551019        self.assertTrue('Course list request has been annulled.'
     
    10591023            '/contactstudent?subject=%s' % urlmessage)
    10601024        self.assertTrue('school fee paid' in self.browser.contents)
    1061         self.assertTrue(self.student['studycourse']['110'].validated_by is None)
    1062         self.assertTrue(self.student['studycourse']['110'].validation_date is None)
    10631025        IWorkflowInfo(self.student).fireTransition('register_courses')
    10641026        self.browser.open(L110_student_path)
     
    11801142        # and can perform actions
    11811143        IWorkflowInfo(self.student).fireTransition('admit')
    1182         # Students can't login if their account is suspended/deactivated
    1183         self.student.suspended = True
    11841144        self.browser.open(self.login_path)
    11851145        self.browser.getControl(name="form.login").value = self.student_id
    11861146        self.browser.getControl(name="form.password").value = 'spwd'
    11871147        self.browser.getControl("Login").click()
    1188         self.assertTrue(
    1189             'Your account has been deactivated.' in self.browser.contents)
    1190         self.student.suspended = False
    1191         self.browser.getControl("Login").click()
    1192         self.assertTrue(
    1193             'You logged in.' in self.browser.contents)
    1194         # Admitted student can upload a passport picture
     1148        # Student can upload a passport picture
    11951149        self.browser.open(self.student_path + '/change_portrait')
    11961150        ctrl = self.browser.getControl(name='passportuploadedit')
     
    12031157            '<img align="middle" height="125px" src="passport.jpg" />'
    12041158            in self.browser.contents)
    1205         # Students can open admission letter
    1206         self.browser.getLink("Base Data").click()
    1207         self.browser.getLink("Download admission letter").click()
    1208         self.assertEqual(self.browser.headers['Status'], '200 Ok')
    1209         self.assertEqual(self.browser.headers['Content-Type'], 'application/pdf')
    12101159        # Student can view the clearance data
    1211         self.browser.open(self.student_path)
    12121160        self.browser.getLink("Clearance Data").click()
    12131161        # Student can't open clearance edit form before starting clearance
     
    12221170        self.assertMatches('...Not all required fields filled...',
    12231171                           self.browser.contents)
    1224         self.browser.open(self.student_path + '/edit_base')
    1225         self.browser.getControl(name="form.email").value = 'aa@aa.ng'
    1226         self.browser.getControl("Save").click()
     1172        self.student.email = 'aa@aa.ng'
    12271173        self.browser.open(self.student_path + '/start_clearance')
    12281174        self.browser.getControl(name="ac_series").value = '3'
     
    12391185        # Set the correct owner
    12401186        self.existing_clrac.owner = self.student_id
    1241         # clr_code might be set (and thus returns None) due importing
    1242         # an empty clr_code column.
    1243         self.student.clr_code = None
    12441187        self.browser.getControl("Start clearance now").click()
    12451188        self.assertMatches('...Clearance process has been started...',
     
    12921235        self.browser.getControl("Create course list now").click()
    12931236        self.browser.getLink("100").click()
    1294         self.browser.getLink("Edit course list").click()
     1237        self.browser.getLink("Add and remove courses").click()
    12951238        self.browser.getControl("Add course ticket").click()
    12961239        self.browser.getControl(name="form.course").value = ['COURSE1']
     
    13051248        self.browser.getControl("Create course list now").click()
    13061249        self.browser.getLink("200").click()
    1307         self.browser.getLink("Edit course list").click()
     1250        self.browser.getLink("Add and remove courses").click()
    13081251        self.browser.getControl("Add course ticket").click()
    13091252        self.browser.getControl(name="form.course").value = ['COURSE1']
     
    13431286        self.assertEqual(self.student.state, 'courses registered')
    13441287        return
    1345 
    1346     def test_student_clearance_wo_clrcode(self):
    1347         IWorkflowState(self.student).setState('clearance started')
    1348         self.browser.open(self.login_path)
    1349         self.browser.getControl(name="form.login").value = self.student_id
    1350         self.browser.getControl(name="form.password").value = 'spwd'
    1351         self.browser.getControl("Login").click()
    1352         self.student.clearance_locked = False
    1353         self.browser.open(self.edit_clearance_path)
    1354         self.browser.getControl(name="form.date_of_birth").value = '09/10/1961'
    1355         self.browser.getControl("Save and request clearance").click()
    1356         self.assertMatches('...Clearance has been requested...',
    1357                            self.browser.contents)
    13581288
    13591289    def test_manage_payments(self):
     
    15861516        # The new SFE-0 pin can be used for starting new session
    15871517        self.browser.open(self.studycourse_path)
    1588         self.browser.getLink('Start new session').click()
     1518        self.browser.getLink('Start session').click()
    15891519        pin = self.app['accesscodes']['SFE-0'].keys()[0]
    15901520        parts = pin.split('-')[1:]
     
    15981528        return
    15991529
    1600     def test_student_previous_payments(self):
    1601         configuration = createObject('waeup.SessionConfiguration')
    1602         configuration.academic_session = 2000
    1603         configuration.clearance_fee = 3456.0
    1604         configuration.booking_fee = 123.4
    1605         self.student['studycourse'].entry_session = 2002
    1606         self.app['configuration'].addSessionConfiguration(configuration)
    1607         configuration2 = createObject('waeup.SessionConfiguration')
    1608         configuration2.academic_session = 2003
    1609         configuration2.clearance_fee = 3456.0
    1610         configuration2.booking_fee = 123.4
    1611         self.student['studycourse'].entry_session = 2002
    1612         self.app['configuration'].addSessionConfiguration(configuration2)
    1613         # Login
    1614         self.browser.open(self.login_path)
    1615         self.browser.getControl(name="form.login").value = self.student_id
    1616         self.browser.getControl(name="form.password").value = 'spwd'
    1617         self.browser.getControl("Login").click()
    1618 
    1619         # Students can add previous school fee payment tickets in any state.
    1620         IWorkflowState(self.student).setState('courses registered')
    1621         self.browser.open(self.payments_path)
    1622         self.browser.getControl("Add online payment ticket").click()
    1623         self.browser.getControl(name="form.p_category").value = ['schoolfee']
    1624         self.browser.getControl("Create ticket").click()
    1625 
    1626         # Amount cannot be determined since the state is not
    1627         # 'cleared' or 'returning'
    1628         self.assertMatches('...Amount could not be determined...',
    1629                            self.browser.contents)
    1630         self.assertMatches('...Would you like to pay for a previous session?...',
    1631                            self.browser.contents)
    1632 
    1633         # Previous session payment form is provided
    1634         self.browser.getControl(name="form.p_category").value = ['schoolfee']
    1635         self.browser.getControl(name="form.p_session").value = ['2000']
    1636         self.browser.getControl(name="form.p_level").value = ['300']
    1637         self.browser.getControl("Create ticket").click()
    1638         self.assertMatches('...The previous session must not fall below...',
    1639                            self.browser.contents)
    1640         self.browser.getControl(name="form.p_category").value = ['schoolfee']
    1641         self.browser.getControl(name="form.p_session").value = ['2004']
    1642         self.browser.getControl(name="form.p_level").value = ['300']
    1643         self.browser.getControl("Create ticket").click()
    1644         self.assertMatches('...This is not a previous session...',
    1645                            self.browser.contents)
    1646         self.browser.getControl(name="form.p_category").value = ['schoolfee']
    1647         self.browser.getControl(name="form.p_session").value = ['2003']
    1648         self.browser.getControl(name="form.p_level").value = ['300']
    1649         self.browser.getControl("Create ticket").click()
    1650         self.assertMatches('...ticket created...',
    1651                            self.browser.contents)
    1652         ctrl = self.browser.getControl(name='val_id')
    1653         value = ctrl.options[0]
    1654         self.browser.getLink(value).click()
    1655         self.assertMatches('...Amount Authorized...',
    1656                            self.browser.contents)
    1657         self.assertEqual(self.student['payments'][value].amount_auth, 20000.0)
    1658 
    1659         # Payment session is properly set
    1660         self.assertEqual(self.student['payments'][value].p_session, 2003)
    1661         self.assertEqual(self.student['payments'][value].p_level, 300)
    1662 
    1663         # We simulate the approval
    1664         self.browser.open(self.browser.url + '/fake_approve')
    1665         self.assertMatches('...Payment approved...',
    1666                           self.browser.contents)
    1667 
    1668         # No AC has been created
    1669         self.assertEqual(len(self.app['accesscodes']['SFE-0'].keys()), 0)
    1670         self.assertTrue(self.student['payments'][value].ac is None)
    1671 
    1672         # Current payment flag is set False
    1673         self.assertFalse(self.student['payments'][value].p_current)
    1674         return
    1675 
    1676     def test_student_postgraduate_payments(self):
     1530    def test_postgraduate_payments(self):
    16771531        self.certificate.study_mode = 'pg_ft'
    16781532        self.certificate.start_level = 999
     
    16981552                           self.browser.contents)
    16991553        # Payment session and level are current ones.
    1700         # Postgrads have to pay school_fee_1.
     1554        # Postgrads have to school_fee_1.
    17011555        self.assertEqual(self.student['payments'][value].amount_auth, 40000.0)
    17021556        self.assertEqual(self.student['payments'][value].p_session, 2004)
     
    17111565        # The new SFE-0 pin can be used for starting session
    17121566        self.browser.open(self.studycourse_path)
    1713         self.browser.getLink('Start new session').click()
     1567        self.browser.getLink('Start session').click()
    17141568        pin = self.app['accesscodes']['SFE-0'].keys()[0]
    17151569        parts = pin.split('-')[1:]
     
    17511605        # The new SFE-1 pin can be used for starting new session
    17521606        self.browser.open(self.studycourse_path)
    1753         self.browser.getLink('Start new session').click()
     1607        self.browser.getLink('Start session').click()
    17541608        self.browser.getControl(name="ac_series").value = sfeseries
    17551609        self.browser.getControl(name="ac_number").value = sfenumber
     
    19931847        self.browser.getControl(name="form.identifier").value = '123'
    19941848        self.browser.getControl(name="form.email").value = 'aa@aa.ng'
    1995         self.browser.getControl("Send login credentials").click()
     1849        self.browser.getControl("Get login credentials").click()
    19961850        self.assertTrue('An email with' in self.browser.contents)
     1851
     1852    def test_reindex(self):
     1853        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
     1854        self.browser.open('http://localhost/app/reindex')
     1855        self.assertTrue('No catalog name provided' in self.browser.contents)
     1856        self.browser.open('http://localhost/app/reindex?ctlg=xyz')
     1857        self.assertTrue('xyz_catalog does not exist' in self.browser.contents)
     1858        cat = queryUtility(ICatalog, name='students_catalog')
     1859        results = cat.searchResults(student_id=(None, None))
     1860        self.assertEqual(len(results),1)
     1861        cat.clear()
     1862        results = cat.searchResults(student_id=(None, None))
     1863        self.assertEqual(len(results),0)
     1864        self.browser.open('http://localhost/app/reindex?ctlg=students')
     1865        self.assertTrue('1 students re-indexed' in self.browser.contents)
     1866        results = cat.searchResults(student_id=(None, None))
     1867        self.assertEqual(len(results),1)
    19971868
    19981869    def test_change_current_mode(self):
     
    20171888        self.assertTrue('Employer' in self.browser.contents)
    20181889
    2019     def test_activate_deactivate_buttons(self):
    2020         self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
    2021         self.browser.open(self.student_path)
    2022         self.browser.getLink("Deactivate").click()
    2023         self.assertTrue(
    2024             'Student account has been deactivated.' in self.browser.contents)
    2025         self.assertTrue(
    2026             'Base Data (account deactivated)' in self.browser.contents)
    2027         self.assertTrue(self.student.suspended)
    2028         self.browser.getLink("Activate").click()
    2029         self.assertTrue(
    2030             'Student account has been activated.' in self.browser.contents)
    2031         self.assertFalse(
    2032             'Base Data (account deactivated)' in self.browser.contents)
    2033         self.assertFalse(self.student.suspended)
    2034         # History messages have been added ...
    2035         self.browser.getLink("History").click()
    2036         self.assertTrue(
    2037             'Student account deactivated by Manager<br />' in self.browser.contents)
    2038         self.assertTrue(
    2039             'Student account activated by Manager<br />' in self.browser.contents)
    2040         # ... and actions have been logged.
    2041         logfile = os.path.join(
    2042             self.app['datacenter'].storage, 'logs', 'students.log')
    2043         logcontent = open(logfile).read()
    2044         self.assertTrue('zope.mgr - students.browser.StudentDeactivatePage - '
    2045                         'K1000000 - account deactivated' in logcontent)
    2046         self.assertTrue('zope.mgr - students.browser.StudentActivatePage - '
    2047                         'K1000000 - account activated' in logcontent)
    2048 
    2049     def test_student_transfer(self):
    2050         # Add second certificate
    2051         self.certificate2 = createObject('waeup.Certificate')
    2052         self.certificate2.code = u'CERT2'
    2053         self.certificate2.study_mode = 'ug_ft'
    2054         self.certificate2.start_level = 999
    2055         self.certificate2.end_level = 999
    2056         self.app['faculties']['fac1']['dep1'].certificates.addCertificate(
    2057             self.certificate2)
    2058 
    2059         # Add study level to old study course
    2060         studylevel = createObject(u'waeup.StudentStudyLevel')
    2061         studylevel.level = 200
    2062         self.student['studycourse'].addStudentStudyLevel(
    2063             self.certificate, studylevel)
    2064 
    2065         self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
    2066         self.browser.open(self.student_path)
    2067         self.browser.getLink("Transfer").click()
    2068         self.browser.getControl(name="form.certificate").value = ['CERT2']
    2069         self.browser.getControl(name="form.current_session").value = ['2011']
    2070         self.browser.getControl(name="form.current_level").value = ['200']
    2071         self.browser.getControl("Transfer").click()
    2072         self.assertTrue(
    2073             'Current level does not match certificate levels'
    2074             in self.browser.contents)
    2075         self.browser.getControl(name="form.current_level").value = ['999']
    2076         self.browser.getControl("Transfer").click()
    2077         self.assertTrue('Successfully transferred' in self.browser.contents)
    2078 
    2079         # Add study level to new study course
    2080         studylevel = createObject(u'waeup.StudentStudyLevel')
    2081         studylevel.level = 200
    2082         self.student['studycourse'].addStudentStudyLevel(
    2083             self.certificate, studylevel)
    2084 
    2085         # Edit and add pages are locked for old study courses
    2086         self.browser.open(self.student_path + '/studycourse/manage')
    2087         self.assertFalse('The requested form is locked' in self.browser.contents)
    2088         self.browser.open(self.student_path + '/studycourse_1/manage')
    2089         self.assertTrue('The requested form is locked' in self.browser.contents)
    2090 
    2091         self.browser.open(self.student_path + '/studycourse/start_session')
    2092         self.assertFalse('The requested form is locked' in self.browser.contents)
    2093         self.browser.open(self.student_path + '/studycourse_1/start_session')
    2094         self.assertTrue('The requested form is locked' in self.browser.contents)
    2095 
    2096         IWorkflowState(self.student).setState('school fee paid')
    2097         self.browser.open(self.student_path + '/studycourse/add')
    2098         self.assertFalse('The requested form is locked' in self.browser.contents)
    2099         self.browser.open(self.student_path + '/studycourse_1/add')
    2100         self.assertTrue('The requested form is locked' in self.browser.contents)
    2101 
    2102         self.browser.open(self.student_path + '/studycourse/200/manage')
    2103         self.assertFalse('The requested form is locked' in self.browser.contents)
    2104         self.browser.open(self.student_path + '/studycourse_1/200/manage')
    2105         self.assertTrue('The requested form is locked' in self.browser.contents)
    2106 
    2107         self.browser.open(self.student_path + '/studycourse/200/validate_courses')
    2108         self.assertFalse('The requested form is locked' in self.browser.contents)
    2109         self.browser.open(self.student_path + '/studycourse_1/200/validate_courses')
    2110         self.assertTrue('The requested form is locked' in self.browser.contents)
    2111 
    2112         self.browser.open(self.student_path + '/studycourse/200/reject_courses')
    2113         self.assertFalse('The requested form is locked' in self.browser.contents)
    2114         self.browser.open(self.student_path + '/studycourse_1/200/reject_courses')
    2115         self.assertTrue('The requested form is locked' in self.browser.contents)
    2116 
    2117         self.browser.open(self.student_path + '/studycourse/200/add')
    2118         self.assertFalse('The requested form is locked' in self.browser.contents)
    2119         self.browser.open(self.student_path + '/studycourse_1/200/add')
    2120         self.assertTrue('The requested form is locked' in self.browser.contents)
    2121 
    2122         self.browser.open(self.student_path + '/studycourse/200/edit')
    2123         self.assertFalse('The requested form is locked' in self.browser.contents)
    2124         self.browser.open(self.student_path + '/studycourse_1/200/edit')
    2125         self.assertTrue('The requested form is locked' in self.browser.contents)
    2126 
    21271890class StudentRequestPWTests(StudentsFullSetup):
    21281891    # Tests for student registration
     
    21311894
    21321895    def test_request_pw(self):
    2133         # Student with wrong number can't be found.
     1896        # Student with wrong reg_number can't be found.
    21341897        self.browser.open('http://localhost/app/requestpw')
    21351898        self.browser.getControl(name="form.firstname").value = 'Anna'
    2136         self.browser.getControl(name="form.number").value = 'anynumber'
     1899        self.browser.getControl(name="form.reg_number").value = 'anynumber'
    21371900        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
    2138         self.browser.getControl("Send login credentials").click()
     1901        self.browser.getControl("Get login credentials").click()
    21391902        self.assertTrue('No student record found.'
    21401903            in self.browser.contents)
     
    21431906        self.browser.open('http://localhost/app/requestpw')
    21441907        self.browser.getControl(name="form.firstname").value = 'Johnny'
    2145         self.browser.getControl(name="form.number").value = '123'
     1908        self.browser.getControl(name="form.reg_number").value = '123'
    21461909        self.browser.getControl(name="form.email").value = 'xx@yy.zz'
    2147         self.browser.getControl("Send login credentials").click()
     1910        self.browser.getControl("Get login credentials").click()
    21481911        self.assertTrue('No student record found.'
    21491912            in self.browser.contents)
     
    21511914        # password has been set and used.
    21521915        self.browser.getControl(name="form.firstname").value = 'Anna'
    2153         self.browser.getControl(name="form.number").value = '123'
    2154         self.browser.getControl("Send login credentials").click()
     1916        self.browser.getControl(name="form.reg_number").value = '123'
     1917        self.browser.getControl("Get login credentials").click()
    21551918        self.assertTrue('Your password has already been set and used.'
    21561919            in self.browser.contents)
     
    21591922        # The firstname field, used for verification, is not case-sensitive.
    21601923        self.browser.getControl(name="form.firstname").value = 'aNNa'
    2161         self.browser.getControl(name="form.number").value = '123'
     1924        self.browser.getControl(name="form.reg_number").value = '123'
    21621925        self.browser.getControl(name="form.email").value = 'new@yy.zz'
    2163         self.browser.getControl("Send login credentials").click()
     1926        self.browser.getControl("Get login credentials").click()
    21641927        # Yeah, we succeded ...
    2165         self.assertTrue('Your password request was successful.'
    2166             in self.browser.contents)
    2167         # We can also use the matric_number instead.
    2168         self.browser.open('http://localhost/app/requestpw')
    2169         self.browser.getControl(name="form.firstname").value = 'aNNa'
    2170         self.browser.getControl(name="form.number").value = '234'
    2171         self.browser.getControl(name="form.email").value = 'new@yy.zz'
    2172         self.browser.getControl("Send login credentials").click()
    21731928        self.assertTrue('Your password request was successful.'
    21741929            in self.browser.contents)
     
    21791934            email=('new@yy.zz', 'new@yy.zz')))
    21801935        self.assertEqual(self.student,results[0])
    2181         logfile = os.path.join(
    2182             self.app['datacenter'].storage, 'logs', 'main.log')
    2183         logcontent = open(logfile).read()
    2184         self.assertTrue('zope.anybody - students.browser.StudentRequestPasswordPage - '
    2185                         '234 (K1000000) - new@yy.zz' in logcontent)
    21861936        return
  • main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/students/tests/test_dynamicroles.py

    r9209 r9211  
    2525    Test as APRMTest, Manageable)
    2626from waeup.kofa.testing import FunctionalLayer
    27 from waeup.kofa.app import University
    2827from waeup.kofa.students.tests.test_browser import StudentsFullSetup
    2928from waeup.kofa.students import Student, StudentPrincipalRoleManager
     
    4948    def setUp(self):
    5049        super(StudentPrincipalRoleManagerFunctionalTests, self).setUp()
     50        self.officer_role = 'waeup.StudentsClearanceOfficer'
    5151        # assign clearance permissions for a virtual officer
    5252        prm = IPrincipalRoleManager(self.app['faculties']['fac1']['dep1'])
    5353        prm.assignRoleToPrincipal('waeup.local.ClearanceOfficer', 'alice')
    54         prm.assignRoleToPrincipal('waeup.local.PGClearanceOfficer', 'bob')
    55         prm.assignRoleToPrincipal('waeup.local.UGClearanceOfficer', 'anne')
    5654        return
    5755
     
    7674        # student
    7775        prm = IPrincipalRoleManager(self.student)
    78         result = prm.getRolesForPrincipal('claus')
     76        result = prm.getRolesForPrincipal('bob')
    7977        self.assertEqual(result, [])
    8078        return
     
    8583        prm = IPrincipalRoleManager(self.student)
    8684        result = prm.getRolesForPrincipal('alice')
    87         self.assertEqual(result, [('waeup.StudentsClearanceOfficer', Allow)])
    88         # Student is a UG student
    89         self.assertFalse(self.student.is_postgrad)
    90         result = prm.getRolesForPrincipal('bob')
    91         self.assertEqual(result, [('waeup.StudentsOfficer', Allow)])
    92         result = prm.getRolesForPrincipal('anne')
    93         self.assertEqual(result, [('waeup.StudentsClearanceOfficer', Allow)])
    94         # Make student a PG student
    95         self.certificate.study_mode = u'pg_ft'
    96         self.assertTrue(self.student.is_postgrad)
    97         result = prm.getRolesForPrincipal('bob')
    98         # The dynamic roles changed
    99         self.assertEqual(result, [('waeup.StudentsClearanceOfficer', Allow)])
    100         result = prm.getRolesForPrincipal('anne')
    101         self.assertEqual(result, [('waeup.StudentsOfficer', Allow)])
     85        self.assertEqual(result, [(self.officer_role, Allow)])
    10286        return
  • main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/students/tests/test_export.py

    r9209 r9211  
    4444            'adm_code,clearance_locked,clr_code,date_of_birth,email,employer,'
    4545            'firstname,lastname,matric_number,middlename,nationality,'
    46             'perm_address,phone,reg_number,sex,student_id,suspended,password,'
     46            'perm_address,phone,reg_number,sex,student_id,password,'
    4747            'state,history,certcode\r\n'
    4848
    4949            'my adm code,0,my clr code,1981-02-04#,anna@sample.com,,'
    50             'Anna,Tester,234,M.,NG,"Studentroad 21\nLagos 123456\n",'
    51             '+234-123-12345#,123,f,A111111,0,,created'
     50            'Anna,Tester,M123456,M.,NG,"Studentroad 21\nLagos 123456\n",'
     51            '+234-123-12345,123456,f,A111111,,created'
    5252            in result
    5353            )
     
    6464            'adm_code,clearance_locked,clr_code,date_of_birth,email,employer,'
    6565            'firstname,lastname,matric_number,middlename,nationality,'
    66             'perm_address,phone,reg_number,sex,student_id,suspended,password,'
     66            'perm_address,phone,reg_number,sex,student_id,password,'
    6767            'state,history,certcode\r\n'
    6868
    6969            'my adm code,0,my clr code,1981-02-04#,anna@sample.com,,'
    70             'Anna,Tester,234,M.,NG,"Studentroad 21\nLagos 123456\n",'
    71             '+234-123-12345#,123,f,A111111,0,,created'
     70            'Anna,Tester,M123456,M.,NG,"Studentroad 21\nLagos 123456\n",'
     71            '+234-123-12345,123456,f,A111111,,created'
    7272            in result
    7373            )
     
    8383            'adm_code,clearance_locked,clr_code,date_of_birth,email,employer,'
    8484            'firstname,lastname,matric_number,middlename,nationality,'
    85             'perm_address,phone,reg_number,sex,student_id,suspended,password,'
     85            'perm_address,phone,reg_number,sex,student_id,password,'
    8686            'state,history,certcode\r\n'
    8787
    8888            'my adm code,0,my clr code,1981-02-04#,anna@sample.com,,'
    89             'Anna,Tester,234,M.,NG,"Studentroad 21\nLagos 123456\n",'
    90             '+234-123-12345#,123,f,A111111,0,,created'
     89            'Anna,Tester,M123456,M.,NG,"Studentroad 21\nLagos 123456\n",'
     90            '+234-123-12345,123456,f,A111111,,created'
    9191            in result
    9292            )
     
    127127            'entry_mode,entry_session,previous_verdict,student_id\r\n'
    128128
    129             ',,,0,,,0,\r\n'
     129            ',,,NY,,,NY,\r\n'
    130130            )
    131131        return
     
    144144            'entry_mode,entry_session,previous_verdict,student_id\r\n'
    145145
    146             'CERT1,200,2012,0,ug_ft,2010,0,A111111\r\n'
     146            'CERT1,200,2012,NY,ug_ft,2010,NY,A111111\r\n'
    147147            )
    148148        return
     
    160160            'entry_mode,entry_session,previous_verdict,student_id\r\n'
    161161
    162             'CERT1,200,2012,0,ug_ft,2010,0,A111111\r\n'
     162            'CERT1,200,2012,NY,ug_ft,2010,NY,A111111\r\n'
    163163            )
    164164        return
     
    175175            'entry_mode,entry_session,previous_verdict,student_id\r\n'
    176176
    177             'CERT1,200,2012,0,ug_ft,2010,0,A111111\r\n'
     177            'CERT1,200,2012,NY,ug_ft,2010,NY,A111111\r\n'
    178178            )
    179179        return
     
    209209        self.assertEqual(
    210210            result,
    211             'level,level_session,level_verdict,validated_by,validation_date,'
    212             'student_id\r\n'
    213             ',,0,,,\r\n'
     211            'level,level_session,level_verdict,student_id\r\n'
     212            ',,NY,\r\n'
    214213            )
    215214        return
     
    226225        self.assertEqual(
    227226            result,
    228             'level,level_session,level_verdict,validated_by,validation_date,'
    229             'student_id\r\n'
    230             '100,2012,A,,,A111111\r\n'
     227            'level,level_session,level_verdict,student_id\r\n'
     228            '100,2012,A,A111111\r\n'
    231229            )
    232230        return
     
    241239        self.assertEqual(
    242240            result,
    243             'level,level_session,level_verdict,validated_by,validation_date,'
    244             'student_id\r\n'
    245             '100,2012,A,,,A111111\r\n'
     241            'level,level_session,level_verdict,student_id\r\n'
     242            '100,2012,A,A111111\r\n'
    246243            )
    247244        return
     
    255252        self.assertEqual(
    256253            result,
    257             'level,level_session,level_verdict,validated_by,validation_date,'
    258             'student_id\r\n'
    259             '100,2012,A,,,A111111\r\n'
     254            'level,level_session,level_verdict,student_id\r\n'
     255            '100,2012,A,A111111\r\n'
    260256            )
    261257        return
     
    375371        self.assertEqual(
    376372            result,
    377             'ac,amount_auth,creation_date,p_category,p_current,p_id,'
     373            'ac,amount_auth,creation_date,p_category,p_id,'
    378374            'p_item,p_level,p_session,p_state,payment_date,r_amount_approved,'
    379375            'r_code,r_desc,student_id\r\n'
    380376
    381             ',0.0,2012-04-01 13:12:01,schoolfee,1,,,,,unpaid,,0.0,,,\r\n'
     377            ',0.0,2012-04-01 13:12:01,schoolfee,,,,,unpaid,,0.0,,,\r\n'
    382378            )
    383379        return
     
    393389        self.assertEqual(
    394390            result,
    395             'ac,amount_auth,creation_date,p_category,p_current,p_id,'
     391            'ac,amount_auth,creation_date,p_category,p_id,'
    396392            'p_item,p_level,p_session,p_state,payment_date,r_amount_approved,'
    397393            'r_code,r_desc,student_id\r\n'
    398394
    399             '666,0.0,2012-04-01 13:12:01,schoolfee,1,my-id,'
     395            '666,0.0,2012-04-01 13:12:01,schoolfee,my-id,'
    400396            'p-item,100,2012,unpaid,2012-04-01 14:12:01,12.12,'
    401397            'r-code,,A111111\r\n'
     
    412408        self.assertEqual(
    413409            result,
    414             'ac,amount_auth,creation_date,p_category,p_current,p_id,'
     410            'ac,amount_auth,creation_date,p_category,p_id,'
    415411            'p_item,p_level,p_session,p_state,payment_date,r_amount_approved,'
    416412            'r_code,r_desc,student_id\r\n'
    417413
    418             '666,0.0,2012-04-01 13:12:01,schoolfee,1,my-id,'
     414            '666,0.0,2012-04-01 13:12:01,schoolfee,my-id,'
    419415            'p-item,100,2012,unpaid,2012-04-01 14:12:01,12.12,'
    420416            'r-code,,A111111\r\n'
     
    431427        self.assertEqual(
    432428            result,
    433             'ac,amount_auth,creation_date,p_category,p_current,p_id,'
     429            'ac,amount_auth,creation_date,p_category,p_id,'
    434430            'p_item,p_level,p_session,p_state,payment_date,r_amount_approved,'
    435431            'r_code,r_desc,student_id\r\n'
    436432
    437             '666,0.0,2012-04-01 13:12:01,schoolfee,1,my-id,'
     433            '666,0.0,2012-04-01 13:12:01,schoolfee,my-id,'
    438434            'p-item,100,2012,unpaid,2012-04-01 14:12:01,12.12,'
    439435            'r-code,,A111111\r\n'
  • main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/students/tests/test_student.py

    r9209 r9211  
    2121import re
    2222import unittest
    23 import grok
    2423from cStringIO import StringIO
    2524from datetime import tzinfo
    26 from zope.component import getUtility, queryUtility, createObject
    27 from zope.catalog.interfaces import ICatalog
     25from zope.component import getUtility
    2826from zope.component.interfaces import IFactory
    29 from zope.event import notify
    3027from zope.interface import verify
    31 from zope.schema.interfaces import RequiredMissing
    3228from waeup.kofa.interfaces import IExtFileStore, IFileStoreNameChooser
    3329from waeup.kofa.students.export import EXPORTER_NAMES
     
    133129        studylevel = StudentStudyLevel()
    134130        self.assertRaises(
    135             TypeError, studylevel.addCourseTicket, department, department)
     131            TypeError, studylevel.addCourseTicket, department)
    136132
    137133    def test_booking_date(self):
     
    240236        return
    241237
    242 class StudentTransferTests(StudentImportExportSetup):
    243 
    244     layer = FunctionalLayer
    245 
    246     def setUp(self):
    247         super(StudentTransferTests, self).setUp()
    248 
    249         # Add additional certificate
    250         self.certificate2 = createObject('waeup.Certificate')
    251         self.certificate2.code = 'CERT2'
    252         self.certificate2.application_category = 'basic'
    253         self.certificate2.start_level = 200
    254         self.certificate2.end_level = 500
    255         self.app['faculties']['fac1']['dep1'].certificates.addCertificate(
    256             self.certificate2)
    257 
    258         # Add student with subobjects
    259         student = Student()
    260         self.app['students'].addStudent(student)
    261         student = self.setup_student(student)
    262         notify(grok.ObjectModifiedEvent(student))
    263         self.student = self.app['students'][student.student_id]
    264         return
    265 
    266     def test_transfer_student(self):
    267         self.assertRaises(
    268             RequiredMissing, self.student.transfer, self.certificate2)
    269         error = self.student.transfer(self.certificate2, current_session=1000)
    270         self.assertTrue(error == -1)
    271         error = self.student.transfer(self.certificate2, current_session=2013)
    272         self.assertTrue(error == None)
    273         self.assertEqual(self.student['studycourse_1'].certificate.code, 'CERT1')
    274         self.assertEqual(self.student['studycourse'].certificate.code, 'CERT2')
    275         self.assertEqual(self.student['studycourse_1'].current_session, 2012)
    276         self.assertEqual(self.student['studycourse'].current_session, 2013)
    277         self.assertEqual(self.student['studycourse'].entry_session,
    278             self.student['studycourse_1'].entry_session)
    279         self.assertEqual(self.student['studycourse_1'].__name__, 'studycourse_1')
    280         logfile = os.path.join(
    281             self.app['datacenter'].storage, 'logs', 'students.log')
    282         logcontent = open(logfile).read()
    283         self.assertTrue('system - K1000000 - transferred from CERT1 to CERT2'
    284             in logcontent)
    285         messages = ' '.join(self.student.history.messages)
    286         self.assertMatches(
    287             '...<YYYY-MM-DD hh:mm:ss> UTC - '
    288             'Transferred from CERT1 to CERT2 by system', messages)
    289 
    290         # The students_catalog has been updated.
    291         cat = queryUtility(ICatalog, name='students_catalog')
    292         results = cat.searchResults(certcode=('CERT1', 'CERT1'))
    293         results = [x for x in results]
    294         self.assertEqual(len(results), 0)
    295         results = cat.searchResults(certcode=('CERT2', 'CERT2'))
    296         results = [x for x in results]
    297         self.assertEqual(len(results), 1)
    298         assert results[0] is self.app['students'][self.student.student_id]
    299         results = cat.searchResults(current_session=(2013,2013))
    300         results = [x for x in results]
    301         self.assertEqual(len(results), 1)
    302         assert results[0] is self.app['students'][self.student.student_id]
    303 
    304         # Students can be transferred (only) two times.
    305         error = self.student.transfer(self.certificate,
    306             current_session=2013)
    307         self.assertTrue(error == None)
    308         error = self.student.transfer(self.certificate2,
    309             current_session=2013)
    310         self.assertTrue(error == -3)
    311         self.assertEqual([i for i in self.student.keys()],
    312             [u'accommodation', u'payments', u'studycourse',
    313              u'studycourse_1', u'studycourse_2'])
    314 
    315         # The students_catalog has been updated again.
    316         cat = queryUtility(ICatalog, name='students_catalog')
    317         results = cat.searchResults(certcode=('CERT1', 'CERT1'))
    318         results = [x for x in results]
    319         self.assertEqual(len(results), 1)
    320         assert results[0] is self.app['students'][self.student.student_id]
    321         return
    322238
    323239class StudentFactoryTest(FunctionalTestCase):
  • main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/students/utils.py

    r9209 r9211  
    1919"""
    2020import grok
     21from random import SystemRandom as r
    2122from time import time
     23from datetime import datetime
     24from zope.i18n import translate
     25from zope.component import getUtility, createObject
     26from reportlab.pdfgen import canvas
    2227from reportlab.lib import colors
    2328from reportlab.lib.units import cm
     29from reportlab.lib.enums import TA_RIGHT
    2430from reportlab.lib.pagesizes import A4
    25 from reportlab.lib.styles import getSampleStyleSheet
    26 from reportlab.platypus import Paragraph, Image, Table, Spacer
    27 from zope.component import getUtility, createObject
     31from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
     32from reportlab.platypus import (Frame, Paragraph, Image, PageBreak, Table,
     33                                Spacer)
     34from reportlab.platypus.tables import TableStyle
     35from reportlab.platypus.flowables import PageBreak
     36from zope.component import getUtility
    2837from zope.formlib.form import setUpEditWidgets
    29 from zope.i18n import translate
     38
    3039from waeup.kofa.interfaces import (
    3140    IExtFileStore, IKofaUtils, RETURNING, PAID, CLEARED)
    3241from waeup.kofa.interfaces import MessageFactory as _
    3342from waeup.kofa.students.interfaces import IStudentsUtils
     43from waeup.kofa.utils.helpers import now
    3444
    3545SLIP_STYLE = [
     
    117127    #data.append([Spacer(1, 12)])
    118128    portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
    119 
    120     f_label = formatted_label(size=12) % _('Name')
    121     f_label = Paragraph(f_label, style["Normal"])
    122     f_text = formatted_text(studentview.context.display_fullname, size=12)
    123     f_text = Paragraph(f_text, style["Normal"])
    124     data_right.append([f_label,f_text])
    125 
    126129    for widget in studentview.widgets:
    127         if 'name' in widget.name:
     130        if widget.name == 'form.adm_code':
    128131            continue
    129132        f_label = formatted_label(size=12) % translate(
     
    134137        f_text = Paragraph(f_text, style["Normal"])
    135138        data_right.append([f_label,f_text])
    136 
    137     if hasattr(studentview.context, 'certcode'):
    138         f_label = formatted_label(size=12) % _('Study Course')
    139         f_label = Paragraph(f_label, style["Normal"])
    140         f_text = formatted_text(
    141             studentview.context['studycourse'].certificate.longtitle(), size=12)
    142         f_text = Paragraph(f_text, style["Normal"])
    143         data_right.append([f_label,f_text])
    144 
    145         f_label = formatted_label(size=12) % _('Department')
    146         f_label = Paragraph(f_label, style["Normal"])
    147         f_text = formatted_text(
    148             studentview.context[
    149             'studycourse'].certificate.__parent__.__parent__.longtitle(),
    150             size=12)
    151         f_text = Paragraph(f_text, style["Normal"])
    152         data_right.append([f_label,f_text])
    153 
    154         f_label = formatted_label(size=12) % _('Faculty')
    155         f_label = Paragraph(f_label, style["Normal"])
    156         f_text = formatted_text(
    157             studentview.context[
    158             'studycourse'].certificate.__parent__.__parent__.__parent__.longtitle(),
    159             size=12)
    160         f_text = Paragraph(f_text, style["Normal"])
    161         data_right.append([f_label,f_text])
    162 
    163139    table_left = Table(data_left,style=SLIP_STYLE)
    164140    table_right = Table(data_right,style=SLIP_STYLE, colWidths=[5*cm, 6*cm])
     
    189165    return table
    190166
    191 def get_signature_table(signatures, lang='en'):
    192     """Return a reportlab table containing signature fields (with date).
    193     """
    194     style = getSampleStyleSheet()
    195     space_width = 0.4  # width in cm of space between signatures
    196     table_width = 16.0 # supposed width of signature table in cms
    197     # width of signature cells in cm...
    198     sig_col_width = table_width - ((len(signatures) - 1) * space_width)
    199     sig_col_width = sig_col_width / len(signatures)
    200     data = []
    201     col_widths = [] # widths of columns
    202 
    203     sig_style = [
    204         ('VALIGN',(0,-1),(-1,-1),'TOP'),
    205         ('FONT', (0,0), (-1,-1), 'Helvetica-BoldOblique', 12),
    206         ('BOTTOMPADDING', (0,0), (-1,0), 36),
    207         ('TOPPADDING', (0,-1), (-1,-1), 0),
    208         ]
    209     for num, elem in enumerate(signatures):
    210         # draw a line above each signature cell (not: empty cells in between)
    211         sig_style.append(
    212             ('LINEABOVE', (num*2,-1), (num*2, -1), 1, colors.black))
    213 
    214     row = []
    215     for signature in signatures:
    216         row.append(trans(_('Date:'), lang))
    217         row.append('')
    218         if len(signatures) > 1:
    219             col_widths.extend([sig_col_width*cm, space_width*cm])
    220         else:
    221             col_widths.extend([sig_col_width/2*cm, sig_col_width/2*cm])
    222             row.append('') # empty spaceholder on right
    223     data.append(row[:-1])
    224     data.extend(([''],)*3) # insert 3 empty rows...
    225     row = []
    226     for signature in signatures:
    227         row.append(Paragraph(trans(signature, lang), style["Normal"]))
    228         row.append('')
    229     data.append(row[:-1])
    230     table = Table(data, style=sig_style, repeatRows=len(data),
    231                   colWidths=col_widths)
    232     return table
    233 
    234167def docs_as_flowables(view, lang='en'):
    235168    """Create reportlab flowables out of scanned docs.
     
    257190            if img_path is None:
    258191                pass
    259             elif not img_path[-4:] in ('.jpg', '.JPG'):
     192            elif not img_path.endswith('.jpg'):
    260193                # reportlab requires jpg images, I think.
    261                 f_text = Paragraph('%s (not displayable)' % (
     194                f_text = Paragraph('%s (Not displayable)' % (
    262195                    viewlet.title,), ENTRY1_STYLE)
    263196            else:
     
    269202    return data
    270203
     204def insert_footer(pdf,width,style,text=None, number_of_pages=1):
     205      """Render the whole footer frame.
     206      """
     207      story = []
     208      frame_footer = Frame(1*cm,0,width-(2*cm),1*cm)
     209      tz = getUtility(IKofaUtils).tzinfo
     210      timestamp = now(tz).strftime("%d/%m/%Y %H:%M:%S %Z")
     211      left_text = '<font size=10>%s</font>' % timestamp
     212      story.append(Paragraph(left_text, style["Normal"]))
     213      frame_footer.addFromList(story,pdf)
     214      story = []
     215      frame_footer = Frame(1*cm,0,width-(2*cm),1*cm)
     216      portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
     217      right_text = translate(_('<font size=10>${a} Page ${b} of ${c}</font>',
     218          mapping = {'a':text, 'b':pdf.getPageNumber(), 'c':number_of_pages}),
     219          'waeup.kofa', target_language=portal_language)
     220      story.append(Paragraph(right_text, style["Right"]))
     221      frame_footer.addFromList(story,pdf)
     222
    271223class StudentsUtils(grok.GlobalUtility):
    272224    """A collection of methods subject to customization.
     
    275227
    276228    def getReturningData(self, student):
    277         """ Define what happens after school fee payment
     229        """ This method defines what happens after school fee payment
    278230        depending on the student's senate verdict.
    279231
     
    286238
    287239    def setReturningData(self, student):
    288         """ Define what happens after school fee payment
    289         depending on the student's senate verdict.
    290 
    291         This method folllows the same algorithm as getReturningData but
    292         it also sets the new values.
     240        """ This method defines what happens after school fee payment
     241        depending on the student's senate verdict. It folllows
     242        the same algorithm as getReturningData but it also sets the new
     243        values
     244
     245        In the base configuration current level is always increased
     246        by 100 no matter which verdict has been assigned.
    293247        """
    294248        new_session, new_level = self.getReturningData(student)
     
    296250        student['studycourse'].current_session = new_session
    297251        verdict = student['studycourse'].current_verdict
    298         student['studycourse'].current_verdict = '0'
     252        student['studycourse'].current_verdict = 'NY'
    299253        student['studycourse'].previous_verdict = verdict
    300254        return
    301255
    302     def setPaymentDetails(self, category, student,
    303             previous_session, previous_level):
     256    def setPaymentDetails(self, category, student):
    304257        """Create Payment object and set the payment data of a student for
    305258        the payment category specified.
    306259
    307260        """
     261        details = {}
    308262        p_item = u''
    309263        amount = 0.0
    310         if previous_session:
    311             p_session = previous_session
    312             p_level = previous_level
    313             p_current = False
    314         else:
    315             p_session = student['studycourse'].current_session
    316             p_level = student['studycourse'].current_level
    317             p_current = True
     264        error = u''
     265        p_session = student['studycourse'].current_session
     266        p_level = student['studycourse'].current_level
    318267        session = str(p_session)
    319268        try:
     
    327276            except (AttributeError, TypeError):
    328277                return _('Study course data are incomplete.'), None
    329             if previous_session:
    330                 if previous_session < student['studycourse'].entry_session:
    331                     return _('The previous session must not fall below '
    332                              'your entry session.'), None
    333                 if previous_session > student['studycourse'].current_session - 1:
    334                     return _('This is not a previous session.'), None
    335                 if previous_level == 100:
    336                     amount = getattr(certificate, 'school_fee_1', 0.0)
    337                 else:
    338                     amount = getattr(certificate, 'school_fee_2', 0.0)
    339             else:
    340                 if student.state == CLEARED:
    341                     amount = getattr(certificate, 'school_fee_1', 0.0)
    342                 elif student.state == RETURNING:
    343                     # In case of returning school fee payment the payment session
    344                     # and level contain the values of the session the student
    345                     # has paid for.
    346                     p_session, p_level = self.getReturningData(student)
    347                     amount = getattr(certificate, 'school_fee_2', 0.0)
    348                 elif student.is_postgrad and student.state == PAID:
    349                     # Returning postgraduate students also pay for the next session
    350                     # but their level always remains the same.
    351                     p_session += 1
    352                     amount = getattr(certificate, 'school_fee_2', 0.0)
     278            if student.state == CLEARED:
     279                amount = getattr(certificate, 'school_fee_1', 0.0)
     280            elif student.state == RETURNING:
     281                # In case of returning school fee payment the payment session
     282                # and level contain the values of the session the student
     283                # has paid for.
     284                p_session, p_level = self.getReturningData(student)
     285                amount = getattr(certificate, 'school_fee_2', 0.0)
     286            elif student.is_postgrad and student.state == PAID:
     287                # Returning postgraduate students also pay for the next session
     288                # but their level always remains the same.
     289                p_session += 1
     290                amount = getattr(certificate, 'school_fee_2', 0.0)
    353291        elif category == 'clearance':
    354             try:
    355                 p_item = student['studycourse'].certificate.code
    356             except (AttributeError, TypeError):
    357                 return _('Study course data are incomplete.'), None
     292            p_item = student['studycourse'].certificate.code
    358293            amount = academic_session.clearance_fee
    359294        elif category == 'bed_allocation':
     
    361296            amount = academic_session.booking_fee
    362297        if amount in (0.0, None):
    363             return _('Amount could not be determined.' +
    364                      ' Would you like to pay for a previous session?'), None
     298            return _(u'Amount could not be determined.'), None
    365299        for key in student['payments'].keys():
    366300            ticket = student['payments'][key]
     
    369303               ticket.p_item == p_item and \
    370304               ticket.p_session == p_session:
    371                   return _('This type of payment has already been made.' +
    372                            ' Would you like to pay for a previous session?'), None
     305                  return _('This type of payment has already been made.'), None
    373306        payment = createObject(u'waeup.StudentOnlinePayment')
    374         timestamp = ("%d" % int(time()*10000))[1:]
     307        timestamp = "%d" % int(time()*1000)
    375308        payment.p_id = "p%s" % timestamp
    376309        payment.p_category = category
     
    378311        payment.p_session = p_session
    379312        payment.p_level = p_level
    380         payment.p_current = p_current
    381313        payment.amount_auth = amount
    382314        return None, payment
     
    398330        entry_session = studycourse.entry_session
    399331        current_level = studycourse.current_level
    400         if None in (entry_session, current_level, certificate):
    401             return d
     332        if not (entry_session and current_level and certificate):
     333            return
    402334        end_level = certificate.end_level
    403         if current_level == 10:
    404             bt = 'pr'
    405         elif entry_session == grok.getSite()['hostels'].accommodation_session:
     335        if entry_session == grok.getSite()['hostels'].accommodation_session:
    406336            bt = 'fr'
    407337        elif current_level >= end_level:
     
    425355        return available_beds[0]
    426356
    427     def renderPDFAdmissionLetter(self, view, student=None):
    428         """Render pdf admission letter.
    429         """
    430         # XXX: we have to fix the import problems here.
    431         from waeup.kofa.browser.interfaces import IPDFCreator
    432         from waeup.kofa.browser.pdf import format_html, NOTE_STYLE
    433         if student is None:
    434             return
    435         style = getSampleStyleSheet()
    436         creator = getUtility(IPDFCreator)
    437         data = []
    438         doc_title = view.label
    439         author = '%s (%s)' % (view.request.principal.title,
    440                               view.request.principal.id)
    441         footer_text = view.label
    442         if getattr(student, 'student_id', None) is not None:
    443             footer_text = "%s - %s - " % (student.student_id, footer_text)
    444 
    445         # Admission text
    446         portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
    447         inst_name = grok.getSite()['configuration'].name
    448         text = trans(_(
    449             'This is to inform you that you have been provisionally'
    450             ' admitted into ${a} as follows:', mapping = {'a': inst_name}),
    451             portal_language)
    452         html = format_html(text)
    453         data.append(Paragraph(html, NOTE_STYLE))
    454         data.append(Spacer(1, 20))
    455 
    456         # Student data
    457         data.append(render_student_data(view))
    458 
    459         # Insert history
    460         data.append(Spacer(1, 20))
    461         datelist = student.history.messages[0].split()[0].split('-')
    462         creation_date = u'%s/%s/%s' % (datelist[2], datelist[1], datelist[0])
    463         text = trans(_(
    464             'Your Kofa student record was created on ${a}.',
    465             mapping = {'a': creation_date}),
    466             portal_language)
    467         html = format_html(text)
    468         data.append(Paragraph(html, NOTE_STYLE))
    469 
    470         # Create pdf stream
    471         view.response.setHeader(
    472             'Content-Type', 'application/pdf')
    473         pdf_stream = creator.create_pdf(
    474             data, None, doc_title, author=author, footer=footer_text,
    475             note=None)
    476         return pdf_stream
    477 
    478357    def renderPDF(self, view, filename='slip.pdf', student=None,
    479358                  studentview=None, tableheader=None, tabledata=None,
    480                   note=None, signatures=None):
     359                  note=None):
    481360        """Render pdf slips for various pages.
    482361        """
     
    494373            footer_text = "%s - %s - " % (student.student_id, footer_text)
    495374
    496         # Insert history
    497         if not filename.startswith('payment'):
    498             data.extend(creator.fromStringList(student.history.messages))
    499 
    500375        # Insert student data table
    501376        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
     
    506381
    507382        # Insert widgets
    508         if view.form_fields:
    509             data.append(Paragraph(view.title, style["Heading3"]))
    510             portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
    511             separators = getattr(self, 'SEPARATORS_DICT', {})
    512             table = creator.getWidgetsTable(
    513                 view.form_fields, view.context, None, lang=portal_language,
    514                 separators=separators)
    515             data.append(table)
     383        data.append(Paragraph(view.title, style["Heading3"]))
     384        portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE
     385        separators = getattr(self, 'SEPARATORS_DICT', {})
     386        table = creator.getWidgetsTable(
     387            view.form_fields, view.context, None, lang=portal_language,
     388            separators=separators)
     389        data.append(table)
    516390
    517391        # Insert scanned docs
     
    525399            contenttable = render_table_data(tableheader,tabledata)
    526400            data.append(contenttable)
    527 
    528         # Insert signatures
    529         if signatures:
    530             data.append(Spacer(1, 20))
    531             signaturetable = get_signature_table(signatures)
    532             data.append(signaturetable)
    533401
    534402        view.response.setHeader(
     
    544412
    545413    VERDICTS_DICT = {
    546         '0': _('(not yet)'),
     414        'NY': _('(not yet)'),
    547415        'A': 'Successful student',
    548416        'B': 'Student with carryover courses',
  • main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/students/viewlets.py

    r9209 r9211  
    1 3## $Id$
     1## $Id$
    22##
    33## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
     
    150150
    151151class ContactActionButton(ManageActionButton):
    152     grok.order(5)
     152    grok.order(4)
    153153    grok.context(IStudent)
    154154    grok.view(StudentBaseDisplayFormPage)
     
    166166    target = 'manage_base'
    167167
    168 class AdmissionSlipActionButton(ManageActionButton):
    169     grok.order(4)
    170     grok.context(IStudent)
    171     grok.view(StudentBaseDisplayFormPage)
    172     grok.require('waeup.viewStudent')
    173     icon = 'actionicon_pdf.png'
    174     text = _('Download admission letter')
    175     target = 'admission_slip.pdf'
    176 
    177 class StudentTransfernButton(ManageActionButton):
    178     grok.order(6)
    179     grok.context(IStudent)
    180     grok.view(StudentBaseDisplayFormPage)
    181     grok.require('waeup.manageStudent')
    182     text = _('Transfer student')
    183     target = 'transfer'
    184     icon = 'actionicon_redo.png'
    185 
    186 class StudentDeactivateActionButton(ManageActionButton):
    187     grok.order(7)
    188     grok.context(IStudent)
    189     grok.view(StudentBaseDisplayFormPage)
    190     grok.require('waeup.manageStudent')
    191     text = _('Deactivate account')
    192     target = 'deactivate'
    193     icon = 'actionicon_traffic_lights_red.png'
    194 
    195     @property
    196     def target_url(self):
    197         if self.context.suspended:
    198             return ''
    199         return self.view.url(self.view.context, self.target)
    200 
    201     @property
    202     def onclick(self):
    203         return "return window.confirm(%s);" % _(
    204             "'A history message will be added. Are you sure?'")
    205 
    206 class StudentActivateActionButton(ManageActionButton):
    207     grok.order(7)
    208     grok.context(IStudent)
    209     grok.view(StudentBaseDisplayFormPage)
    210     grok.require('waeup.manageStudent')
    211     text = _('Activate account')
    212     target = 'activate'
    213     icon = 'actionicon_traffic_lights_green.png'
    214 
    215     @property
    216     def target_url(self):
    217         if not self.context.suspended:
    218             return ''
    219         return self.view.url(self.view.context, self.target)
    220 
    221     @property
    222     def onclick(self):
    223         return "return window.confirm(%s);" % _(
    224             "'A history message will be added. Are you sure?'")
    225 
    226168class StudentClearanceManageActionButton(ManageActionButton):
    227169    grok.order(1)
     
    289231    target = 'view_personal'
    290232
    291 class StudentPersonalManageActionButton(ManageActionButton):
     233class StudentPersonalEditActionButton(ManageActionButton):
    292234    grok.order(1)
    293235    grok.context(IStudent)
    294236    grok.view(StudentPersonalDisplayFormPage)
    295     grok.require('waeup.manageStudent')
    296     text = _('Manage')
    297     target = 'manage_personal'
    298 
    299 class StudentPersonalEditActionButton(ManageActionButton):
    300     grok.order(2)
    301     grok.context(IStudent)
    302     grok.view(StudentPersonalDisplayFormPage)
    303     grok.require('waeup.handleStudent')
     237    grok.require('waeup.viewStudent')
    304238    text = _('Edit')
    305239    target = 'edit_personal'
     
    313247    target = 'manage'
    314248
    315     @property
    316     def target_url(self):
    317         if self.context.is_current:
    318             return self.view.url(self.view.context, self.target)
    319         return False
    320 
    321249class StudyLevelManageActionButton(ManageActionButton):
    322250    grok.order(1)
     
    326254    text = _('Manage')
    327255    target = 'manage'
    328 
    329     @property
    330     def target_url(self):
    331         is_current = self.context.__parent__.is_current
    332         if not is_current:
    333             return ''
    334         return self.view.url(self.view.context, self.target)
    335256
    336257class StudentValidateCoursesActionButton(ManageActionButton):
     
    345266    @property
    346267    def target_url(self):
    347         is_current = self.context.__parent__.is_current
    348268        if self.context.student.state != REGISTERED or \
    349             str(self.context.__parent__.current_level) != self.context.__name__ or\
    350             not is_current:
     269            str(self.context.__parent__.current_level) != self.context.__name__:
    351270            return ''
    352271        return self.view.url(self.view.context, self.target)
     
    363282    @property
    364283    def target_url(self):
    365         is_current = self.context.__parent__.is_current
    366284        if self.context.student.state not in (VALIDATED, REGISTERED) or \
    367             str(self.context.__parent__.current_level) != self.context.__name__ or\
    368             not is_current:
     285            str(self.context.__parent__.current_level) != self.context.__name__:
    369286            return ''
    370287        return self.view.url(self.view.context, self.target)
     
    378295    text = _('Download course registration slip')
    379296    target = 'course_registration.pdf'
    380 
    381     @property
    382     def target_url(self):
    383         is_current = self.context.__parent__.is_current
    384         if not is_current:
    385             return ''
    386         return self.view.url(self.view.context, self.target)
    387297
    388298class CourseTicketManageActionButton(ManageActionButton):
     
    403313
    404314class PaymentReceiptActionButton(ManageActionButton):
    405     grok.order(9) # This button should always be the last one.
     315    grok.order(1)
    406316    grok.context(IStudentOnlinePayment)
    407317    grok.view(OnlinePaymentDisplayFormPage)
     
    417327        return self.view.url(self.view.context, self.target)
    418328
     329
    419330class ApprovePaymentActionButton(ManageActionButton):
    420     grok.order(8)
     331    grok.order(2)
    421332    grok.context(IStudentOnlinePayment)
    422333    grok.view(OnlinePaymentDisplayFormPage)
     
    526437    grok.require('waeup.handleStudent')
    527438    icon = 'actionicon_start.gif'
    528     text = _('Start new session')
     439    text = _('Start session')
    529440    target = 'start_session'
    530441
    531442    @property
    532443    def target_url(self):
    533         if self.context.next_session_allowed and self.context.is_current:
     444        if self.context.next_session_allowed:
    534445            return self.view.url(self.view.context, self.target)
    535446        return False
     
    549460        condition2 = str(student['studycourse'].current_level) in \
    550461            self.view.context.keys()
    551         condition3 = not self.context.is_current
    552         if condition1 or condition2 or condition3:
     462        if condition1 or condition2:
    553463            return ''
    554464        return self.view.url(self.view.context, self.target)
     
    559469    grok.view(StudyLevelDisplayFormPage)
    560470    grok.require('waeup.handleStudent')
    561     text = _('Edit course list')
     471    text = _('Add and remove courses')
    562472    target = 'edit'
    563473
     
    568478        condition2 = student[
    569479            'studycourse'].current_level != self.view.context.level
    570         is_current = self.context.__parent__.is_current
    571         if condition1 or condition2 or not is_current:
     480        if condition1 or condition2:
    572481            return ''
    573482        return self.view.url(self.view.context, self.target)
     
    633542    @property
    634543    def targets(self):
    635         student = grok.getSite()['students'][self.request.principal.id]
    636         student_url = self.view.url(student)
    637         app_slip = getUtility(IExtFileStore).getFileByContext(
    638             student, 'application_slip')
     544        student_url = self.view.application_url() + (
     545            '/students/%s' % self.request.principal.id)
     546        #app_slip = getUtility(IExtFileStore).getFileByContext(
     547        #    self.context.student, 'application_slip')
    639548        targets = []
    640         if app_slip:
    641             targets = [{'url':student_url + '/application_slip', 'title':'Application Slip'},]
     549        #if app_slip:
     550        #    targets = [{'url':student_url + '/application_slip', 'title':'Application Slip'},]
    642551        targets += [
    643552            {'url':student_url, 'title':'Base Data'},
  • main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/students/vocabularies.py

    r9209 r9211  
    3636nats_vocab = SimpleKofaVocabulary(*COUNTRIES)
    3737
    38 def study_levels(context):
    39     certificate = getattr(context, 'certificate', None)
    40     if  certificate is not None:
    41         start_level = int(certificate.start_level)
    42         end_level = int(certificate.end_level)
     38def study_levels(studycourse):
     39    if studycourse.certificate is not None:
     40        start_level = int(studycourse.certificate.start_level)
     41        end_level = int(studycourse.certificate.end_level)
    4342        if start_level == 999 or end_level == 999:
    4443            levels = [999]
     
    5150    else:
    5251        # default level range
    53         levels = [10, ]
    54         levels += [level for level in range(100,1000,10) if level % 100 < 30]
    55         levels.append(999)
     52        levels = [level for level in range(100,1000,10) if level % 100 < 30]
    5653    return levels
    5754
     
    7168
    7269    def getTitle(self, context, value):
    73         certificate = getattr(context, 'certificate', None)
    74         if certificate is not None:
    75             start_level = int(certificate.start_level)
    76             end_level = int(certificate.end_level)
     70        if context.certificate is not None:
     71            start_level = int(context.certificate.start_level)
     72            end_level = int(context.certificate.end_level)
    7773        else:
    7874            # default level range
    79             start_level = 10
     75            start_level = 100
    8076            end_level = 1000
    8177        if start_level == 999 or end_level == 999:
     
    8379                return _('Error: wrong level id ${value}',
    8480                    mapping={'value': value})
    85         if value == 999:
    8681            return course_levels.by_value[999].title
    8782        if value < start_level or value > end_level + 120:
  • main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/students/workflow.py

    r9209 r9211  
    22"""
    33import grok
    4 from datetime import datetime
    54from zope.component import getUtility
    65from hurry.workflow.workflow import Transition, WorkflowState, NullCondition
     
    1312from waeup.kofa.workflow import KofaWorkflow, KofaWorkflowInfo
    1413from waeup.kofa.students.interfaces import IStudent, IStudentsUtils
    15 from waeup.kofa.utils.helpers import get_current_principal
    1614
    1715
    1816IMPORTABLE_STATES = (ADMITTED, CLEARANCE, REQUESTED, CLEARED, PAID, RETURNING,
    1917    REGISTERED, VALIDATED)
    20 
    21 FORBIDDEN_POSTGRAD_STATES = (RETURNING, REGISTERED, VALIDATED)
    2218
    2319REGISTRATION_TRANSITIONS = (
     
    2723        source = None,
    2824        condition = NullCondition,
    29         msg = _('Record created'),
     25        msg = _('Student record created'),
    3026        destination = CREATED),
    3127
     
    3329        transition_id = 'admit',
    3430        title = _('Admit student'),
    35         msg = _('Admitted'),
     31        msg = _('Student admitted'),
    3632        source = CREATED,
    3733        destination = ADMITTED),
     
    6763    Transition(
    6864        transition_id = 'reset3',
    69         title = _('Reset to clearance started'),
    70         msg = _("Reset to 'clearance started'"),
     65        title = _('Reset to clearance'),
     66        msg = _("Reset to 'clearance'"),
    7167        source = REQUESTED,
    7268        destination = CLEARANCE),
     
    8177    Transition(
    8278        transition_id = 'reset4',
    83         title = _('Reset to clearance started'),
    84         msg = _("Reset to 'clearance started'"),
     79        title = _('Reset to clearance'),
     80        msg = _("Reset to 'clearance'"),
    8581        source = CLEARED,
    8682        destination = CLEARANCE),
     
    8985        transition_id = 'pay_first_school_fee',
    9086        title = _('Pay school fee'),
    91         msg = _('First school fee payment made'),
     87        msg = _('School fee paid'),
    9288        source = CLEARED,
    9389        destination = PAID),
     
    9692        transition_id = 'approve_first_school_fee',
    9793        title = _('Approve payment'),
    98         msg = _('First school fee payment approved'),
     94        msg = _('School fee payment approved'),
    9995        source = CLEARED,
    10096        destination = PAID),
     
    110106        transition_id = 'pay_school_fee',
    111107        title = _('Pay school fee'),
    112         msg = _('School fee payment made'),
     108        msg = _('Payment made'),
    113109        source = RETURNING,
    114110        destination = PAID),
     
    116112    Transition(
    117113        transition_id = 'pay_pg_fee',
    118         title = _('Pay PG school fee'),
    119         msg = _('PG school fee payment made'),
     114        title = _('Pay postgraduate school fee'),
     115        msg = _('Payment made'),
    120116        source = PAID,
    121117        destination = PAID),
     
    123119    Transition(
    124120        transition_id = 'approve_school_fee',
    125         title = _('Approve school fee payment'),
     121        title = _('Approve payment'),
    126122        msg = _('School fee payment approved'),
    127123        source = RETURNING,
     
    130126    Transition(
    131127        transition_id = 'approve_pg_fee',
    132         title = _('Approve PG school fee payment'),
    133         msg = _('PG school fee payment approved'),
     128        title = _('Approve postgraduate payment'),
     129        msg = _('School fee payment approved'),
    134130        source = PAID,
    135131        destination = PAID),
     
    151147    Transition(
    152148        transition_id = 'reset7',
    153         title = _('Reset to school fee paid'),
    154         msg = _("Reset to 'school fee paid'"),
     149        title = _('Reset to paid'),
     150        msg = _("Reset to 'paid'"),
    155151        source = REGISTERED,
    156152        destination = PAID),
     
    165161    Transition(
    166162        transition_id = 'reset8',
    167         title = _('Reset to school fee paid'),
    168         msg = _("Reset to 'school fee paid'"),
     163        title = _('Reset to paid'),
     164        msg = _("Reset to 'paid'"),
    169165        source = VALIDATED,
    170166        destination = PAID),
     
    179175    Transition(
    180176        transition_id = 'reset9',
    181         title = _('Reset to courses validated'),
    182         msg = _("Reset to 'courses validated'"),
     177        title = _('Reset to validated'),
     178        msg = _("Reset to 'validated'"),
    183179        source = RETURNING,
    184180        destination = VALIDATED),
     
    187183IMPORTABLE_TRANSITIONS = [i.transition_id for i in REGISTRATION_TRANSITIONS]
    188184
    189 FORBIDDEN_POSTGRAD_TRANS = ['reset6', 'register_courses']
    190185LOCK_CLEARANCE_TRANS = ('reset2', 'request_clearance')
    191186UNLOCK_CLEARANCE_TRANS = ('reset3', 'reset4', 'start_clearance')
     
    217212
    218213    Lock and unlock clearance form.
    219     Trigger actions after school fee payment.
     214    Triger actions after school fee payment.
    220215    """
    221216
     
    236231        new_session = obj['studycourse'].current_session + 1
    237232        obj['studycourse'].current_session = new_session
    238     elif event.transition.transition_id == 'validate_courses':
    239         current_level = obj['studycourse'].current_level
    240         level_object = obj['studycourse'].get(str(current_level), None)
    241         if level_object is not None:
    242             user = get_current_principal()
    243             if user is None:
    244                 usertitle = 'system'
    245             else:
    246                 usertitle = getattr(user, 'public_name', None)
    247                 if not usertitle:
    248                     usertitle = user.title
    249             level_object.validated_by = usertitle
    250             level_object.validation_date = datetime.utcnow()
    251     elif event.transition.transition_id == 'reset8':
    252         current_level = obj['studycourse'].current_level
    253         level_object = obj['studycourse'].get(str(current_level), None)
    254         if level_object is not None:
    255             level_object.validated_by = None
    256             level_object.validation_date = None
    257233    # In some tests we don't have a students container
    258234    try:
Note: See TracChangeset for help on using the changeset viewer.