epoint-python-sdk 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- epoint_python_sdk-0.2.0/.gitignore +14 -0
- epoint_python_sdk-0.2.0/CHANGELOG.md +19 -0
- epoint_python_sdk-0.2.0/LICENSE +21 -0
- epoint_python_sdk-0.2.0/PKG-INFO +154 -0
- epoint_python_sdk-0.2.0/README.md +112 -0
- epoint_python_sdk-0.2.0/examples/django_view.py +23 -0
- epoint_python_sdk-0.2.0/examples/epoint.toml +6 -0
- epoint_python_sdk-0.2.0/pyproject.toml +65 -0
- epoint_python_sdk-0.2.0/src/epoint_sdk/__init__.py +73 -0
- epoint_python_sdk-0.2.0/src/epoint_sdk/_core.py +209 -0
- epoint_python_sdk-0.2.0/src/epoint_sdk/_version.py +1 -0
- epoint_python_sdk-0.2.0/src/epoint_sdk/callbacks.py +31 -0
- epoint_python_sdk-0.2.0/src/epoint_sdk/client.py +55 -0
- epoint_python_sdk-0.2.0/src/epoint_sdk/config.py +108 -0
- epoint_python_sdk-0.2.0/src/epoint_sdk/enums.py +61 -0
- epoint_python_sdk-0.2.0/src/epoint_sdk/errors.py +73 -0
- epoint_python_sdk-0.2.0/src/epoint_sdk/messages.py +60 -0
- epoint_python_sdk-0.2.0/src/epoint_sdk/messages.yaml +43 -0
- epoint_python_sdk-0.2.0/src/epoint_sdk/models.py +278 -0
- epoint_python_sdk-0.2.0/src/epoint_sdk/money.py +40 -0
- epoint_python_sdk-0.2.0/src/epoint_sdk/py.typed +0 -0
- epoint_python_sdk-0.2.0/src/epoint_sdk/resources.py +374 -0
- epoint_python_sdk-0.2.0/src/epoint_sdk/signing.py +49 -0
- epoint_python_sdk-0.2.0/tests/__init__.py +0 -0
- epoint_python_sdk-0.2.0/tests/conftest.py +71 -0
- epoint_python_sdk-0.2.0/tests/test_async.py +32 -0
- epoint_python_sdk-0.2.0/tests/test_messages.py +17 -0
- epoint_python_sdk-0.2.0/tests/test_money.py +25 -0
- epoint_python_sdk-0.2.0/tests/test_payments.py +156 -0
- epoint_python_sdk-0.2.0/tests/test_safety.py +75 -0
- epoint_python_sdk-0.2.0/tests/test_signing.py +53 -0
- epoint_python_sdk-0.2.0/tests/test_wallet_pay.py +93 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.2.0
|
|
4
|
+
|
|
5
|
+
- Apple Pay and Google Pay: `widgets.create` returns `Widget.origin` for `postMessage` checks, `widgets.split` covers `token/split-payment`
|
|
6
|
+
- `WidgetMessage.from_event` reads the widget `postMessage` as an untrusted hint
|
|
7
|
+
- `Transaction.matches(order_id, amount, transaction)` for callback cross checks
|
|
8
|
+
- Signed requests are refused over plain http outside localhost unless `allow_insecure_http` is set
|
|
9
|
+
- Callback `data` over 64 KB and signatures over 128 characters are rejected before hashing
|
|
10
|
+
|
|
11
|
+
## 0.1.0
|
|
12
|
+
|
|
13
|
+
- Sync `Epoint` and async `AsyncEpoint`
|
|
14
|
+
- Payments, saved cards, payouts, split, pre-auth, installments, wallets, Apple Pay and Google Pay widget, invoices, B2B transfers
|
|
15
|
+
- Callback verification from a raw pair or a form mapping
|
|
16
|
+
- Calls that move money are never resent after an ambiguous failure; `OutcomeUnknownError` carries the `order_id`
|
|
17
|
+
- Reads retry with backoff, connection failures retry because nothing was sent
|
|
18
|
+
- Strict `Decimal` amounts, constant time signature checks, private key kept as a secret
|
|
19
|
+
- goodconf settings, endpoint paths and messages are configurable
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 qiyascc
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: epoint-python-sdk
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Typed Python client for the Epoint (epoint.az) payment gateway, sync and async, safe against double charges.
|
|
5
|
+
Project-URL: Homepage, https://theqiyas.cc/projects/epoint-python-sdk/
|
|
6
|
+
Project-URL: Source, https://github.com/qiyascc/epoint-python-sdk
|
|
7
|
+
Project-URL: Author, https://theqiyas.cc
|
|
8
|
+
Project-URL: Issues, https://github.com/qiyascc/epoint-python-sdk/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/qiyascc/epoint-python-sdk/blob/main/CHANGELOG.md
|
|
10
|
+
Author-email: qiyascc <qiyasturk@gmail.com>
|
|
11
|
+
License-Expression: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Keywords: azerbaijan,azn,checkout,epoint,gateway,payment,sdk
|
|
14
|
+
Classifier: Development Status :: 4 - Beta
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Office/Business :: Financial
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Requires-Dist: goodconf>=7.1
|
|
26
|
+
Requires-Dist: httpx<1,>=0.24
|
|
27
|
+
Requires-Dist: pydantic>=2.7
|
|
28
|
+
Requires-Dist: pyyaml>=6
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: goodconf[toml]>=7.1; extra == 'dev'
|
|
31
|
+
Requires-Dist: goodconf[yaml]>=7.1; extra == 'dev'
|
|
32
|
+
Requires-Dist: mypy>=1.8; extra == 'dev'
|
|
33
|
+
Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
|
|
34
|
+
Requires-Dist: pytest>=7; extra == 'dev'
|
|
35
|
+
Requires-Dist: ruff>=0.4; extra == 'dev'
|
|
36
|
+
Requires-Dist: types-pyyaml; extra == 'dev'
|
|
37
|
+
Provides-Extra: toml
|
|
38
|
+
Requires-Dist: goodconf[toml]>=7.1; extra == 'toml'
|
|
39
|
+
Provides-Extra: yaml
|
|
40
|
+
Requires-Dist: goodconf[yaml]>=7.1; extra == 'yaml'
|
|
41
|
+
Description-Content-Type: text/markdown
|
|
42
|
+
|
|
43
|
+
# epoint-python-sdk
|
|
44
|
+
|
|
45
|
+
[](https://www.python.org)
|
|
46
|
+
[](https://epoint.az)
|
|
47
|
+
[](https://mypy-lang.org)
|
|
48
|
+
[](https://www.python-httpx.org)
|
|
49
|
+
[](https://docs.astral.sh/ruff)
|
|
50
|
+
[](#apple-pay-and-google-pay)
|
|
51
|
+
[](#apple-pay-and-google-pay)
|
|
52
|
+
[](https://github.com/qiyascc/epoint-python-sdk/blob/main/LICENSE)
|
|
53
|
+
|
|
54
|
+
Typed Python client for the [Epoint](https://epoint.az) payment gateway. Sync and async, every endpoint, signed callbacks, and retry rules built so a payment is never sent twice.
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
pip install epoint-python-sdk
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Pay
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
from epoint_sdk import Epoint
|
|
64
|
+
|
|
65
|
+
with Epoint("i000000001", "PRIVATE_KEY", success_url="https://shop.az/ok", error_url="https://shop.az/fail") as ep:
|
|
66
|
+
checkout = ep.payments.create("19.90", "ORDER-1042", description="Pro plan")
|
|
67
|
+
redirect(checkout.redirect_url)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Confirm
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
tx = ep.verify_callback(request.POST)
|
|
74
|
+
if tx.paid:
|
|
75
|
+
fulfil(tx.order_id, tx.amount, tx.transaction)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Never trust the redirect alone. Use the signed callback, or ask the gateway:
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
ep.payments.status(checkout.transaction).paid
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Apple Pay and Google Pay
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
widget = ep.widgets.create("19.90", "ORDER-1043", "Pro plan")
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
```html
|
|
91
|
+
<iframe src="{{ widget.widget_url }}" allow="payment" title="Apple Pay / Google Pay"></iframe>
|
|
92
|
+
<script>
|
|
93
|
+
addEventListener("message", (e) => {
|
|
94
|
+
if (e.origin !== "{{ widget.origin }}") return;
|
|
95
|
+
fetch("/orders/1043/check/", { method: "POST" });
|
|
96
|
+
});
|
|
97
|
+
</script>
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
The page needs `Permissions-Policy: payment=(self "https://epoint.az")`. The `postMessage` is a hint only: `WidgetMessage.from_event(data)` reads it, then confirm on the server with `ep.payments.status(widget.transaction)` or the signed callback. Epoint enables token payments per merchant. `ep.widgets.split(...)` is the split variant.
|
|
101
|
+
|
|
102
|
+
## Safety
|
|
103
|
+
|
|
104
|
+
| Situation | What the client does |
|
|
105
|
+
| --- | --- |
|
|
106
|
+
| Connection refused, nothing sent | Retries, then `NotSentError` |
|
|
107
|
+
| Timeout, cut connection or 5xx on a call that moves money | No retry, `OutcomeUnknownError` with the `order_id` |
|
|
108
|
+
| Same failure on a read (status, card, lists) | Retries with backoff |
|
|
109
|
+
| 429 | Retries, the gateway did not process it |
|
|
110
|
+
| `status: error` from the gateway | `GatewayError` with `code` and `trace_id` |
|
|
111
|
+
| Declined card on a direct charge | Returns `Transaction` with `failed`, never raises |
|
|
112
|
+
| Amount like `1.005`, `0`, `NaN` or `True` | `InvalidRequestError` before anything is sent |
|
|
113
|
+
| `base_url` over plain http | `ConfigurationError`, except localhost or `allow_insecure_http` |
|
|
114
|
+
| Callback `data` over 64 KB | Rejected before hashing |
|
|
115
|
+
| Callback for another order or amount | `tx.matches(order_id=..., amount=...)` is `False` |
|
|
116
|
+
|
|
117
|
+
Reuse the same `order_id` when you retry. Epoint refuses a used one, so a double click or a crash can not charge twice. Amounts are `Decimal` end to end, and signatures are compared in constant time.
|
|
118
|
+
|
|
119
|
+
## Endpoints
|
|
120
|
+
|
|
121
|
+
| Namespace | Methods |
|
|
122
|
+
| --- | --- |
|
|
123
|
+
| `payments` | `create` `form` `status` `reverse` `hold` `capture` |
|
|
124
|
+
| `cards` | `register` `register_and_pay` `charge` `status` `payout` |
|
|
125
|
+
| `split` | `create` `charge` `register_and_pay` |
|
|
126
|
+
| `installments` | `plans` `create` |
|
|
127
|
+
| `wallets` | `list` `pay` |
|
|
128
|
+
| `widgets` | `create` `split` (Apple Pay, Google Pay) |
|
|
129
|
+
| `invoices` | `create` `update` `get` `list` `send_sms` `send_email` |
|
|
130
|
+
| `transfers` | `create` `status` (B2B) |
|
|
131
|
+
| client | `heartbeat` `verify_callback` `request` |
|
|
132
|
+
|
|
133
|
+
`AsyncEpoint` has the same methods, awaited.
|
|
134
|
+
|
|
135
|
+
## Config
|
|
136
|
+
|
|
137
|
+
Pass values in code, or set `EPOINT_PUBLIC_KEY`, `EPOINT_PRIVATE_KEY`, `EPOINT_SUCCESS_URL`, `EPOINT_ERROR_URL`, `EPOINT_LANGUAGE`, `EPOINT_TIMEOUT`, `EPOINT_MAX_RETRIES`, or put them in `epoint.toml`. Every path is a setting (`EPOINT_ENDPOINTS__PAYMENT=...`) and `base_url` can point at a sandbox such as [epoint-sandbox](https://github.com/martian56/epoint-sandbox). Messages live in `messages.yaml` and can be replaced with `messages.use(...)`.
|
|
138
|
+
|
|
139
|
+
## Develop
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
pip install -e ".[dev]" && pytest && ruff check . && mypy src
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Links
|
|
146
|
+
|
|
147
|
+
- Source code: [github.com/qiyascc/epoint-python-sdk](https://github.com/qiyascc/epoint-python-sdk)
|
|
148
|
+
- PyPI: [pypi.org/project/epoint-python-sdk](https://pypi.org/project/epoint-python-sdk/)
|
|
149
|
+
- Project page: [theqiyas.cc/projects/epoint-python-sdk](https://theqiyas.cc/projects/epoint-python-sdk/)
|
|
150
|
+
- Author: [Qiyas Sadıqov](https://theqiyas.cc), more projects at [theqiyas.cc](https://theqiyas.cc)
|
|
151
|
+
|
|
152
|
+
## License
|
|
153
|
+
|
|
154
|
+
MIT
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# epoint-python-sdk
|
|
2
|
+
|
|
3
|
+
[](https://www.python.org)
|
|
4
|
+
[](https://epoint.az)
|
|
5
|
+
[](https://mypy-lang.org)
|
|
6
|
+
[](https://www.python-httpx.org)
|
|
7
|
+
[](https://docs.astral.sh/ruff)
|
|
8
|
+
[](#apple-pay-and-google-pay)
|
|
9
|
+
[](#apple-pay-and-google-pay)
|
|
10
|
+
[](https://github.com/qiyascc/epoint-python-sdk/blob/main/LICENSE)
|
|
11
|
+
|
|
12
|
+
Typed Python client for the [Epoint](https://epoint.az) payment gateway. Sync and async, every endpoint, signed callbacks, and retry rules built so a payment is never sent twice.
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
pip install epoint-python-sdk
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Pay
|
|
19
|
+
|
|
20
|
+
```python
|
|
21
|
+
from epoint_sdk import Epoint
|
|
22
|
+
|
|
23
|
+
with Epoint("i000000001", "PRIVATE_KEY", success_url="https://shop.az/ok", error_url="https://shop.az/fail") as ep:
|
|
24
|
+
checkout = ep.payments.create("19.90", "ORDER-1042", description="Pro plan")
|
|
25
|
+
redirect(checkout.redirect_url)
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Confirm
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
tx = ep.verify_callback(request.POST)
|
|
32
|
+
if tx.paid:
|
|
33
|
+
fulfil(tx.order_id, tx.amount, tx.transaction)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Never trust the redirect alone. Use the signed callback, or ask the gateway:
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
ep.payments.status(checkout.transaction).paid
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Apple Pay and Google Pay
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
widget = ep.widgets.create("19.90", "ORDER-1043", "Pro plan")
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
```html
|
|
49
|
+
<iframe src="{{ widget.widget_url }}" allow="payment" title="Apple Pay / Google Pay"></iframe>
|
|
50
|
+
<script>
|
|
51
|
+
addEventListener("message", (e) => {
|
|
52
|
+
if (e.origin !== "{{ widget.origin }}") return;
|
|
53
|
+
fetch("/orders/1043/check/", { method: "POST" });
|
|
54
|
+
});
|
|
55
|
+
</script>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The page needs `Permissions-Policy: payment=(self "https://epoint.az")`. The `postMessage` is a hint only: `WidgetMessage.from_event(data)` reads it, then confirm on the server with `ep.payments.status(widget.transaction)` or the signed callback. Epoint enables token payments per merchant. `ep.widgets.split(...)` is the split variant.
|
|
59
|
+
|
|
60
|
+
## Safety
|
|
61
|
+
|
|
62
|
+
| Situation | What the client does |
|
|
63
|
+
| --- | --- |
|
|
64
|
+
| Connection refused, nothing sent | Retries, then `NotSentError` |
|
|
65
|
+
| Timeout, cut connection or 5xx on a call that moves money | No retry, `OutcomeUnknownError` with the `order_id` |
|
|
66
|
+
| Same failure on a read (status, card, lists) | Retries with backoff |
|
|
67
|
+
| 429 | Retries, the gateway did not process it |
|
|
68
|
+
| `status: error` from the gateway | `GatewayError` with `code` and `trace_id` |
|
|
69
|
+
| Declined card on a direct charge | Returns `Transaction` with `failed`, never raises |
|
|
70
|
+
| Amount like `1.005`, `0`, `NaN` or `True` | `InvalidRequestError` before anything is sent |
|
|
71
|
+
| `base_url` over plain http | `ConfigurationError`, except localhost or `allow_insecure_http` |
|
|
72
|
+
| Callback `data` over 64 KB | Rejected before hashing |
|
|
73
|
+
| Callback for another order or amount | `tx.matches(order_id=..., amount=...)` is `False` |
|
|
74
|
+
|
|
75
|
+
Reuse the same `order_id` when you retry. Epoint refuses a used one, so a double click or a crash can not charge twice. Amounts are `Decimal` end to end, and signatures are compared in constant time.
|
|
76
|
+
|
|
77
|
+
## Endpoints
|
|
78
|
+
|
|
79
|
+
| Namespace | Methods |
|
|
80
|
+
| --- | --- |
|
|
81
|
+
| `payments` | `create` `form` `status` `reverse` `hold` `capture` |
|
|
82
|
+
| `cards` | `register` `register_and_pay` `charge` `status` `payout` |
|
|
83
|
+
| `split` | `create` `charge` `register_and_pay` |
|
|
84
|
+
| `installments` | `plans` `create` |
|
|
85
|
+
| `wallets` | `list` `pay` |
|
|
86
|
+
| `widgets` | `create` `split` (Apple Pay, Google Pay) |
|
|
87
|
+
| `invoices` | `create` `update` `get` `list` `send_sms` `send_email` |
|
|
88
|
+
| `transfers` | `create` `status` (B2B) |
|
|
89
|
+
| client | `heartbeat` `verify_callback` `request` |
|
|
90
|
+
|
|
91
|
+
`AsyncEpoint` has the same methods, awaited.
|
|
92
|
+
|
|
93
|
+
## Config
|
|
94
|
+
|
|
95
|
+
Pass values in code, or set `EPOINT_PUBLIC_KEY`, `EPOINT_PRIVATE_KEY`, `EPOINT_SUCCESS_URL`, `EPOINT_ERROR_URL`, `EPOINT_LANGUAGE`, `EPOINT_TIMEOUT`, `EPOINT_MAX_RETRIES`, or put them in `epoint.toml`. Every path is a setting (`EPOINT_ENDPOINTS__PAYMENT=...`) and `base_url` can point at a sandbox such as [epoint-sandbox](https://github.com/martian56/epoint-sandbox). Messages live in `messages.yaml` and can be replaced with `messages.use(...)`.
|
|
96
|
+
|
|
97
|
+
## Develop
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
pip install -e ".[dev]" && pytest && ruff check . && mypy src
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Links
|
|
104
|
+
|
|
105
|
+
- Source code: [github.com/qiyascc/epoint-python-sdk](https://github.com/qiyascc/epoint-python-sdk)
|
|
106
|
+
- PyPI: [pypi.org/project/epoint-python-sdk](https://pypi.org/project/epoint-python-sdk/)
|
|
107
|
+
- Project page: [theqiyas.cc/projects/epoint-python-sdk](https://theqiyas.cc/projects/epoint-python-sdk/)
|
|
108
|
+
- Author: [Qiyas Sadıqov](https://theqiyas.cc), more projects at [theqiyas.cc](https://theqiyas.cc)
|
|
109
|
+
|
|
110
|
+
## License
|
|
111
|
+
|
|
112
|
+
MIT
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from django.http import HttpResponse, HttpResponseBadRequest
|
|
2
|
+
from django.views.decorators.csrf import csrf_exempt
|
|
3
|
+
from django.views.decorators.http import require_POST
|
|
4
|
+
|
|
5
|
+
from epoint_sdk import Epoint, SignatureError
|
|
6
|
+
|
|
7
|
+
epoint = Epoint()
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@csrf_exempt
|
|
11
|
+
@require_POST
|
|
12
|
+
def epoint_callback(request):
|
|
13
|
+
try:
|
|
14
|
+
tx = epoint.verify_callback(request.POST)
|
|
15
|
+
except SignatureError:
|
|
16
|
+
return HttpResponseBadRequest()
|
|
17
|
+
if tx.paid:
|
|
18
|
+
mark_paid(tx.order_id, tx.amount, tx.transaction)
|
|
19
|
+
return HttpResponse("OK")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def mark_paid(order_id, amount, transaction):
|
|
23
|
+
raise NotImplementedError
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling>=1.21"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "epoint-python-sdk"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "Typed Python client for the Epoint (epoint.az) payment gateway, sync and async, safe against double charges."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
license-files = ["LICENSE"]
|
|
12
|
+
requires-python = ">=3.10"
|
|
13
|
+
authors = [{ name = "qiyascc", email = "qiyasturk@gmail.com" }]
|
|
14
|
+
keywords = ["epoint", "payment", "gateway", "azerbaijan", "azn", "sdk", "checkout"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 4 - Beta",
|
|
17
|
+
"Intended Audience :: Developers",
|
|
18
|
+
"Operating System :: OS Independent",
|
|
19
|
+
"Programming Language :: Python :: 3",
|
|
20
|
+
"Programming Language :: Python :: 3.10",
|
|
21
|
+
"Programming Language :: Python :: 3.11",
|
|
22
|
+
"Programming Language :: Python :: 3.12",
|
|
23
|
+
"Programming Language :: Python :: 3.13",
|
|
24
|
+
"Topic :: Office/Business :: Financial",
|
|
25
|
+
"Typing :: Typed",
|
|
26
|
+
]
|
|
27
|
+
dependencies = ["httpx>=0.24,<1", "goodconf>=7.1", "pydantic>=2.7", "PyYAML>=6"]
|
|
28
|
+
|
|
29
|
+
[project.optional-dependencies]
|
|
30
|
+
toml = ["goodconf[toml]>=7.1"]
|
|
31
|
+
yaml = ["goodconf[yaml]>=7.1"]
|
|
32
|
+
dev = ["epoint-python-sdk[toml,yaml]", "pytest>=7", "pytest-asyncio>=0.21", "ruff>=0.4", "mypy>=1.8", "types-PyYAML"]
|
|
33
|
+
|
|
34
|
+
[project.urls]
|
|
35
|
+
Homepage = "https://theqiyas.cc/projects/epoint-python-sdk/"
|
|
36
|
+
Source = "https://github.com/qiyascc/epoint-python-sdk"
|
|
37
|
+
Author = "https://theqiyas.cc"
|
|
38
|
+
Issues = "https://github.com/qiyascc/epoint-python-sdk/issues"
|
|
39
|
+
Changelog = "https://github.com/qiyascc/epoint-python-sdk/blob/main/CHANGELOG.md"
|
|
40
|
+
|
|
41
|
+
[tool.hatch.version]
|
|
42
|
+
path = "src/epoint_sdk/_version.py"
|
|
43
|
+
|
|
44
|
+
[tool.hatch.build.targets.wheel]
|
|
45
|
+
packages = ["src/epoint_sdk"]
|
|
46
|
+
|
|
47
|
+
[tool.hatch.build.targets.sdist]
|
|
48
|
+
include = ["src/epoint_sdk", "tests", "examples", "README.md", "CHANGELOG.md", "LICENSE"]
|
|
49
|
+
|
|
50
|
+
[tool.pytest.ini_options]
|
|
51
|
+
testpaths = ["tests"]
|
|
52
|
+
asyncio_mode = "auto"
|
|
53
|
+
|
|
54
|
+
[tool.ruff]
|
|
55
|
+
line-length = 120
|
|
56
|
+
target-version = "py310"
|
|
57
|
+
|
|
58
|
+
[tool.ruff.lint]
|
|
59
|
+
select = ["E", "F", "I", "B", "UP"]
|
|
60
|
+
ignore = ["E731", "UP006", "UP007", "UP035", "UP045"]
|
|
61
|
+
|
|
62
|
+
[tool.mypy]
|
|
63
|
+
python_version = "3.10"
|
|
64
|
+
plugins = ["pydantic.mypy"]
|
|
65
|
+
warn_unused_ignores = true
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
from . import messages, signing
|
|
2
|
+
from ._version import __version__
|
|
3
|
+
from .callbacks import callback_form, verify_callback
|
|
4
|
+
from .client import AsyncEpoint, Epoint
|
|
5
|
+
from .config import Settings, load_settings
|
|
6
|
+
from .enums import CardStatus, Currency, Language, OperationCode, Status
|
|
7
|
+
from .errors import (
|
|
8
|
+
ConfigurationError,
|
|
9
|
+
EpointError,
|
|
10
|
+
GatewayError,
|
|
11
|
+
HTTPStatusError,
|
|
12
|
+
InvalidRequestError,
|
|
13
|
+
NotSentError,
|
|
14
|
+
OutcomeUnknownError,
|
|
15
|
+
SignatureError,
|
|
16
|
+
TransportError,
|
|
17
|
+
)
|
|
18
|
+
from .models import (
|
|
19
|
+
Callback,
|
|
20
|
+
Card,
|
|
21
|
+
CardRegistration,
|
|
22
|
+
CheckoutForm,
|
|
23
|
+
InstallmentPlan,
|
|
24
|
+
Invoice,
|
|
25
|
+
Redirect,
|
|
26
|
+
Result,
|
|
27
|
+
Transaction,
|
|
28
|
+
Transfer,
|
|
29
|
+
Wallet,
|
|
30
|
+
Widget,
|
|
31
|
+
WidgetMessage,
|
|
32
|
+
origin_of,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
__all__ = [
|
|
36
|
+
"__version__",
|
|
37
|
+
"Epoint",
|
|
38
|
+
"AsyncEpoint",
|
|
39
|
+
"Settings",
|
|
40
|
+
"load_settings",
|
|
41
|
+
"messages",
|
|
42
|
+
"signing",
|
|
43
|
+
"verify_callback",
|
|
44
|
+
"callback_form",
|
|
45
|
+
"Status",
|
|
46
|
+
"CardStatus",
|
|
47
|
+
"Currency",
|
|
48
|
+
"Language",
|
|
49
|
+
"OperationCode",
|
|
50
|
+
"Callback",
|
|
51
|
+
"Card",
|
|
52
|
+
"CardRegistration",
|
|
53
|
+
"CheckoutForm",
|
|
54
|
+
"InstallmentPlan",
|
|
55
|
+
"Invoice",
|
|
56
|
+
"Redirect",
|
|
57
|
+
"Result",
|
|
58
|
+
"Transaction",
|
|
59
|
+
"Transfer",
|
|
60
|
+
"Wallet",
|
|
61
|
+
"Widget",
|
|
62
|
+
"WidgetMessage",
|
|
63
|
+
"origin_of",
|
|
64
|
+
"EpointError",
|
|
65
|
+
"ConfigurationError",
|
|
66
|
+
"InvalidRequestError",
|
|
67
|
+
"SignatureError",
|
|
68
|
+
"TransportError",
|
|
69
|
+
"NotSentError",
|
|
70
|
+
"OutcomeUnknownError",
|
|
71
|
+
"HTTPStatusError",
|
|
72
|
+
"GatewayError",
|
|
73
|
+
]
|