source: main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/remita/studentsbrowser.py @ 15945

Last change on this file since 15945 was 15842, checked in by Henrik Bettermann, 5 years ago

Show correct buttons if payment state in ('paid', 'waived', 'scholarship').

  • Property svn:keywords set to Id
File size: 11.6 KB
RevLine 
[14743]1## $Id: studentsbrowser.py 15842 2019-11-25 11:02:44Z henrik $
2##
3## Copyright (C) 2017 Uli Fouquet & Henrik Bettermann
4## This program is free software; you can redistribute it and/or modify
5## it under the terms of the GNU General Public License as published by
6## the Free Software Foundation; either version 2 of the License, or
7## (at your option) any later version.
8##
9## This program is distributed in the hope that it will be useful,
10## but WITHOUT ANY WARRANTY; without even the implied warranty of
11## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12## GNU General Public License for more details.
13##
14## You should have received a copy of the GNU General Public License
15## along with this program; if not, write to the Free Software
16## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17##
18import grok
19import hashlib
20from datetime import datetime, timedelta
21from zope.component import getUtility
22from zope.security import checkPermission
23from waeup.kofa.interfaces import IKofaUtils
24from waeup.kofa.utils.helpers import to_timezone
25from waeup.kofa.browser.layout import UtilityView, KofaPage
26from waeup.kofa.browser.viewlets import ManageActionButton
27from waeup.kofa.students.interfaces import IStudentsUtils
28from waeup.kofa.students.browser import OnlinePaymentDisplayFormPage as OPDPStudent
29from kofacustom.nigeria.remita.helpers import (
30    get_JSON_POST_response, query_remita, write_payments_log)
31from kofacustom.nigeria.payments.interfaces import INigeriaOnlinePayment
32from kofacustom.nigeria.students.interfaces import INigeriaStudentOnlinePayment
33from kofacustom.nigeria.interfaces import MessageFactory as _
34
[14790]35from kofacustom.nigeria.remita.tests import (
[15755]36    MERCHANTID, HOST, HTTPS, API_KEY, SERVICETYPEID, GATEWAY_AMT)
[14790]37
[14765]38grok.templatedir('browser_templates')
39
[15770]40def module_activated(session, payment):
[15825]41    if payment.r_company and payment.r_company != 'remita':
[15770]42        return False
[14743]43    try:
44        return getattr(grok.getSite()['configuration'][str(session)],
[14755]45            'remita_enabled', False)
[14743]46    except KeyError:
47        return False
48
49# Buttons
50
51class RemitaActionButtonStudent(ManageActionButton):
52    grok.order(1)
53    grok.context(INigeriaOnlinePayment)
54    grok.view(OPDPStudent)
55    grok.require('waeup.payStudent')
56    icon = 'actionicon_pay.png'
57    text = _('Pay via Remita')
58    target = 'goto_remita'
59
60    @property
61    def target_url(self):
[15770]62        if not module_activated(
63            self.context.student.current_session, self.context):
[14743]64            return ''
65        if self.context.p_state != 'unpaid':
66            return ''
67        return self.view.url(self.view.context, self.target)
68
[14753]69class RemitaRequestPaymentStatusActionButtonStudent(ManageActionButton):
70    grok.order(2)
71    grok.context(INigeriaOnlinePayment)
72    grok.view(OPDPStudent)
73    grok.require('waeup.payStudent')
74    icon = 'actionicon_call.png'
75    text = _('Requery Remita Payment Status')
76    target = 'request_payment_status'
77
78    @property
79    def target_url(self):
[15770]80        if not module_activated(
81            self.context.student.current_session, self.context):
[14753]82            return ''
[15842]83        if self.context.p_state in ('paid', 'waived', 'scholarship'):
[14753]84            return ''
85        return self.view.url(self.view.context, self.target)
86
87
88class RemitaVerifyPaymentStatusActionButtonStudent(ManageActionButton):
89    grok.order(3)
90    grok.context(INigeriaOnlinePayment)
91    grok.view(OPDPStudent)
92    grok.require('waeup.manageStudent')
93    icon = 'actionicon_call.png'
94    text = _('Verify Remita Payment Status')
95    target = 'verify_payment_status'
96
97    @property
98    def target_url(self):
[15770]99        if not module_activated(
100            self.context.student.current_session, self.context):
[14753]101            return ''
102        if self.context.p_state != 'paid' \
103            or self.context.r_company != u'remita':
104            return ''
105        return self.view.url(self.view.context, self.target)
106
[14743]107# Webservice request views
108
[14753]109class RemitaRequestPaymentStatusPageStudent(UtilityView, grok.View):
[14743]110    """ Request webservice view for the Remita gateway.
111    """
112    grok.context(INigeriaStudentOnlinePayment)
113    grok.name('request_payment_status')
114    grok.require('waeup.payStudent')
115
[14790]116    merchantId = MERCHANTID
117    host = HOST
118    https = HTTPS
119    api_key = API_KEY
[14743]120
121    def update(self):
[15770]122        if not module_activated(
123            self.context.student.current_session, self.context):
[14743]124            return
[15842]125        if self.context.p_state in ('paid', 'waived', 'scholarship'):
[14743]126            self.flash(_('This ticket has already been paid.'), type='danger')
127            return
128        student = self.context.student
129        RRR = self.context.r_pay_reference
130        if not RRR:
131            self.flash(_('Remita Retrieval Reference not found.'), type='danger')
132            return
133        # Remita sends a POST request which may contain more information
134        # if a payment was not successful.
135        resp = self.request.form
[14750]136        if resp and resp.get('statuscode') not in (None, '025', '00', '01'):
137            self.flash('Transaction status message from Remita: %s'
138                % resp.get('status'), type='warning')
[14743]139        success, msg, log = query_remita(
140            self.context,
141            self.merchantId,
142            self.api_key,
143            RRR,
144            self.host,
145            self.https,
146            False)
147        student.writeLogMessage(self, log)
148        if not success:
149            self.flash(msg, type='danger')
150            return
151        write_payments_log(student.student_id, self.context)
152        flashtype, msg, log = self.context.doAfterStudentPayment()
153        if log is not None:
154            student.writeLogMessage(self, log)
155        self.flash(msg, type=flashtype)
156        return
157
158    def render(self):
159        self.redirect(self.url(self.context, '@@index'))
160        return
161
[14753]162class RemitaVerifyPaymentStatusPageStudent(UtilityView, grok.View):
163    """ Request webservice view for the Remita gateway.
164    """
165    grok.context(INigeriaStudentOnlinePayment)
166    grok.name('verify_payment_status')
[14765]167    grok.require('waeup.manageStudent')
[14753]168
[14790]169    merchantId = MERCHANTID
170    host = HOST
171    https = HTTPS
172    api_key = API_KEY
[14753]173
174    def update(self):
[15770]175        if not module_activated(
176            self.context.student.current_session, self.context):
[14753]177            return
178        if self.context.p_state  != 'paid' \
179            or self.context.r_company != u'remita':
180            self.flash(_('This ticket has not been paid.'), type='danger')
181            return
182        student = self.context.student
183        RRR = self.context.r_pay_reference
184        if not RRR:
185            self.flash(_('Remita Retrieval Reference not found.'), type='danger')
186            return
187        # Remita sends a POST request which may contain more information
188        # if a payment was not successful.
189        resp = self.request.form
190        if resp and resp.get('statuscode') not in (None, '025', '00', '01'):
191            self.flash('Transaction status message from Remita: %s'
192                % resp.get('status'), type='warning')
193        success, msg, log = query_remita(
194            self.context,
195            self.merchantId,
196            self.api_key,
197            RRR,
198            self.host,
199            self.https,
200            True)
201        student.writeLogMessage(self, log)
202        if not success:
203            self.flash(msg, type='danger')
204            return
[14765]205        self.flash(msg)
[14753]206        return
207
208    def render(self):
209        self.redirect(self.url(self.context, '@@index'))
210        return
211
212
[14743]213# Forwarding pages
214
215class RemitaPageStudent(KofaPage):
216    """ View which sends a POST request to the Remita payment gateway.
217    """
218    grok.context(INigeriaOnlinePayment)
219    grok.name('goto_remita')
[14765]220    grok.template('goto_remita')
[14743]221    grok.require('waeup.payStudent')
222    label = _('Pay via Remita')
223    submit_button = _('Pay now')
224
[14790]225    merchantId = MERCHANTID
226    host = HOST
227    https = HTTPS
228    api_key = API_KEY
229    serviceTypeId = SERVICETYPEID
[15755]230    gateway_amt = GATEWAY_AMT
[14790]231
[14805]232    #orderId = '3456346346'
[14743]233    init_url = '/remita/ecomm/split/init.reg'
234    amount='1000'
235    lineitems = (
236                  {"lineItemsId":"itemid1","beneficiaryName":"Klaus Mueller",
237                  "beneficiaryAccount":"6020067886","bankCode":"011",
238                  "beneficiaryAmount":"500","deductFeeFrom":"1"},
239                  {"lineItemsId":"itemid2","beneficiaryName":"Werner Rumm",
240                  "beneficiaryAccount":"0360883515","bankCode":"050",
241                  "beneficiaryAmount":"500","deductFeeFrom":"0"}
242                )
243
[14796]244    @property
245    def action(self):
[14798]246        if self.https:
247            return 'https://' + self.host + '/remita/ecomm/finalize.reg'
248        return 'http://' + self.host + '/remita/ecomm/finalize.reg'
[14743]249
250    def init_update(self):
251        if self.context.p_state == 'paid':
252            return _("Payment ticket can't be re-sent to Remita.")
[15755]253        if self.context.r_company and self.context.r_company != 'remita':
254            return _("Payment ticket has been used for another payment gateway.")
[14743]255        now = datetime.utcnow()
256        if self.context.creation_date.tzinfo is not None:
257            # That's bad. Please store timezone-naive datetimes only!
258            now = self.context.creation_date.tzinfo.localize(now)
259        time_delta = now - self.context.creation_date
260        if time_delta.days > 7:
261            return _("This payment ticket is too old. Please create a new ticket.")
[14765]262        certificate = getattr(self.context.student['studycourse'],'certificate',None)
[14743]263        if certificate is None:
264            return _("Study course data are incomplete.")
265        kofa_utils = getUtility(IKofaUtils)
266        student_utils = getUtility(IStudentsUtils)
[14765]267        if student_utils.samePaymentMade(self.context.student, self.context.p_category,
[14743]268            self.context.p_item, self.context.p_session):
269            return _("This type of payment has already been made.")
270        self.responseurl = self.url(self.context, 'request_payment_status')
271        resp = get_JSON_POST_response(
272            merchantId=self.merchantId,
273            serviceTypeId=self.serviceTypeId,
274            api_key=self.api_key,
275            orderId=self.orderId,
276            amount=self.amount,
277            responseurl=self.responseurl,
278            host=self.host,
279            url=self.init_url,
280            https=self.https,
[14765]281            fullname=self.context.student.display_fullname,
282            email=self.context.student.email,
[14743]283            lineitems=self.lineitems)
284        if resp.get('error'):
285            return resp.get('error')
286        if resp.get('statuscode') not in ('021', '025', '055'):
[14750]287            return 'RRR generation message from Remita: ' + resp.get('status')
[14743]288        self.rrr = self.context.r_pay_reference = resp['RRR'].rstrip()
289        hashargs =      self.merchantId + self.rrr + self.api_key
290        self.hashvalue = hashlib.sha512(hashargs).hexdigest()
[14765]291        self.customer = self.context.student
[14793]292        self.customer.writeLogMessage(self,
293            'RRR retrieved: %s, ServiceTypeId: %s'
294            % (self.rrr, self.serviceTypeId))
[14743]295        return
296
297    def update(self):
[15770]298        if not module_activated(
299            self.context.student.current_session, self.context):
[14743]300            return
[14805]301        self.orderId = self.context.p_id
[14743]302        error = self.init_update()
303        if error:
304            self.flash(error, type='danger')
305            self.redirect(self.url(self.context, '@@index'))
306            return
[15755]307        # Already now it becomes a Remita payment. We set the net amount
308        # and add the gateway amount.
309        if not self.context.r_company:
310            self.context.net_amt = self.context.amount_auth
311            self.context.amount_auth += self.gateway_amt
312            self.context.gateway_amt = self.gateway_amt
313            self.context.r_company = u'remita'
314        self.amount_auth = int(100 * self.context.amount_auth)
[14743]315        return
Note: See TracBrowser for help on using the repository browser.