· 6 years ago · Apr 26, 2020, 08:18 AM
1"""
2LiqPay Python SDK
3~~~~~~~~~~~~~~~~~
4supports python 3 version
5requires requests module
6"""
7
8__title__ = "LiqPay Python SDK"
9__version__ = "1.0"
10
11import base64
12from copy import deepcopy
13import hashlib
14import json
15from urllib.parse import urljoin
16
17import requests
18
19
20class ParamValidationError(Exception):
21 pass
22
23
24class LiqPay(object):
25 FORM_TEMPLATE = """\
26 <form method="post" action="{action}" accept-charset="utf-8">
27 \t{param_inputs}
28 <input type="image" src="//static.liqpay.ua/buttons/p1{language}.radius.png" name="btn_text" />
29 </form>"""
30 INPUT_TEMPLATE = "<input type='hidden' name='{name}' value='{value}'/>"
31
32 SUPPORTED_PARAMS = [
33 "public_key", "amount", "currency", "description", "order_id",
34 "result_url", "server_url", "type", "signature", "language", "sandbox"
35 ]
36
37 def __init__(self, public_key, private_key, host="https://www.liqpay.ua/api/"):
38 self._public_key = public_key
39 self._private_key = private_key
40 self._host = host
41
42 def _make_signature(self, *args):
43 joined_fields = "".join(x for x in args)
44 joined_fields = joined_fields.encode("utf-8")
45 return base64.b64encode(hashlib.sha1(joined_fields).digest()).decode("ascii")
46
47 def _prepare_params(self, params):
48 params = {} if params is None else deepcopy(params)
49 params.update(public_key=self._public_key)
50 return params
51
52 def api(self, url, params=None):
53 params = self._prepare_params(params)
54
55 json_encoded_params = json.dumps(params)
56 private_key = self._private_key
57 signature = self._make_signature(private_key, json_encoded_params, private_key)
58
59 request_url = urljoin(self._host, url)
60 request_data = {"data": json_encoded_params, "signature": signature}
61 response = requests.post(request_url, data=request_data, verify=False)
62 return json.loads(response.content.decode("utf-8"))
63
64 def cnb_form(self, params):
65 params = self._prepare_params(params)
66 params_validator = (
67 ("amount", lambda x: x is not None and float(x) > 0),
68 ("description", lambda x: x is not None)
69 )
70 for key, validator in params_validator:
71 if validator(params.get(key)):
72 continue
73
74 raise ParamValidationError("Invalid param: '{}'".format(key))
75
76 # spike to set correct values for language, currency and sandbox params
77 language = params.get("language", "ru")
78 currency = params["currency"]
79 params.update(
80 language=language,
81 currency=currency if currency != "RUR" else "RUB",
82 sandbox=int(bool(params.get("sandbox")))
83 )
84
85 encoded_data = self.data_to_sign(params)
86 params_templ = {"data": encoded_data}
87
88 params_templ["signature"] = self._make_signature(self._private_key, params_templ["data"], self._private_key)
89 form_action_url = urljoin(self._host, "3/checkout/")
90 format_input = (lambda k, v: self.INPUT_TEMPLATE.format(name=k, value=v))
91 inputs = [format_input(k, v) for k, v in params_templ.items()]
92 return self.FORM_TEMPLATE.format(
93 action=form_action_url,
94 language=language,
95 param_inputs="\n\t".join(inputs)
96 )
97
98 def cnb_signature(self, params):
99 params = self._prepare_params(params)
100
101 data_to_sign = self.data_to_sign(params)
102 return self._make_signature(self._private_key, data_to_sign, self._private_key)
103
104 def cnb_data(self, params):
105 params = self._prepare_params(params)
106 return self.data_to_sign(params)
107
108 def str_to_sign(self, str):
109 return base64.b64encode(hashlib.sha1(str.encode("utf-8")).digest()).decode("ascii")
110
111 def data_to_sign(self, params):
112 return base64.b64encode(json.dumps(params).encode("utf-8")).decode("ascii")
113
114 def decode_data_from_str(self, data):
115 """Decoding data that were encoded by base64.b64encode(str)
116 Note:
117 Often case of using is decoding data from LiqPay Callback.
118 Dict contains all information about payment.
119 More info about callback params see in documentation
120 https://www.liqpay.ua/documentation/api/callback.
121 Args:
122 data: json string with api params and encoded by base64.b64encode(str).
123 Returns:
124 Dict
125 Example:
126 liqpay = LiqPay(settings.LIQPAY_PUBLIC_KEY, settings.LIQPAY_PRIVATE_KEY)
127 data = request.POST.get('data')
128 response = liqpay.decode_data_from_str(data)
129 print(response)
130 {'commission_credit': 0.0, 'order_id': 'order_id_1', 'liqpay_order_id': 'T8SRXWM71509085055293216', ...}
131 """
132 return json.loads(base64.b64decode(data).decode('utf-8'))