Changeset 15128 for main


Ignore:
Timestamp:
6 Sep 2018, 11:16:55 (6 years ago)
Author:
Henrik Bettermann
Message:

Extend transcript workflow (par 1)

Location:
main/waeup.kofa/branches/henrik-transcript-workflow
Files:
1 added
1 deleted
10 edited

Legend:

Unmodified
Added
Removed
  • main/waeup.kofa/branches/henrik-transcript-workflow/docs/source/userdocs/datacenter/export.rst

    r15051 r15128  
    282282  .. autoattribute:: waeup.kofa.students.export.SessionPaymentsOverviewExporter.fields
    283283  .. autoattribute:: waeup.kofa.students.export.SessionPaymentsOverviewExporter.title
    284   .. autoattribute:: waeup.kofa.students.export.SessionPaymentsOverviewExporter.curr_year
    285284  .. automethod:: waeup.kofa.students.export.SessionPaymentsOverviewExporter.mangle_value()
    286285
  • main/waeup.kofa/branches/henrik-transcript-workflow/docs/source/userdocs/datacenter/import_stages.rst

    r12998 r15128  
    88   :ref:`Data Center Doctests <datacenter_txt>`
    99
    10 The term 'data import' actually understates the range of funcnctions
     10The term 'data import' actually understates the range of functions
    1111importers really have. As already stated, many importers do not only
    1212restore data once backed up by exporters or, in other words, take
  • main/waeup.kofa/branches/henrik-transcript-workflow/docs/source/userdocs/students/workflow.rst

    r13610 r15128  
    2828
    2929              a
    30    created ------- admitted
    31               b       |
    32      +----------------+
    33      |                         e
    34      +------------------------------------------------------+
    35      |                  c                            d      |
    36    clearance started ------- clearance requested  ------- cleared
    37                                                             |
    38                                 f                           |
    39      +--------+---------------------------------------------+
    40      |        |
    41      | h    school fee paid -------- returning -------------+
    42      |        |             \   l        |                  |
    43      +--------+ g            \ _ _ _ m   | k                |
    44               |                      \   |                  |
    45            courses registered ------ courses validated      |
    46                           |      i       |                  |
    47                           |              | n                |
    48                           | j            |                  |
    49                           |          graduated              |
    50                           |              |                  |
    51                           |              | o                |
    52                           |              |                  |
    53                           |          transcript requested   |
    54      a: admit             |                                 |
    55     -a: reset1            +---------------------------------+
    56      b: start_clearance
    57     -b: reset2
    58      c: request_clearance
    59     -c: reset3 (= reject request)
    60      d: clear
    61     -d: N/A
     30    created ------- admitted
     31               b       |
     32      +----------------+
     33      |                         e
     34      +------------------------------------------------------+
     35      |                  c                            d      |
     36    clearance started ------- clearance requested  ------- cleared
     37                                                             |
     38                                 f                           |
     39      +--------+---------------------------------------------+
     40      |        |
     41      | h    school fee paid -------- returning -------------+
     42      |        |             \   l        |                  |
     43      +--------+ g            \ _ _ _ m   | k                |
     44               |                      \   |                  |
     45            courses registered ------ courses validated      |
     46                           |      i       |                  |
     47                           |              | n                |
     48                           | j            |                  |
     49                           |          graduated              |
     50                           |              |                  |
     51                           |              | o                |
     52                           |              |                  |
     53                           |          transcript requested   |
     54     a: admit              |              |                  |
     55    -a: reset1             |              | p                |
     56     b: start_clearance    |              |                  |
     57    -b: reset2             |          transcript validated   |
     58     c: request_clearance  |              |                  |
     59    -c: reset3             |              | q                |
     60        (= reject request) |              |                  |
     61     d: clear              |          transcript released    |
     62    -d: N/A                +---------------------------------+
    6263     e: N/A
    6364    -e: reset4 (= annul clearance)
     
    8182    -n: N/A
    8283     o: request_transcript
    83     -o: process_transcript
    84 
     84    -o: reset10 (= reject request)
     85     p: validate_transcript
     86    -p: N/A
     87     q: release_transcript
     88    -q: N/A
    8589
    8690Student registration starts with the first login of the student into
  • main/waeup.kofa/branches/henrik-transcript-workflow/src/waeup/kofa/interfaces.py

    r14699 r15128  
    5656VALIDATED = 'courses validated'
    5757GRADUATED = 'graduated'
    58 TRANSCRIPT = 'transcript requested'
     58TRANSREQ = 'transcript requested'
     59TRANSVAL = 'transcript validated'
     60TRANSREL = 'transcript released'
    5961
    6062
     
    103105    (_('returning'), RETURNING),
    104106    (_('graduated'), GRADUATED),
    105     (_('transcript requested'), TRANSCRIPT),
     107    (_('transcript requested'), TRANSREQ),
     108    (_('transcript validated'), TRANSVAL),
     109    (_('transcript released'), TRANSREL),
    106110    )
    107111
  • main/waeup.kofa/branches/henrik-transcript-workflow/src/waeup/kofa/students/browser.py

    r15116 r15128  
    7878from waeup.kofa.students.workflow import (
    7979    ADMITTED, PAID, CLEARANCE, REQUESTED, RETURNING, CLEARED, REGISTERED,
    80     VALIDATED, GRADUATED, TRANSCRIPT, FORBIDDEN_POSTGRAD_TRANS
     80    VALIDATED, GRADUATED, TRANSREQ, TRANSVAL, TRANSREL, FORBIDDEN_POSTGRAD_TRANS
    8181    )
    8282
     
    11461146        return
    11471147
    1148 class StudentTranscriptRequestProcessFormPage(KofaEditFormPage):
    1149     """ Page to process transcript requests
     1148class StudentTranscriptReleasesFormPage(KofaEditFormPage):
     1149    """ Page to release transcript
    11501150    """
    11511151    grok.context(IStudent)
    1152     grok.name('process_transcript_request')
     1152    grok.name('release_transcript')
    11531153    grok.require('waeup.viewTranscript')
    1154     grok.template('transcriptprocess')
     1154    grok.template('transcriptrelease')
    11551155    form_fields = grok.AutoFields(IStudentTranscript)
    1156     label = _('Process transcript request')
    1157     buttonname = _('Save comment and mark as processed')
     1156    label = _('Release transcript')
     1157    buttonname = _('Save comment and mark as released')
    11581158    pnav = 4
    11591159
    11601160    def update(self, SUBMIT=None):
    1161         super(StudentTranscriptRequestProcessFormPage, self).update()
    1162         if self.context.state != TRANSCRIPT:
     1161        super(StudentTranscriptReleasesFormPage, self).update()
     1162        if self.context.state != TRANSVAL:
    11631163            self.flash(_('Student is in wrong state.'), type="warning")
    11641164            self.redirect(self.url(self.context))
     
    11711171        if SUBMIT is None:
    11721172            return
    1173         IWorkflowInfo(self.context).fireTransition('process_transcript')
    1174         self.flash(_('Transcript request processed.'))
     1173        # Fire transition
     1174        IWorkflowInfo(self.context).fireTransition('release_transcript')
     1175        self.flash(_('Transcript released.'))
    11751176        comment = self.request.form.get('comment', '').replace('\r', '')
    11761177        tz = getattr(queryUtility(IKofaUtils), 'tzinfo', pytz.utc)
     
    11871188        self.context.writeLogMessage(
    11881189            self, 'comment: %s' % comment.replace('\n', '<br>'))
    1189         subject = _('Transcript processed')
    1190         args = {'subject':subject, 'body':comment}
    1191         self.redirect(self.url(self.context) +
    1192             '/contactstudent?%s' % urlencode(args))
     1190        # Show and produce transcript file
     1191        self.redirect(self.url(self.context) + '/studycourse/transcript.pdf')
     1192
     1193        #subject = _('Transcript released')
     1194        #args = {'subject':subject, 'body':comment}
     1195        #self.redirect(self.url(self.context) +
     1196        #    '/contactstudent?%s' % urlencode(args))
     1197
    11931198        return
    11941199
     
    12761281    def _signatures(self):
    12771282        return None
     1283
     1284    def _save_file(self):
     1285        if self.context.student.state == TRANSREL:
     1286            return True
     1287        return False
    12781288
    12791289    def render(self):
     
    13041314            signatures=self._signatures(),
    13051315            sigs_in_footer=self._sigsInFooter(),
     1316            save_file=self._save_file(),
    13061317            )
    13071318
  • main/waeup.kofa/branches/henrik-transcript-workflow/src/waeup/kofa/students/reports/tests/test_student_statistics.py

    r14514 r15128  
    2121              'clearance requested', 'cleared', 'school fee paid',
    2222              'courses registered', 'courses validated', 'returning',
    23               'graduated', 'transcript requested', 'Total')
     23              'graduated', 'transcript requested', 'transcript validated',
     24              'transcript released', 'Total')
    2425
    2526    def test_iface(self):
     
    4142            ((u'fac1', u'Total',),
    4243             self.states,
    43              ((1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1),
    44               (1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1),)))
     44             ((1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1),
     45              (1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1),)))
    4546        self.assertEqual(
    4647            result2,
    4748            ((u'fac1', u'Total'),
    4849             self.states,
    49              ((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
    50               (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),)))
     50             ((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
     51              (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),)))
    5152        return
    5253
     
    6263            ((u'fac1', u'fac2', u'Total'),
    6364             self.states,
    64              ((1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1),
    65               (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
    66               (1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1),)))
     65             ((1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1),
     66              (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
     67              (1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1),)))
    6768        self.assertEqual(
    6869            result2,
    6970            ((u'fac1', u'fac2', u'Total'),
    7071             self.states,
    71              ((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
    72               (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
    73               (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),)))
     72             ((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
     73              (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
     74              (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),)))
    7475        return
    7576
     
    8384            ((u'fac1/dep1', u'fac2/dep2', u'Total'),
    8485             self.states,
    85              ((1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1),
    86               (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
    87               (1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1),)))
    88         self.assertEqual(
    89             result2,
    90             ((u'fac1/dep1', u'fac2/dep2', u'Total'),
    91              self.states,
    92              ((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
    93               (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
    94               (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),)))
     86             ((1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1),
     87              (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
     88              (1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1),)))
     89        self.assertEqual(
     90            result2,
     91            ((u'fac1/dep1', u'fac2/dep2', u'Total'),
     92             self.states,
     93             ((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
     94              (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
     95              (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),)))
    9596        return
    9697
     
    104105            ((u'fac1/dep1', u'fac2/dep2', u'Total'),
    105106             self.states,
    106              ((1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1),
    107               (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
    108               (1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1),)))
    109         self.assertEqual(
    110             result2,
    111             ((u'fac1/dep1', u'fac2/dep2', u'Total'),
    112              self.states,
    113              ((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
    114               (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
    115               (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),)))
     107             ((1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1),
     108              (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
     109              (1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1),)))
     110        self.assertEqual(
     111            result2,
     112            ((u'fac1/dep1', u'fac2/dep2', u'Total'),
     113             self.states,
     114             ((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
     115              (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
     116              (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),)))
    116117        return
    117118
  • main/waeup.kofa/branches/henrik-transcript-workflow/src/waeup/kofa/students/tests/test_browser.py

    r15055 r15128  
    4141from waeup.kofa.testing import FunctionalLayer, FunctionalTestCase
    4242from waeup.kofa.app import University
     43from waeup.kofa.interfaces import IFileStoreNameChooser, IExtFileStore
    4344from waeup.kofa.payments.interfaces import IPayer
    4445from waeup.kofa.students.payments import StudentOnlinePayment
     
    21192120        print "Sample PDF transcript.pdf written to %s" % path
    21202121
    2121     def test_process_transcript_request(self):
     2122    def test_release_transcript(self):
    21222123        IWorkflowState(self.student).setState('transcript requested')
    21232124        notify(grok.ObjectModifiedEvent(self.student))
     
    21432144            '...<div>Transcript Officer</div>...',
    21442145            self.browser.contents)
    2145         # Officer can search for students in state 'transcripr requested'
     2146        # Officer can search for students in state 'transcript requested'
    21462147        self.browser.open(self.container_path)
    21472148        self.browser.getControl(name="searchtype").value = ['transcript']
     
    21492150        self.assertTrue('Anna Tester' in self.browser.contents)
    21502151        self.browser.getLink("K1000000").click()
    2151         self.browser.getLink("Manage transcript request").click()
     2152        self.assertFalse('Release transcript request' in self.browser.contents)
     2153        # ToDo: Somebody has to validate the transcript
     2154
     2155
     2156
     2157        IWorkflowState(self.student).setState('transcript validated')
     2158
     2159
     2160
     2161        self.browser.open(self.student_path)
     2162        self.assertTrue('Release transcript' in self.browser.contents)
     2163        # Now the transcript can be released.
     2164        self.browser.getLink("Release transcript").click()
    21522165        self.assertTrue(' UTC K1000000 wrote:<br><br>Comment line 1 <br>'
    21532166        'Comment line2<br><br>Dispatch Address:<br>Address line 1 <br>'
     
    21552168        self.browser.getControl(name="comment").value = (
    21562169            'Hello,\nYour transcript has been sent to the address provided.')
    2157         self.browser.getControl("Save comment and mark as processed").click()
     2170        self.browser.getControl("Save comment and mark as released").click()
    21582171        self.assertTrue(
    21592172            'UTC mrtranscript wrote:\n\nHello,\nYour transcript has '
     
    21652178        logcontent = open(logfile).read()
    21662179        self.assertTrue(
    2167             'mrtranscript - students.browser.StudentTranscriptRequestProcessFormPage - '
     2180            'mrtranscript - students.browser.StudentTranscriptReleasesFormPage - '
    21682181            'K1000000 - comment: Hello,<br>'
    21692182            'Your transcript has been sent to the address provided'
    21702183            in logcontent)
     2184        # File has been stored in the file system
     2185        # Check if transcript exists in the file system and is a PDF file
     2186        storage = getUtility(IExtFileStore)
     2187        file_id = IFileStoreNameChooser(
     2188            self.student).chooseName(attr='transcript.pdf')
     2189        pdf = storage.getFile(file_id).read()
     2190        self.assertTrue(len(pdf) > 0)
     2191        self.assertEqual(pdf[:8], '%PDF-1.4')
     2192        # Copy the file to samples_dir
     2193        path = os.path.join(samples_dir(), 'final_transcript.pdf')
     2194        open(path, 'wb').write(pdf)
     2195        print "Sample PDF final_transcript.pdf written to %s" % path
     2196        # Check if there is an transcript pdf link in UI
     2197        self.browser.open(self.student_path)
     2198        self.assertTrue('Final Transcript' in self.browser.contents)
     2199        self.browser.getLink("Final Transcript").click()
     2200        self.assertEqual(self.browser.headers['Status'], '200 Ok')
     2201        self.assertEqual(self.browser.headers['Content-Type'],
     2202                         'application/pdf')
    21712203
    21722204class StudentUITests(StudentsFullSetup):
  • main/waeup.kofa/branches/henrik-transcript-workflow/src/waeup/kofa/students/utils.py

    r15102 r15128  
    2020import grok
    2121from time import time
     22from cStringIO import StringIO
    2223from reportlab.lib import colors
    2324from reportlab.lib.units import cm
     
    3334from waeup.kofa.interfaces import (
    3435    IExtFileStore, IKofaUtils, RETURNING, PAID, CLEARED,
    35     academic_sessions_vocab)
     36    academic_sessions_vocab, IFileStoreNameChooser)
    3637from waeup.kofa.interfaces import MessageFactory as _
    3738from waeup.kofa.students.interfaces import IStudentsUtils
     
    854855            level_obj.cumulative_params[0], level_obj.student)[0]
    855856
     857    def _saveTranscriptPDF(self, student, transcript):
     858        """Create a transcript PDF file and store it in student folder.
     859        """
     860        file_store = getUtility(IExtFileStore)
     861        file_id = IFileStoreNameChooser(student).chooseName(
     862            attr="transcript.pdf")
     863        file_store.createFile(file_id, StringIO(transcript))
     864        return
     865
    856866    def renderPDFTranscript(self, view, filename='transcript.pdf',
    857867                  student=None,
     
    861871                  omit_fields=(),
    862872                  tableheader=None,
    863                   no_passport=False):
     873                  no_passport=False,
     874                  save_file=False):
    864875        """Render pdf slip of a transcripts.
    865876        """
     
    966977            view.flash(_('Error in image file.'))
    967978            return view.redirect(view.url(view.context))
     979        if save_file:
     980            self._saveTranscriptPDF(student, pdf_stream)
    968981        return pdf_stream
    969982
  • main/waeup.kofa/branches/henrik-transcript-workflow/src/waeup/kofa/students/viewlets.py

    r14158 r15128  
    4040from waeup.kofa.students.workflow import (
    4141    ADMITTED, PAID, REQUESTED, CLEARED, REGISTERED, VALIDATED, GRADUATED,
    42     TRANSCRIPT)
     42    TRANSREQ, TRANSVAL)
    4343from waeup.kofa.university.interfaces import ICourse
    4444
     
    9696        return ''
    9797
    98 
    9998class StudentManageBaseLink(StudentManageLink):
    10099    grok.order(2)
     
    142141    link = 'history'
    143142    text = _(u'History')
     143
     144
     145class StudentManageTranscriptLink(StudentManageLink):
     146    grok.order(9)
     147    link = 'transcript.pdf'
     148    text = _(u'Final Transcript')
     149
     150    def render(self):
     151        slip = getUtility(IExtFileStore).getFileByContext(
     152            self.context.student, attr=self.link)
     153        if slip:
     154            lang = self.request.cookies.get('kofa.language')
     155            text = translate(
     156                self.text, 'waeup.kofa', target_language=lang)
     157            url = self.view.url(self.context.student['studycourse'], self.link)
     158            return u'<li><a href="%s">%s</a></li>' % (
     159                url, text)
     160        return ''
    144161
    145162
     
    759776
    760777
    761 class ProcessTranscriptRequestActionButton(ManageActionButton):
     778class ReleaseTranscriptActionButton(ManageActionButton):
    762779    grok.order(9)
    763780    grok.context(IStudent)
    764781    grok.view(StudentBaseDisplayFormPage)
    765782    grok.require('waeup.viewTranscript')
    766     text = _('Manage transcript request')
    767     target = 'process_transcript_request'
     783    text = _('Release transcript')
     784    target = 'release_transcript'
    768785    icon = 'actionicon_transcript.png'
    769786
    770787    @property
    771788    def target_url(self):
    772         if self.context.state != TRANSCRIPT:
     789        if self.context.state != TRANSVAL:
    773790            return ''
    774791        return self.view.url(self.view.context, self.target)
  • main/waeup.kofa/branches/henrik-transcript-workflow/src/waeup/kofa/students/workflow.py

    r13610 r15128  
    99    IObjectHistory, IKofaWorkflowInfo, IKofaUtils,
    1010    CREATED, ADMITTED, CLEARANCE, REQUESTED, CLEARED, PAID, RETURNING,
    11     REGISTERED, VALIDATED, GRADUATED, TRANSCRIPT)
     11    REGISTERED, VALIDATED, GRADUATED, TRANSREQ, TRANSVAL, TRANSREL)
    1212from waeup.kofa.interfaces import MessageFactory as _
    1313from waeup.kofa.workflow import KofaWorkflow, KofaWorkflowInfo
     
    198198        msg = _("Transcript requested"),
    199199        source = GRADUATED,
    200         destination = TRANSCRIPT),
    201 
    202     Transition(
    203         transition_id = 'process_transcript',
    204         title = _('Transcript processed'),
    205         msg = _("Transcript processed"),
    206         source = TRANSCRIPT,
     200        destination = TRANSREQ),
     201
     202    Transition(
     203        transition_id = 'reset10',
     204        title = _('Reject transcript request'),
     205        msg = _("Transcript request rejected"),
     206        source = TRANSREQ,
    207207        destination = GRADUATED),
     208
     209    Transition(
     210        transition_id = 'validate_transcript',
     211        title = _('Transcript validated'),
     212        msg = _("Transcript validated"),
     213        source = TRANSREQ,
     214        destination = TRANSVAL),
     215
     216    Transition(
     217        transition_id = 'release_transcript',
     218        title = _('Transcript released'),
     219        msg = _("Transcript released"),
     220        source = TRANSVAL,
     221        destination = TRANSREL),
    208222    )
    209223
Note: See TracChangeset for help on using the changeset viewer.