Ignore:
Timestamp:
10 Sep 2012, 11:05:07 (12 years ago)
Author:
uli
Message:

Merge changes from trunk, r8786-HEAD

Location:
main/waeup.kofa/branches/uli-async-update
Files:
2 edited

Legend:

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

  • main/waeup.kofa/branches/uli-async-update/src/waeup/kofa/students/batching.py

    r8736 r9169  
    2626import grok
    2727import csv
     28from time import time
    2829from zope.interface import Interface
    2930from zope.schema import getFields
     
    4243    IStudentOnlinePayment, IStudentVerdictUpdate)
    4344from waeup.kofa.students.workflow import  (
    44     IMPORTABLE_STATES, IMPORTABLE_TRANSITIONS)
     45    IMPORTABLE_STATES, IMPORTABLE_TRANSITIONS,
     46    FORBIDDEN_POSTGRAD_TRANS, FORBIDDEN_POSTGRAD_STATES)
    4547from waeup.kofa.utils.batching import BatchProcessor
    4648
     
    170172            if transition not in allowed_transitions:
    171173                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).'
    172182        return None
    173183
     
    183193
    184194        # Update password
     195        # XXX: Tale DELETION_MARKER into consideration
    185196        if row.has_key('password'):
    186197            passwd = row.get('password', IGNORE_MARKER)
     
    222233        parent = self.getParent(row, site)
    223234        if hasattr(obj,'student_id'):
    224             # Update mode: the student exists and we can get the student_id
     235            # Update mode: the student exists and we can get the student_id.
     236            # Create mode: the record contains the student_id
    225237            parent.logger.info(
    226238                '%s - Student record updated: %s'
     
    259271        errs, inv_errs, conv_dict =  converter.fromStringDict(
    260272            row, self.factory_name, mode=mode)
    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 
     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
    274285        try:
    275286            # Correct stud_id counter. As the IConverter for students
     
    291302    grok.baseclass()
    292303
    293     #: required fields beside 'student_id', 'reg_number' and 'matric_number'
     304    # additional available  fields
     305    # beside 'student_id', 'reg_number' and 'matric_number'
    294306    additional_fields = []
    295307
    296     #: header fields additional required
     308    #: header fields additionally required
    297309    additional_headers = []
    298310
     
    361373        return errs, inv_errs, conv_dict
    362374
     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
    363392
    364393class StudentStudyCourseProcessor(StudentProcessorBase):
     
    406435            StudentStudyCourseProcessor, self).checkConversion(row, mode=mode)
    407436        # We have to check if current_level is in range of certificate.
    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'))
     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'))
    413443        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
    414456
    415457class StudentStudyLevelProcessor(StudentProcessorBase):
     
    427469
    428470    location_fields = []
     471
    429472    additional_fields = ['level']
    430473    additional_headers = ['level']
     
    509552        items_changed = super(CourseTicketProcessor, self).updateEntry(
    510553            obj, row, site)
     554        parent = self.getParent(row, site)
    511555        student = self.getParent(row, site).__parent__.__parent__
    512556        student.__parent__.logger.info(
    513             '%s - Course ticket updated: %s'
    514             % (student.student_id, items_changed))
     557            '%s - Course ticket in %s updated: %s'
     558            % (student.student_id,  parent.level, items_changed))
    515559        return
    516560
     
    528572        return
    529573
     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
    530584    def checkConversion(self, row, mode='ignore'):
    531585        """Validates all values in row.
     
    552606    grok.name(util_name)
    553607
    554     name = u'Payment Processor'
     608    name = u'Student Payment Processor'
    555609    iface = IStudentOnlinePayment
    556610    factory_name = 'waeup.StudentOnlinePayment'
     
    558612    location_fields = []
    559613    additional_fields = ['p_id']
    560     additional_headers = ['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
    561622
    562623    def parentsExist(self, row, site):
     
    573634        if payments is None:
    574635            return None
     636        p_id = row.get('p_id', None)
     637        if p_id is None:
     638            return None
    575639        # We can use the hash symbol at the end of p_id in import files
    576640        # to avoid annoying automatic number transformation
    577641        # by Excel or Calc
    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:])
     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)
    584647        return entry
    585648
     
    600663        if not p_id.startswith('p'):
    601664            # For data migration from old SRP
    602             obj.p_id = 'p' + p_id[6:]
     665            obj.p_id = 'p' + p_id[7:] + '0'
    603666            parent[obj.p_id] = obj
    604667        else:
     
    606669        return
    607670
     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
    608681    def checkConversion(self, row, mode='ignore'):
    609682        """Validates all values in row.
     
    613686
    614687        # We have to check p_id.
    615         p_id = row['p_id'].strip('#')
     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('#')
    616696        if p_id.startswith('p'):
    617697            if not len(p_id) == 14:
Note: See TracChangeset for help on using the changeset viewer.