Changeset 7250
- Timestamp:
- 2 Dec 2011, 12:46:36 (13 years ago)
- Location:
- main/waeup.sirp/trunk/src/waeup/sirp
- Files:
-
- 2 added
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
main/waeup.sirp/trunk/src/waeup/sirp/applicants/applicant.py
r7244 r7250 45 45 return u"xxx_1234" 46 46 47 class Applicant(grok. Model):47 class Applicant(grok.Container): 48 48 grok.implements(IApplicant,IApplicantEdit) 49 49 grok.provides(IApplicant) -
main/waeup.sirp/trunk/src/waeup/sirp/applicants/browser.py
r7249 r7250 21 21 import sys 22 22 import grok 23 23 from time import time 24 24 from datetime import datetime, date 25 25 from zope.authentication.interfaces import ILogout, IAuthentication … … 58 58 from waeup.sirp.utils.helpers import string_from_bytes, file_size 59 59 from waeup.sirp.widgets.datewidget import ( 60 FriendlyDateWidget, FriendlyDateDisplayWidget) 60 FriendlyDateWidget, FriendlyDateDisplayWidget, 61 FriendlyDatetimeDisplayWidget) 61 62 from waeup.sirp.widgets.restwidget import ReSTDisplayWidget 62 63 from waeup.sirp.widgets.objectwidget import ( … … 66 67 IApplicant, IApplicantEdit, IApplicantsRoot, 67 68 IApplicantsContainer, IApplicantsContainerAdd, application_types_vocab, 68 MAX_UPLOAD_SIZE, 69 MAX_UPLOAD_SIZE, IApplicantOnlinePayment, 69 70 ) 70 from waeup.sirp.applicants.workflow import INITIALIZED, STARTED 71 from waeup.sirp.applicants.workflow import INITIALIZED, STARTED, PAID 71 72 from waeup.sirp.students.viewlets import PrimaryStudentNavTab 73 from waeup.sirp.students.interfaces import IStudentsUtils 72 74 73 75 grok.context(IWAeUPObject) # Make IWAeUPObject the default context … … 228 230 return self.context.application_number 229 231 232 class OnlinePaymentBreadcrumb(Breadcrumb): 233 """A breadcrumb for payments. 234 """ 235 grok.context(IApplicantOnlinePayment) 236 237 @property 238 def title(self): 239 return self.context.p_id 240 230 241 class ApplicantsAuthTab(PrimaryNavTab): 231 242 """Applicants tab in primary navigation. … … 233 244 grok.context(IWAeUPObject) 234 245 grok.order(3) 235 grok.require('waeup.viewApplica tionsTab')246 grok.require('waeup.viewApplicantsTab') 236 247 pnav = 3 237 248 tab_title = u'Applicants' … … 478 489 return '<a href="%s">%s - %s</a>' %(url,code,title) 479 490 return '' 491 492 def formatDatetime(self,datetimeobj): 493 if isinstance(datetimeobj, datetime): 494 return datetimeobj.strftime("%Y-%m-%d %H:%M:%S") 495 else: 496 return None 497 498 class AcceptanceFeePaymentAddPage(grok.View): 499 """ Page to add an online payment ticket 500 """ 501 grok.context(IApplicant) 502 grok.name('addafp') 503 grok.require('waeup.payApplicant') 504 505 def update(self): 506 p_category = 'acceptance' 507 d = {} 508 session = str(self.context.__parent__.year) 509 try: 510 academic_session = grok.getSite()['configuration'][session] 511 except KeyError: 512 self.flash('Session configuration object is not available.') 513 return 514 timestamp = "%d" % int(time()*1000) 515 #order_id = "%s%s" % (student_id[1:],timestamp) 516 for key in self.context.keys(): 517 ticket = self.context[key] 518 if ticket.p_state == 'paid': 519 self.flash( 520 'This type of payment has already been made.') 521 self.redirect(self.url(self.context)) 522 return 523 payment = createObject(u'waeup.ApplicantOnlinePayment') 524 payment.p_id = "p%s" % timestamp 525 payment.p_item = self.context.__parent__.title 526 payment.p_year = self.context.__parent__.year 527 payment.p_category = p_category 528 payment.amount_auth = academic_session.acceptance_fee 529 payment.surcharge_1 = academic_session.surcharge_1 530 payment.surcharge_2 = academic_session.surcharge_2 531 payment.surcharge_3 = academic_session.surcharge_3 532 self.context[payment.p_id] = payment 533 #import pdb; pdb.set_trace() 534 self.flash('Payment ticket created.') 535 return 536 537 def render(self): 538 usertype = getattr(self.request.principal, 'user_type', None) 539 if usertype == 'applicant': 540 self.redirect(self.url(self.context, '@@edit')) 541 return 542 self.redirect(self.url(self.context, '@@manage')) 543 return 544 545 546 class OnlinePaymentDisplayFormPage(WAeUPDisplayFormPage): 547 """ Page to view an online payment ticket 548 """ 549 grok.context(IApplicantOnlinePayment) 550 grok.name('index') 551 grok.require('waeup.viewApplication') 552 form_fields = grok.AutoFields(IApplicantOnlinePayment) 553 form_fields['creation_date'].custom_widget = FriendlyDatetimeDisplayWidget('le') 554 form_fields['payment_date'].custom_widget = FriendlyDatetimeDisplayWidget('le') 555 pnav = 3 556 557 @property 558 def title(self): 559 return 'Online Payment Ticket %s' % self.context.p_id 560 561 @property 562 def label(self): 563 return '%s: Online Payment Ticket %s' % ( 564 self.context.__parent__.fullname,self.context.p_id) 565 566 class PaymentReceiptActionButton(ManageActionButton): 567 grok.order(1) 568 grok.context(IApplicantOnlinePayment) 569 grok.view(OnlinePaymentDisplayFormPage) 570 grok.require('waeup.viewApplication') 571 icon = 'actionicon_pdf.png' 572 text = 'Download payment receipt' 573 target = 'payment_receipt.pdf' 574 575 @property 576 def target_url(self): 577 if self.context.p_state != 'paid': 578 return '' 579 return self.view.url(self.view.context, self.target) 580 581 class RequestCallbackActionButton(ManageActionButton): 582 grok.order(2) 583 grok.context(IApplicantOnlinePayment) 584 grok.view(OnlinePaymentDisplayFormPage) 585 grok.require('waeup.payApplicant') 586 icon = 'actionicon_call.png' 587 text = 'Request callback' 588 target = 'callback' 589 590 @property 591 def target_url(self): 592 if self.context.p_state != 'unpaid': 593 return '' 594 return self.view.url(self.view.context, self.target) 595 596 class OnlinePaymentCallbackPage(grok.View): 597 """ Callback view 598 """ 599 grok.context(IApplicantOnlinePayment) 600 grok.name('callback') 601 grok.require('waeup.payApplicant') 602 603 # This update method simulates a valid callback und must be 604 # specified in the customization package. The parameters must be taken 605 # from the incoming request. 606 def update(self): 607 if self.context.p_state == 'paid': 608 self.flash('This ticket has already been paid.') 609 return 610 self.context.r_amount_approved = self.context.amount_auth 611 self.context.r_card_num = u'0000' 612 self.context.r_code = u'00' 613 self.context.p_state = 'paid' 614 self.context.payment_date = datetime.now() 615 ob_class = self.__implemented__.__name__.replace('waeup.sirp.','') 616 self.context.__parent__.loggerInfo( 617 ob_class, 'valid callback: %s' % self.context.p_id) 618 self.wf_info = IWorkflowInfo(self.context.__parent__) 619 self.wf_info.fireTransition('pay') 620 self.flash('Valid callback received.') 621 return 622 623 def render(self): 624 self.redirect(self.url(self.context, '@@index')) 625 return 626 627 class ExportPDFPaymentSlipPage(grok.View): 628 """Deliver a PDF slip of the context. 629 """ 630 grok.context(IApplicantOnlinePayment) 631 grok.name('payment_receipt.pdf') 632 grok.require('waeup.viewApplication') 633 form_fields = grok.AutoFields(IApplicantOnlinePayment) 634 form_fields['creation_date'].custom_widget = FriendlyDateDisplayWidget('le') 635 form_fields['payment_date'].custom_widget = FriendlyDateDisplayWidget('le') 636 prefix = 'form' 637 638 @property 639 def label(self): 640 return 'Online Payment Receipt %s' % self.context.p_id 641 642 def render(self): 643 if self.context.p_state != 'paid': 644 self.flash('Ticket not yet paid.') 645 self.redirect(self.url(self.context)) 646 return 647 applicantview = ApplicantDisplayFormPage(self.context.__parent__, 648 self.request) 649 students_utils = getUtility(IStudentsUtils) 650 return students_utils.renderPDF(self,'Payment', 'payment_receipt.pdf', 651 self.context.__parent__, applicantview) 480 652 481 653 class PDFActionButton(ManageActionButton): … … 646 818 manage_applications = True 647 819 pnav = 3 820 display_actions = [['Save', 'Final Submit'], 821 ['Add online payment ticket','Remove selected tickets']] 648 822 649 823 def update(self): … … 716 890 return 717 891 892 def formatDatetime(self,datetimeobj): 893 if isinstance(datetimeobj, datetime): 894 return datetimeobj.strftime("%Y-%m-%d %H:%M:%S") 895 else: 896 return None 897 898 def unremovable(self, ticket): 899 usertype = getattr(self.request.principal, 'user_type', None) 900 if not usertype: 901 return False 902 return self.request.principal.user_type == 'applicant' and ticket.r_code 903 904 # This method is also used by the ApplicantEditFormPage 905 def delPaymentTickets(self, **data): 906 form = self.request.form 907 if form.has_key('val_id'): 908 child_id = form['val_id'] 909 else: 910 self.flash('No payment selected.') 911 self.redirect(self.url(self.context)) 912 return 913 if not isinstance(child_id, list): 914 child_id = [child_id] 915 deleted = [] 916 for id in child_id: 917 # Applicants are not allowed to remove used payment tickets 918 if not self.unremovable(self.context[id]): 919 try: 920 del self.context[id] 921 deleted.append(id) 922 except: 923 self.flash('Could not delete %s: %s: %s' % ( 924 id, sys.exc_info()[0], sys.exc_info()[1])) 925 if len(deleted): 926 self.flash('Successfully removed: %s' % ', '.join(deleted)) 927 ob_class = self.__implemented__.__name__.replace('waeup.sirp.','') 928 self.context.loggerInfo(ob_class, 'removed: % s' % ', '.join(deleted)) 929 return 930 931 @grok.action('Add online payment ticket') 932 def addPaymentTicket(self, **data): 933 self.redirect(self.url(self.context, '@@addafp')) 934 935 @grok.action('Remove selected tickets') 936 def removePaymentTickets(self, **data): 937 self.delPaymentTickets(**data) 938 self.redirect(self.url(self.context) + '/@@manage') 939 return 940 718 941 class ApplicantEditFormPage(ApplicantManageFormPage): 719 942 """An applicant-centered edit view for applicant data. … … 731 954 title = u'Your Application Form' 732 955 956 @property 957 def display_actions(self): 958 state = IWorkflowState(self.context).getState() 959 if state == INITIALIZED: 960 actions = [[],[]] 961 elif state == STARTED: 962 actions = [['Save'], 963 ['Add online payment ticket','Remove selected tickets']] 964 elif state == PAID: 965 actions = [['Save', 'Final Submit'], 966 ['Remove selected tickets']] 967 elif state == SUBMITTED: 968 actions = [[],[]] 969 return actions 970 733 971 def emit_lock_message(self): 734 972 self.flash('The requested form is locked (read-only).') … … 748 986 return 'Passport confirmation box not ticked.' 749 987 return False 988 989 @grok.action('Add online payment ticket') 990 def addPaymentTicket(self, **data): 991 self.redirect(self.url(self.context, '@@addafp')) 992 993 @grok.action('Remove selected tickets') 994 def removePaymentTickets(self, **data): 995 self.delPaymentTickets(**data) 996 self.redirect(self.url(self.context) + '/@@edit') 997 return 750 998 751 999 @grok.action('Save') … … 754 1002 return # error during image upload. Ignore other values 755 1003 self.applyData(self.context, **data) 756 #self.context._p_changed = True757 1004 self.flash('Form has been saved.') 758 1005 return … … 770 1017 # This shouldn't happen, but the application officer 771 1018 # might have forgotten to lock the form after changing the state 772 if state != STARTED:1019 if state != PAID: 773 1020 self.flash('This form cannot be submitted. Wrong state!') 774 1021 return -
main/waeup.sirp/trunk/src/waeup/sirp/applicants/browser_templates/applicantdisplaypage.pt
r7240 r7250 43 43 </tbody> 44 44 </table> 45 <h3 i18n:translate="">Acceptance Fee Payment Tickets</h3> 46 <table class="zebra"> 47 <thead> 48 <tr> 49 <th>Payment Id</th> 50 <th>Creation Date</th> 51 <th>Payment Date</th> 52 <th>Category</th> 53 <th>Item</th> 54 <th>State</th> 55 </tr> 56 </thead> 57 <tbody> 58 <tr tal:repeat="value context/values"> 59 <td> <a tal:attributes="href value/__name__"> 60 <span tal:content="value/p_id">PID</span></a></td> 61 <td tal:content="python: view.formatDatetime(value.creation_date)">CREATION DATE</td> 62 <td tal:content="python: view.formatDatetime(value.payment_date)">PAYMENT DATE</td> 63 <td tal:content ="value/category">CATEGORY</td> 64 <td tal:content ="value/p_item">ITEM</td> 65 <td tal:content ="value/state">STATE</td> 66 </tr> 67 </tbody> 68 </table> -
main/waeup.sirp/trunk/src/waeup/sirp/applicants/browser_templates/applicanteditpage.pt
r7240 r7250 95 95 96 96 <div class="actionButtons" tal:condition="view/availableActions"> 97 <input tal:repeat="action view/actions" 98 tal:replace="structure action/render" 99 /> 97 <span tal:repeat="action view/actions" 98 tal:omit-tag=""> 99 <input tal:condition="python:action.label in view.display_actions[0]" 100 tal:replace="structure action/render"/> 101 </span> 102 </div> 103 104 <br /><br /> 105 <h3 i18n:translate="">Acceptance Fee Payment Tickets</h3> 106 107 <table class="display dataTableManage"> 108 <thead> 109 <tr> 110 <th> </th> 111 <th>Payment Id</th> 112 <th>Creation Date</th> 113 <th>Payment Date</th> 114 <th>Category</th> 115 <th>Item</th> 116 <th>State</th> 117 </tr> 118 </thead> 119 <tbody> 120 <tr tal:repeat="cl context/values"> 121 <td> 122 <input type="checkbox" 123 name="val_id" 124 tal:attributes="value cl/__name__" 125 tal:condition="python: not view.unremovable(cl)" /> 126 </td> 127 <td> <a tal:attributes="href cl/__name__"> 128 <span tal:content="cl/p_id">PID</span></a></td> 129 <td tal:content="python: view.formatDatetime(cl.creation_date)">CREATION DATE</td> 130 <td tal:content="python: view.formatDatetime(cl.payment_date)">PAYMENT DATE</td> 131 <td tal:content ="cl/category">CATEGORY</td> 132 <td tal:content ="cl/p_item">ITEM</td> 133 <td tal:content ="cl/state">STATE</td> 134 </tr> 135 </tbody> 136 </table> 137 138 <div class="actionButtons" tal:condition="view/availableActions"> 139 <span tal:repeat="action view/actions" 140 tal:omit-tag=""> 141 <input tal:condition="python:action.label in view.display_actions[1]" 142 tal:replace="structure action/render"/> 143 </span> 100 144 </div> 101 145 </form> -
main/waeup.sirp/trunk/src/waeup/sirp/applicants/interfaces.py
r7240 r7250 29 29 from zope.security.interfaces import IGroupClosureAwarePrincipal as IPrincipal 30 30 from zc.sourcefactory.basic import BasicSourceFactory 31 from waeup.sirp.interfaces import IWAeUPObject, year_range, validate_email 31 from waeup.sirp.interfaces import ( 32 IWAeUPObject, year_range, validate_email, academic_sessions_vocab) 32 33 from waeup.sirp.university.vocabularies import application_categories 33 34 from waeup.sirp.students.vocabularies import ( … … 38 39 AppCatCertificateSource, 39 40 ) 41 from waeup.sirp.payments.interfaces import IOnlinePayment 40 42 41 43 #: Maximum upload size for applicant passport photographs (in bytes) … … 351 353 ) 352 354 student_id = schema.TextLine( 353 title = u'Student I D',355 title = u'Student Id', 354 356 required = False, 355 357 readonly = True, … … 398 400 readonly = True, 399 401 ) 402 403 class IApplicantOnlinePayment(IOnlinePayment): 404 """An applicant payment via payment gateways. 405 406 """ 407 p_year = schema.Choice( 408 title = u'Payment Session', 409 source = academic_sessions_vocab, 410 required = False, 411 ) 412 413 IApplicantOnlinePayment['p_year'].order = IApplicantOnlinePayment[ 414 'p_year'].order 400 415 401 416 class IApplicantsContainerProvider(Interface): -
main/waeup.sirp/trunk/src/waeup/sirp/applicants/permissions.py
r7240 r7250 30 30 31 31 class ViewApplicationsTab(grok.Permission): 32 grok.name('waeup.viewApplica tionsTab')32 grok.name('waeup.viewApplicantsTab') 33 33 34 34 class ViewMyApplicationDataTab(grok.Permission): … … 38 38 grok.name('waeup.manageApplication') 39 39 40 class PayApplicant(grok.Permission): 41 grok.name('waeup.payApplicant') 42 40 43 # Local role 41 44 class ApplicationOwner(grok.Role): … … 43 46 grok.title(u'Application Owner') 44 47 grok.permissions('waeup.handleApplication', 'waeup.viewApplication', 45 'waeup.Authenticated' )48 'waeup.Authenticated', 'waeup.payApplicant') 46 49 47 50 # Site role … … 55 58 grok.title(u'Applications Officer') 56 59 grok.permissions('waeup.manageApplication', 'waeup.viewApplication' 57 'waeup.viewApplica tionsTab')60 'waeup.viewApplicantsTab', 'waeup.payApplicant') -
main/waeup.sirp/trunk/src/waeup/sirp/applicants/workflow.py
r7192 r7250 28 28 INITIALIZED = 'initialized' 29 29 STARTED = 'started' 30 PAID = 'paid' 30 31 SUBMITTED = 'submitted' 31 32 ADMITTED = 'admitted' … … 50 51 51 52 Transition( 53 transition_id = 'pay', 54 title = 'Pay acceptance fee', 55 msg = 'Fee paid', 56 source = STARTED, 57 destination = PAID), 58 59 Transition( 52 60 transition_id = 'submit', 53 61 title = 'Submit application', 54 62 msg = 'Application submitted', 55 source = STARTED,63 source = PAID, 56 64 destination = SUBMITTED), 57 65 … … 86 94 Transition( 87 95 transition_id = 'reset1', 88 title = 'Reset application ',96 title = 'Reset application to started', 89 97 msg = 'Application reset', 90 98 source = SUBMITTED, … … 93 101 Transition( 94 102 transition_id = 'reset2', 95 title = 'Reset application ',103 title = 'Reset application to started', 96 104 msg = 'Application reset', 97 105 source = ADMITTED, … … 100 108 Transition( 101 109 transition_id = 'reset3', 102 title = 'Reset application ',110 title = 'Reset application to started', 103 111 msg = 'Application reset', 104 112 source = NOT_ADMITTED, … … 107 115 Transition( 108 116 transition_id = 'reset4', 109 title = 'Reset application ',117 title = 'Reset application to started', 110 118 msg = 'Application reset', 111 119 source = CREATED, 112 120 destination = STARTED), 121 Transition( 122 transition_id = 'reset5', 123 title = 'Reset application to paid', 124 msg = 'Application reset', 125 source = SUBMITTED, 126 destination = PAID), 113 127 ) 114 128 -
main/waeup.sirp/trunk/src/waeup/sirp/interfaces.py
r7233 r7250 458 458 ) 459 459 460 acceptance_fee = schema.Int( 461 title = u'Acceptance Fee', 462 default = 0, 463 ) 464 460 465 def getSessionString(): 461 466 """Returns the session string from the vocabulary. -
main/waeup.sirp/trunk/src/waeup/sirp/payments/vocabularies.py
r7195 r7250 32 32 ('Transfer','transfer'), 33 33 ('Gown','gown'), 34 ('Acceptance Fee', 'acceptance'), 34 35 ) -
main/waeup.sirp/trunk/src/waeup/sirp/permissions.py
r7242 r7250 114 114 'waeup.managePortalConfiguration', 'waeup.viewApplication', 115 115 'waeup.manageApplication', 'waeup.handleApplication', 116 'waeup.viewApplicationsTab', 117 'waeup.viewStudent', 'waeup.manageStudent', 'clearStudent', 118 'waeup.uploadStudentFile', 116 'waeup.viewApplicantsTab', 'waeup.payApplicant', 117 'waeup.viewStudent', 'waeup.manageStudent', 118 'waeup.clearStudent', 'waeup.payStudent', 119 'waeup.uploadStudentFile', 'waeup.showStudents', 120 'waeup.viewStudentsContainer','waeup.viewStudentsTab', 119 121 'waeup.viewHostels', 'waeup.manageHostels', 120 'waeup.showStudents',121 'waeup.viewStudentsContainer','waeup.viewStudentsTab',122 122 ) 123 123
Note: See TracChangeset for help on using the changeset viewer.