forked from burhan/knet-client
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.py
189 lines (143 loc) · 6.08 KB
/
main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
#encoding: UTF-8
"""
KNET Client
Copyright (C) 2012 Burhan Khalid <[email protected]>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
A sample e24PaymentPipe client for KNET. Use this as inspiration
(or directly in your code) when you need to provide a KNET payment
gateway for your application.
It has minimal requirements and is written in Flask using SQLAlchemy
as the database ORM.
"""
from datetime import date
from datetime import datetime
from flask import Flask, request, redirect, render_template, flash
from flask.helpers import url_for
from flaskext.sqlalchemy import SQLAlchemy
from knet.api import e24PaymentPipe as gw
app = Flask(__name__)
app.config.from_pyfile('settings.cfg')
# Setting up a default database to be used for knet specific information
# In production, you should probably change this to point to an existing database
#app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///knet.db'
#app.config['SECRET_KEY'] = 'changeme' # change this!
db = SQLAlchemy(app)
# Change these to match your server URLs
# These are required for KNET, but can
# be customized to your needs.
ERROR_URL = app.config['ERROR_URL']
SUCCESS_URL = app.config['SUCCESS_URL']
RESPONSE_URL = app.config['RESPONSE_URL']
knet = gw('resource.cgn', app.config['KNET_ALIAS'])
knet.ERROR_URL = ERROR_URL
knet.RESPONSE_URL = RESPONSE_URL
class Transaction(db.Model):
__tablename__ = 'KNET_TRANS'
id = db.Column(db.Integer, primary_key=True)
transaction_id = db.Column(db.String(50))
payment_id = db.Column(db.String(50))
tracking_id = db.Column(db.String(50))
reference = db.Column(db.String(50), default=None)
total = db.Column(db.Float, default=0.000)
result = db.Column(db.String(100))
postdate = db.Column(db.Date)
auth = db.Column(db.String(50))
order_id = db.Column(db.String(50))
def __init__(self, tracking, order, total=1.000):
self.tracking_id = tracking
self.total = total
self.order_id = order
def __repr__(self):
return '<KNET R: {0} | T: {1} | O: {2}>'.format(self.payment_id, self.total, self.order_id)
@app.route('/error/<pid>')
@app.route('/error')
def error(pid=None):
pid = request.args.get('PaymentID') or pid
if pid:
t = Transaction.query.filter_by(payment_id=pid).first()
flash('Oops! There was an error with your payment!')
return render_template('error.html', t=t)
else:
return 'There was an error with your request'
@app.route('/thank-you/<pid>')
def thanks(pid):
# Fetch the object for this payment ID
if not pid:
return 'ERROR'
else:
t = Transaction.query.filter_by(payment_id=pid).first()
flash('Your payment was successful')
return render_template('thanks.html', t=t)
@app.route('/result/', methods=['POST'])
def result():
# Get the paymentid
pid = request.form.get('paymentid')
t = Transaction.query.filter_by(payment_id=pid).first() or None
if not t:
return redirect(url_for('error'))
# We have the transaction, now fill in the rest of the fields
r = request.form.get('result')
t.result = r
t.postdate = date(date.today().year, int(request.form.get('postdate')[:2]), int(request.form.get('postdate')[2:]))
t.transaction_id = request.form.get('tranid')
t.tracking_id = request.form.get('trackid')
t.reference = request.form.get('ref')
t.auth = request.form.get('auth')
# Store the result
db.session.add(t)
db.session.commit()
if r == unicode('CANCELLED') or r == unicode('NOT CAPTURED'):
return 'REDIRECT=%s/%s' % (ERROR_URL, pid)
return 'REDIRECT=%s%s' % (SUCCESS_URL, pid)
@app.route('/<id>/<total>/<trackingid>/<udf>')
@app.route('/<id>/<total>/<trackingid>/')
@app.route('/<id>/<total>/')
def entry(id, trackingid=None, total=1.000, udf=None):
"""
This is the main entry point for the server, you pass it three things:
1. The ID of the transaction from your database - this could be a receipt
number or any other unique identifier.
2. The amount that needs to be paid. Minimum is 1, which is the default.
3. A unique tracking ID. This is optional, but highly recommended. KNET
requires this for their backend. If you don't pass one, the system
generates one with the following pattern:
YYYYMMDD-ID-HHMMSS
5. Optional UDF fields (1-5)
Example URL:
/12/34.345/ABC-TRACK/abc,[email protected],hello
12 = ID
34.345 = Amount to be charged
ABC-TRACK = Tracking ID
abc = UDF field 1
[email protected] = UDF field 2
hello = UDF field 3
Restrictions - none of your fields can include the / character
"""
# - Check if this order has already been paid
t = Transaction.query.filter_by(order_id=id, result='CAPTURED').first()
if t is not None:
return 'You have already paid for this order.'
# 2 - Build and dispatch KNET URL
trackid = trackingid or '{0.year}{0.month}{0.day}-{1}-{0.hour}{0.minute}{0.second}'.format(datetime.now(), id)
knet.parse()
if udf is not None:
udf = {'udf%s' % udf.find(x): x for x in udf if x is not ','}
payment_id, payment_url = knet.transaction(trackid, amount=total, udf=udf)
# Store information in DB
t = Transaction(trackid, id, total)
t.payment_id = payment_id
db.session.add(t)
db.session.commit()
return redirect(payment_url + '?PaymentID=' + payment_id)
if __name__ == '__main__':
db.create_all() # This will reset and recreate the database on each restart of the system
app.run(debug=True)