1 | ## $Id: webservices.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 | ## |
---|
18 | |
---|
19 | import grok |
---|
20 | import json |
---|
21 | from zope.component import getUtility |
---|
22 | from zope.catalog.interfaces import ICatalog |
---|
23 | from waeup.kofa.interfaces import IUniversity |
---|
24 | from kofacustom.nigeria.remita.helpers import query_remita, write_payments_log |
---|
25 | |
---|
26 | class PaymentNotificationListenerWebservice(grok.View): |
---|
27 | """A webservice to receive payment notifications from |
---|
28 | accepted IP addresses without authentication which trigger |
---|
29 | a query of a Remita transaction status. |
---|
30 | """ |
---|
31 | grok.context(IUniversity) |
---|
32 | grok.name('paymentnotificationlistener') |
---|
33 | grok.require('waeup.Public') |
---|
34 | |
---|
35 | ACCEPTED_IP = ('127.0.0.1',) |
---|
36 | |
---|
37 | # Here we use Remita test portal data |
---|
38 | merchantId = '2547916' |
---|
39 | host = 'www.remitademo.net' |
---|
40 | https = True |
---|
41 | api_key = '1946' |
---|
42 | |
---|
43 | def update(self, P_ID=None): |
---|
44 | |
---|
45 | # Remita sends a JSON POST request with an array with |
---|
46 | # multiple JSON objects: |
---|
47 | # [ |
---|
48 | # { |
---|
49 | # "rrr": "A39359490", |
---|
50 | # "channnel": "BRANCH", |
---|
51 | # "amount": "6500.00", |
---|
52 | # "transactiondate": "19/01/2015", |
---|
53 | # "debitdate": "19/01/2015", |
---|
54 | # "bank": "033", |
---|
55 | # "branch": "033152763", |
---|
56 | # "serviceTypeId": "4430731", |
---|
57 | # "dateSent": "20/01/2015", |
---|
58 | # "dateRequested": "19/01/2015", |
---|
59 | # "orderRef": "4086852511", |
---|
60 | # "payerName": "mujib ishola", |
---|
61 | # "payerEmail": "ishola@specs.com", |
---|
62 | # "payerPhoneNumber": "08141376868", |
---|
63 | # "uniqueIdentifier": 10001 |
---|
64 | # }, |
---|
65 | # {...} |
---|
66 | # ] |
---|
67 | |
---|
68 | real_ip = self.request.get('HTTP_X_FORWARDED_FOR', None) |
---|
69 | if real_ip: |
---|
70 | self.context.logger.info( |
---|
71 | 'PaymentNotificationListenerWebservice called from %s' % real_ip) |
---|
72 | if real_ip and self.ACCEPTED_IP: |
---|
73 | if real_ip not in self.ACCEPTED_IP: |
---|
74 | self.output = '-1' |
---|
75 | return |
---|
76 | requ = self.request.bodyStream.read() |
---|
77 | self.context.logger.info( |
---|
78 | 'PaymentNotificationListenerWebservice request: %s' % requ) |
---|
79 | try: |
---|
80 | parsed_json = json.loads(requ) |
---|
81 | except ValueError: |
---|
82 | self.output = '-2' |
---|
83 | return |
---|
84 | successful = 0 |
---|
85 | failed = 0 |
---|
86 | for payment in parsed_json: |
---|
87 | orderRef = payment.get('orderRef') |
---|
88 | rrr = payment.get('rrr') |
---|
89 | if not orderRef or not rrr: |
---|
90 | failed += 1 |
---|
91 | continue |
---|
92 | cat = getUtility(ICatalog, name='payments_catalog') |
---|
93 | results = list(cat.searchResults(p_id=(orderRef, orderRef))) |
---|
94 | if len(results) != 1: |
---|
95 | failed += 1 |
---|
96 | continue |
---|
97 | ticket = results[0] |
---|
98 | if ticket.p_state in ('waived', 'scholarship'): |
---|
99 | failed += 1 |
---|
100 | continue |
---|
101 | waspaid = (ticket.p_state == 'paid') |
---|
102 | success, msg, log = query_remita( |
---|
103 | ticket, self.merchantId, self.api_key, |
---|
104 | rrr, self.host, self.https, False) |
---|
105 | if not success: |
---|
106 | failed += 1 |
---|
107 | continue |
---|
108 | if hasattr(ticket, 'doAfterStudentPayment'): |
---|
109 | ticket.student.writeLogMessage(self, log) |
---|
110 | successful += 1 |
---|
111 | if not waspaid: |
---|
112 | write_payments_log(ticket.student.student_id, ticket) |
---|
113 | flashtype, msg, log = ticket.doAfterStudentPayment() |
---|
114 | if log is not None: |
---|
115 | ticket.student.writeLogMessage(self, log) |
---|
116 | else: |
---|
117 | applicant = ticket.__parent__ |
---|
118 | applicant.writeLogMessage(self, log) |
---|
119 | successful += 1 |
---|
120 | if not waspaid: |
---|
121 | write_payments_log(applicant.applicant_id, ticket) |
---|
122 | flashtype, msg, log = ticket.doAfterApplicantPayment() |
---|
123 | if log is not None: |
---|
124 | applicant.writeLogMessage(self, log) |
---|
125 | self.output = '%s (%s)' % (successful, failed + successful) |
---|
126 | return |
---|
127 | |
---|
128 | def render(self): |
---|
129 | return self.output |
---|