source: main/kofacustom.nigeria/trunk/src/kofacustom/nigeria/remita/applicantsbrowser.py @ 14787

Last change on this file since 14787 was 14779, checked in by Henrik Bettermann, 7 years ago

Log RRR retrieval.

File size: 10.2 KB
Line 
1## $Id: browser.py 14759 2017-08-03 09:09:54Z 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.applicants.browser import OnlinePaymentDisplayFormPage as OPDPApplicant
28from kofacustom.nigeria.remita.helpers import (
29    get_JSON_POST_response, query_remita, write_payments_log)
30from kofacustom.nigeria.payments.interfaces import INigeriaOnlinePayment
31from kofacustom.nigeria.applicants.interfaces import INigeriaApplicantOnlinePayment
32from kofacustom.nigeria.interfaces import MessageFactory as _
33from kofacustom.nigeria.remita.studentsbrowser import module_activated
34
35grok.templatedir('browser_templates')
36
37# Buttons
38
39class RemitaActionButtonApplicant(ManageActionButton):
40    grok.order(1)
41    grok.context(INigeriaOnlinePayment)
42    grok.view(OPDPApplicant)
43    grok.require('waeup.payApplicant')
44    icon = 'actionicon_pay.png'
45    text = _('Pay via Remita')
46    target = 'goto_remita'
47
48    @property
49    def target_url(self):
50        if not module_activated(self.context.__parent__.__parent__.year):
51            return ''
52        if self.context.p_state != 'unpaid':
53            return ''
54        return self.view.url(self.view.context, self.target)
55
56class RemitaRequestPaymentStatusActionButtonApplicant(ManageActionButton):
57    grok.order(2)
58    grok.context(INigeriaOnlinePayment)
59    grok.view(OPDPApplicant)
60    grok.require('waeup.payApplicant')
61    icon = 'actionicon_call.png'
62    text = _('Requery Remita Payment Status')
63    target = 'request_payment_status'
64
65    @property
66    def target_url(self):
67        if not module_activated(self.context.__parent__.__parent__.year):
68            return ''
69        if self.context.p_state in ('paid', 'waived'):
70            return ''
71        return self.view.url(self.view.context, self.target)
72
73class RemitaVerifyPaymentStatusActionButtonApplicant(ManageActionButton):
74    grok.order(3)
75    grok.context(INigeriaOnlinePayment)
76    grok.view(OPDPApplicant)
77    grok.require('waeup.manageApplication')
78    icon = 'actionicon_call.png'
79    text = _('Verify Remita Payment Status')
80    target = 'verify_payment_status'
81
82    @property
83    def target_url(self):
84        if not module_activated(self.context.__parent__.__parent__.year):
85            return ''
86        if self.context.p_state != 'paid' \
87            or self.context.r_company != u'remita':
88            return ''
89        return self.view.url(self.view.context, self.target)
90
91# Webservice request views
92
93class RemitaRequestPaymentStatusPageApplicant(UtilityView, grok.View):
94    """ Request webservice view for the Remita gateway.
95    """
96    grok.context(INigeriaApplicantOnlinePayment)
97    grok.name('request_payment_status')
98    grok.require('waeup.payApplicant')
99
100    # Here we use Remita test portal data
101    merchantId = '2547916'
102    host = 'www.remitademo.net'
103    https = False
104    api_key = '1946'
105
106    def update(self):
107        if not module_activated(self.context.__parent__.__parent__.year):
108            return
109        if self.context.p_state in ('paid', 'waived'):
110            self.flash(_('This ticket has already been paid.'), type='danger')
111            return
112        applicant = self.context.__parent__
113        RRR = self.context.r_pay_reference
114        if not RRR:
115            self.flash(_('Remita Retrieval Reference not found.'), type='danger')
116            return
117        # Remita sends a POST request which may contain more information
118        # if a payment was not successful.
119        resp = self.request.form
120        if resp and resp.get('statuscode') not in (None, '025', '00', '01'):
121            self.flash('Transaction status message from Remita: %s'
122                % resp.get('status'), type='warning')
123        success, msg, log = query_remita(
124            self.context,
125            self.merchantId,
126            self.api_key,
127            RRR,
128            self.host,
129            self.https,
130            False)
131        applicant.writeLogMessage(self, log)
132        if not success:
133            self.flash(msg, type='danger')
134            return
135        write_payments_log(applicant.applicant_id, self.context)
136        flashtype, msg, log = self.context.doAfterApplicantPayment()
137        if log is not None:
138            applicant.writeLogMessage(self, log)
139        self.flash(msg, type=flashtype)
140        return
141
142    def render(self):
143        self.redirect(self.url(self.context, '@@index'))
144        return
145
146class RemitaVerifyPaymentStatusPageApplicant(UtilityView, grok.View):
147    """ Request webservice view for the Remita gateway.
148    """
149    grok.context(INigeriaApplicantOnlinePayment)
150    grok.name('verify_payment_status')
151    grok.require('waeup.manageApplication')
152
153    # Here we use Remita test portal data
154    merchantId = '2547916'
155    host = 'www.remitademo.net'
156    https = False
157    api_key = '1946'
158
159    def update(self):
160        if not module_activated(self.context.__parent__.__parent__.year):
161            return
162        if self.context.p_state  != 'paid' \
163            or self.context.r_company != u'remita':
164            self.flash(_('This ticket has not been paid.'), type='danger')
165            return
166        applicant = self.context.__parent__
167        RRR = self.context.r_pay_reference
168        if not RRR:
169            self.flash(_('Remita Retrieval Reference not found.'), type='danger')
170            return
171        # Remita sends a POST request which may contain more information
172        # if a payment was not successful.
173        resp = self.request.form
174        if resp and resp.get('statuscode') not in (None, '025', '00', '01'):
175            self.flash('Transaction status message from Remita: %s'
176                % resp.get('status'), type='warning')
177        success, msg, log = query_remita(
178            self.context,
179            self.merchantId,
180            self.api_key,
181            RRR,
182            self.host,
183            self.https,
184            True)
185        applicant.writeLogMessage(self, log)
186        if not success:
187            self.flash(msg, type='danger')
188            return
189        self.flash(msg)
190        return
191
192    def render(self):
193        self.redirect(self.url(self.context, '@@index'))
194        return
195
196
197# Forwarding pages
198
199class RemitaPageApplicant(KofaPage):
200    """ View which sends a POST request to the Remita payment gateway.
201    """
202    grok.context(INigeriaApplicantOnlinePayment)
203    grok.name('goto_remita')
204    grok.template('goto_remita')
205    grok.require('waeup.payApplicant')
206    label = _('Pay via Remita')
207    submit_button = _('Pay now')
208    https = False
209
210    # Here we use Remita test portal data
211    merchantId = '2547916'
212    serviceTypeId = '4430731'
213    api_key = '1946'
214    orderId = '3456346346'
215    host = 'www.remitademo.net'
216    init_url = '/remita/ecomm/split/init.reg'
217    amount='1000'
218    lineitems = (
219                  {"lineItemsId":"itemid1","beneficiaryName":"Klaus Mueller",
220                  "beneficiaryAccount":"6020067886","bankCode":"011",
221                  "beneficiaryAmount":"500","deductFeeFrom":"1"},
222                  {"lineItemsId":"itemid2","beneficiaryName":"Werner Rumm",
223                  "beneficiaryAccount":"0360883515","bankCode":"050",
224                  "beneficiaryAmount":"500","deductFeeFrom":"0"}
225                )
226
227    action = 'http://www.remitademo.net/remita/ecomm/finalize.reg'
228
229    def init_update(self):
230        if self.context.p_state == 'paid':
231            return _("Payment ticket can't be re-sent to Remita.")
232        now = datetime.utcnow()
233        if self.context.creation_date.tzinfo is not None:
234            # That's bad. Please store timezone-naive datetimes only!
235            now = self.context.creation_date.tzinfo.localize(now)
236        time_delta = now - self.context.creation_date
237        if time_delta.days > 7:
238            return _("This payment ticket is too old. Please create a new ticket.")
239        self.responseurl = self.url(self.context, 'request_payment_status')
240        resp = get_JSON_POST_response(
241            merchantId=self.merchantId,
242            serviceTypeId=self.serviceTypeId,
243            api_key=self.api_key,
244            orderId=self.orderId,
245            amount=self.amount,
246            responseurl=self.responseurl,
247            host=self.host,
248            url=self.init_url,
249            https=self.https,
250            fullname=self.context.__parent__.display_fullname,
251            email=self.context.__parent__.email,
252            lineitems=self.lineitems)
253        if resp.get('error'):
254            return resp.get('error')
255        if resp.get('statuscode') not in ('021', '025', '055'):
256            return 'RRR generation message from Remita: ' + resp.get('status')
257        # Already now it becomes a Remita payment
258        self.context.r_company = u'remita'
259        self.rrr = self.context.r_pay_reference = resp['RRR'].rstrip()
260        hashargs =      self.merchantId + self.rrr + self.api_key
261        self.hashvalue = hashlib.sha512(hashargs).hexdigest()
262        self.customer = self.context.__parent__
263        self.customer.writeLogMessage(self, 'RRR retrieved: %s' % self.rrr)
264        return
265
266    def update(self):
267        if not module_activated(self.context.__parent__.__parent__.year):
268            return
269        error = self.init_update()
270        if error:
271            self.flash(error, type='danger')
272            self.redirect(self.url(self.context, '@@index'))
273            return
274        return
Note: See TracBrowser for help on using the repository browser.