payme-pkg 2.5.3__py3-none-any.whl

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.

Potentially problematic release.


This version of payme-pkg might be problematic. Click here for more details.

@@ -0,0 +1,47 @@
1
+ import time
2
+
3
+ from django.db import DatabaseError
4
+
5
+ from payme.utils.logging import logger
6
+ from payme.utils.get_params import get_params
7
+ from payme.models import MerchatTransactionsModel
8
+ from payme.serializers import MerchatTransactionsModelSerializer
9
+
10
+
11
+ class PerformTransaction:
12
+ """
13
+ PerformTransaction class
14
+ That's used to perform a transaction.
15
+
16
+ Full method documentation
17
+ -------------------------
18
+ https://developer.help.paycom.uz/metody-merchant-api/performtransaction
19
+ """
20
+ def __call__(self, params: dict) -> dict:
21
+ serializer = MerchatTransactionsModelSerializer(
22
+ data=get_params(params)
23
+ )
24
+ serializer.is_valid(raise_exception=True)
25
+ clean_data: dict = serializer.validated_data
26
+ response: dict = None
27
+ try:
28
+ transaction = \
29
+ MerchatTransactionsModel.objects.get(
30
+ _id=clean_data.get("_id"),
31
+ )
32
+ transaction.state = 2
33
+ if transaction.perform_time == 0:
34
+ transaction.perform_time = int(time.time() * 1000)
35
+
36
+ transaction.save()
37
+ response: dict = {
38
+ "result": {
39
+ "perform_time": int(transaction.perform_time),
40
+ "transaction": transaction.transaction_id,
41
+ "state": int(transaction.state),
42
+ }
43
+ }
44
+ except DatabaseError as error:
45
+ logger.error("error while getting transaction in db: %s", error)
46
+
47
+ return transaction.order_id, response
@@ -0,0 +1,48 @@
1
+ # pylint: disable=invalid-name
2
+ from django.db import migrations, models
3
+
4
+
5
+ class Migration(migrations.Migration):
6
+ # pylint: disable=missing-class-docstring
7
+ initial = True
8
+ dependencies = []
9
+
10
+ operations = [
11
+ migrations.CreateModel(
12
+ name='MerchatTransactionsModel',
13
+ fields=[
14
+ ('id', models.BigAutoField(
15
+ auto_created=True,
16
+ primary_key=True,
17
+ serialize=False,
18
+ verbose_name='ID')
19
+ ),
20
+ ('_id', models.CharField(max_length=255, null=True)),
21
+ ('transaction_id', models.CharField(max_length=255, null=True)),
22
+ ('order_id', models.BigIntegerField(blank=True, null=True)),
23
+ ('amount', models.FloatField(blank=True, null=True)),
24
+ ('time', models.BigIntegerField(blank=True, null=True)),
25
+ ('perform_time', models.BigIntegerField(default=0, null=True)),
26
+ ('cancel_time', models.BigIntegerField(default=0, null=True)),
27
+ ('state', models.IntegerField(default=1, null=True)),
28
+ ('reason', models.CharField(blank=True, max_length=255, null=True)),
29
+ ('created_at_ms', models.CharField(blank=True, max_length=255, null=True)),
30
+ ('created_at', models.DateTimeField(auto_now_add=True)),
31
+ ('updated_at', models.DateTimeField(auto_now=True)),
32
+ ],
33
+ ),
34
+ migrations.CreateModel(
35
+ name='Order',
36
+ fields=[
37
+ ('id', models.BigAutoField(
38
+ auto_created=True,
39
+ primary_key=True,
40
+ serialize=False,
41
+ verbose_name='ID')
42
+ ),
43
+ ('amount', models.IntegerField(blank=True, null=True)),
44
+ ('created_at', models.DateTimeField(auto_now_add=True)),
45
+ ('updated_at', models.DateTimeField(auto_now=True)),
46
+ ],
47
+ ),
48
+ ]
File without changes
payme/models.py ADDED
@@ -0,0 +1,61 @@
1
+ from django.db import models
2
+ from django.conf import settings
3
+ from django.utils.module_loading import import_string
4
+ from django.core.exceptions import FieldError
5
+
6
+ from payme.utils.logging import logger
7
+
8
+
9
+ class MerchatTransactionsModel(models.Model):
10
+ """
11
+ MerchatTransactionsModel class \
12
+ That's used for managing transactions in database.
13
+ """
14
+ _id = models.CharField(max_length=255, null=True, blank=False)
15
+ transaction_id = models.CharField(max_length=255, null=True, blank=False)
16
+ order_id = models.BigIntegerField(null=True, blank=True)
17
+ amount = models.FloatField(null=True, blank=True)
18
+ time = models.BigIntegerField(null=True, blank=True)
19
+ perform_time = models.BigIntegerField(null=True, default=0)
20
+ cancel_time = models.BigIntegerField(null=True, default=0)
21
+ state = models.IntegerField(null=True, default=1)
22
+ reason = models.CharField(max_length=255, null=True, blank=True)
23
+ created_at_ms = models.CharField(max_length=255, null=True, blank=True)
24
+ created_at = models.DateTimeField(auto_now_add=True)
25
+ updated_at = models.DateTimeField(auto_now=True)
26
+
27
+ def __str__(self):
28
+ return str(self._id)
29
+
30
+
31
+ try:
32
+ CUSTOM_ORDER = import_string(settings.ORDER_MODEL)
33
+
34
+ if not isinstance(CUSTOM_ORDER, models.base.ModelBase):
35
+ raise TypeError("The input must be an instance of models.Model class")
36
+
37
+ # pylint: disable=protected-access
38
+ if 'amount' not in [f.name for f in CUSTOM_ORDER._meta.fields]:
39
+ raise FieldError("Missing 'amount' field in your custom order model")
40
+
41
+ Order = CUSTOM_ORDER
42
+ except (ImportError, AttributeError):
43
+ logger.warning("You have no payme custom order model")
44
+
45
+ CUSTOM_ORDER = None
46
+
47
+ class Order(models.Model):
48
+ """
49
+ Order class \
50
+ That's used for managing order process
51
+ """
52
+ amount = models.IntegerField(null=True, blank=True)
53
+ created_at = models.DateTimeField(auto_now_add=True)
54
+ updated_at = models.DateTimeField(auto_now=True)
55
+
56
+ def __str__(self):
57
+ return f"ORDER ID: {self.id} - AMOUNT: {self.amount}"
58
+
59
+ class Meta:
60
+ # pylint: disable=missing-class-docstring
61
+ managed = False
@@ -0,0 +1 @@
1
+ from .import subscribe_receipts
@@ -0,0 +1,217 @@
1
+ from payme.utils.to_json import to_json
2
+ from payme.decorators.decorators import payme_request
3
+
4
+
5
+
6
+ class PaymeSubscribeReceipts:
7
+ """
8
+ The PaymeSubscribeReceipts class inclues
9
+ all paycom methods which are belongs receipts part.
10
+
11
+ Parameters
12
+ ----------
13
+ base_url string: The base url of the paycom api
14
+ paycom_id string: The paycom_id uses to identify
15
+ paycom_key string: The paycom_key uses to identify too
16
+
17
+ Full method documentation
18
+ -------------------------
19
+ https://developer.help.paycom.uz/metody-subscribe-api/
20
+ """
21
+ def __init__(
22
+ self,
23
+ base_url: str,
24
+ paycom_id: str,
25
+ paycom_key: str,
26
+ timeout: int = 5
27
+ ) -> "PaymeSubscribeReceipts":
28
+ self.base_url: str = base_url
29
+ self.headers: dict = {
30
+ "X-Auth": f"{paycom_id}:{paycom_key}"
31
+ }
32
+ self.__methods: dict = {
33
+ "receipts_get": "receipts.get",
34
+ "receipts_pay": "receipts.pay",
35
+ "receipts_send": "receipts.send",
36
+ "receipts_check": "receipts.check",
37
+ "receipts_cancel": "receipts.cancel",
38
+ "receipts_create": "receipts.create",
39
+ "receipts_get_all": "receipts.get_all",
40
+ }
41
+ self.timeout = timeout
42
+
43
+ @payme_request
44
+ def __request(self, data) -> dict:
45
+ """
46
+ Use this private method to request.
47
+ On success,response will be OK with format JSON.
48
+
49
+ Parameters
50
+ ----------
51
+ data: dict — Includes request data.
52
+
53
+ Returns dictionary Payme Response
54
+ ---------------------------------
55
+ """
56
+ return data
57
+
58
+ def receipts_create(self, amount: float, order_id: int) -> dict:
59
+ """
60
+ Use this method to create a new payment receipt.
61
+
62
+ Parameters
63
+ ----------
64
+ amount: float — Payment amount in tiyins
65
+ order_id: int — Order object ID
66
+
67
+ Full method documentation
68
+ -------------------------
69
+ https://developer.help.paycom.uz/metody-subscribe-api/receipts.create
70
+ """
71
+ data: dict = {
72
+ "method": self.__methods.get("receipts_create"),
73
+ "params": {
74
+ "amount": amount,
75
+ "account": {
76
+ "order_id": order_id,
77
+ }
78
+ }
79
+ }
80
+ return self.__request(to_json(**data))
81
+
82
+ def receipts_pay(self, invoice_id: str, token: str, phone: str) -> dict:
83
+ """
84
+ Use this method to pay for an exist receipt.
85
+
86
+ Parameters
87
+ ----------
88
+ invoice_id: str — Invoice id for indentity transaction
89
+ token: str — The card's active token
90
+ phone: str —The payer's phone number
91
+
92
+ Full method documentation
93
+ -------------------------
94
+ https://developer.help.paycom.uz/metody-subscribe-api/receipts.pay
95
+ """
96
+ data: dict = {
97
+ "method": self.__methods.get("receipts_pay"),
98
+ "params": {
99
+ "id": invoice_id,
100
+ "token": token,
101
+ "payer": {
102
+ "phone": phone,
103
+ }
104
+ }
105
+ }
106
+ return self.__request(to_json(**data))
107
+
108
+ def receipts_send(self, invoice_id: str, phone: str) -> dict:
109
+ """
110
+ Use this method to send a receipt for payment in an SMS message.
111
+
112
+ Parameters
113
+ ----------
114
+ invoice_id: str — The invoice id for indentity transaction
115
+ phone: str — The payer's phone number
116
+
117
+ Full method documentation
118
+ -------------------------
119
+ https://developer.help.paycom.uz/metody-subscribe-api/receipts.send
120
+ """
121
+ data: dict = {
122
+ "method": self.__methods.get('receipts_send'),
123
+ "params": {
124
+ "id": invoice_id,
125
+ "phone": phone
126
+ }
127
+ }
128
+ return self.__request(to_json(**data))
129
+
130
+ def receipts_cancel(self, invoice_id: str) -> dict:
131
+ """
132
+ Use this method a paid check in the queue for cancellation.
133
+
134
+ Parameters
135
+ ----------
136
+ invoice_id: str — The invoice id for indentity transaction
137
+
138
+ Full method documentation
139
+ -------------------------
140
+ https://developer.help.paycom.uz/metody-subscribe-api/receipts.cancel
141
+ """
142
+ data: dict = {
143
+ "method": self.__methods.get('receipts_cancel'),
144
+ "params": {
145
+ "id": invoice_id
146
+ }
147
+ }
148
+
149
+ return self.__request(to_json(**data))
150
+
151
+ def receipts_check(self, invoice_id: str) -> dict:
152
+ """
153
+ Use this method check for an exist receipt.
154
+
155
+ Parameters
156
+ ----------
157
+ invoice_id: str — The invoice id for indentity transaction
158
+
159
+ Full method documentation
160
+ -------------------------
161
+ https://developer.help.paycom.uz/metody-subscribe-api/receipts.check
162
+ """
163
+ data: dict = {
164
+ "method": self.__methods.get('receipts_check'),
165
+ "params": {
166
+ "id": invoice_id
167
+ }
168
+ }
169
+
170
+ return self.__request(to_json(**data))
171
+
172
+ def reciepts_get(self, invoice_id: str) -> dict:
173
+ """
174
+ Use this method check status for an exist receipt.
175
+
176
+ Parameters
177
+ ----------
178
+ invoice_id: str — The invoice id for indentity transaction
179
+
180
+ Full method documentation
181
+ -------------------------
182
+ https://developer.help.paycom.uz/metody-subscribe-api/receipts.get
183
+ """
184
+ data: dict = {
185
+ "method": self.__methods.get('receipts_get'),
186
+ "params": {
187
+ "id": invoice_id
188
+ }
189
+ }
190
+
191
+ return self.__request(to_json(**data))
192
+
193
+ def reciepts_get_all(self, count: int, _from: int, _to: int, offset: int) -> dict:
194
+ """
195
+ Use this method get all complete information, on checks for a certain period.
196
+
197
+ Parameters
198
+ ----------
199
+ count: int — The number of checks. Maximum value - 50
200
+ _from: str — The date of the beginning
201
+ _to: int — The date of the ending
202
+ offset: str — The number of subsequent skipped checks.
203
+
204
+ Full method documentation
205
+ -------------------------
206
+ https://developer.help.paycom.uz/metody-subscribe-api/receipts.get_all
207
+ """
208
+ data: str = {
209
+ "method": self.__methods.get('receipts_get_all'),
210
+ "params": {
211
+ "count": count,
212
+ "from": _from,
213
+ "to": _to,
214
+ "offset": offset
215
+ }
216
+ }
217
+ return self.__request(to_json(**data))
payme/serializers.py ADDED
@@ -0,0 +1,88 @@
1
+ from django.conf import settings
2
+
3
+ from rest_framework import serializers
4
+
5
+ from payme.models import Order
6
+ from payme.utils.logging import logger
7
+ from payme.utils.get_params import get_params
8
+ from payme.models import MerchatTransactionsModel
9
+ from payme.errors.exceptions import IncorrectAmount
10
+ from payme.errors.exceptions import PerformTransactionDoesNotExist
11
+
12
+
13
+ class MerchatTransactionsModelSerializer(serializers.ModelSerializer):
14
+ """
15
+ MerchatTransactionsModelSerializer class \
16
+ That's used to serialize merchat transactions data.
17
+ """
18
+ start_date = serializers.IntegerField(allow_null=True)
19
+ end_date = serializers.IntegerField(allow_null=True)
20
+
21
+ class Meta:
22
+ # pylint: disable=missing-class-docstring
23
+ model: MerchatTransactionsModel = MerchatTransactionsModel
24
+ fields: str = "__all__"
25
+ extra_fields = ['start_date', 'end_date']
26
+
27
+ def validate(self, attrs) -> dict:
28
+ """
29
+ Validate the data given to the MerchatTransactionsModel.
30
+ """
31
+ if attrs.get("order_id") is not None:
32
+ try:
33
+ order = Order.objects.get(
34
+ id=attrs['order_id']
35
+ )
36
+ if order.amount != int(attrs['amount']):
37
+ raise IncorrectAmount()
38
+
39
+ except IncorrectAmount as error:
40
+ logger.error("Invalid amount for order: %s", attrs['order_id'])
41
+ raise IncorrectAmount() from error
42
+
43
+ return attrs
44
+
45
+ def validate_amount(self, amount) -> int:
46
+ """
47
+ Validator for Transactions Amount.
48
+ """
49
+ if amount is None:
50
+ raise IncorrectAmount()
51
+
52
+ if int(amount) <= int(settings.PAYME.get("PAYME_MIN_AMOUNT", 0)):
53
+ raise IncorrectAmount("Payment amount is less than allowed.")
54
+
55
+ return amount
56
+
57
+ def validate_order_id(self, order_id) -> int:
58
+ """
59
+ Use this method to check if a transaction is allowed to be executed.
60
+
61
+ Parameters
62
+ ----------
63
+ order_id: str -> Order Indentation.
64
+ """
65
+ try:
66
+ Order.objects.get(id=order_id)
67
+ except Order.DoesNotExist as error:
68
+ logger.error("Order does not exist order_id: %s", order_id)
69
+ raise PerformTransactionDoesNotExist() from error
70
+
71
+ return order_id
72
+
73
+ @staticmethod
74
+ def get_validated_data(params: dict) -> dict:
75
+ """
76
+ This static method helps to get validated data.
77
+
78
+ Parameters
79
+ ----------
80
+ params: dict — Includes request params.
81
+ """
82
+ serializer = MerchatTransactionsModelSerializer(
83
+ data=get_params(params)
84
+ )
85
+ serializer.is_valid(raise_exception=True)
86
+ clean_data: dict = serializer.validated_data
87
+
88
+ return clean_data
payme/urls.py ADDED
@@ -0,0 +1,8 @@
1
+ from django.urls import path
2
+
3
+ from payme.views import MerchantAPIView
4
+
5
+
6
+ urlpatterns = [
7
+ path("merchant/", MerchantAPIView.as_view())
8
+ ]
File without changes
@@ -0,0 +1,24 @@
1
+ from django.conf import settings
2
+
3
+
4
+ def get_params(params: dict) -> dict:
5
+ """
6
+ Use this function to get the parameters from the payme.
7
+ """
8
+ account: dict = params.get("account")
9
+
10
+ clean_params: dict = {}
11
+ clean_params["_id"] = params.get("id")
12
+ clean_params["time"] = params.get("time")
13
+ clean_params["amount"] = params.get("amount")
14
+ clean_params["reason"] = params.get("reason")
15
+
16
+ # get statement method params
17
+ clean_params["start_date"] = params.get("from")
18
+ clean_params["end_date"] = params.get("to")
19
+
20
+ if account is not None:
21
+ account_name: str = settings.PAYME.get("PAYME_ACCOUNT")
22
+ clean_params["order_id"] = account[account_name]
23
+
24
+ return clean_params
payme/utils/logging.py ADDED
@@ -0,0 +1,9 @@
1
+ import logging
2
+
3
+ logging.basicConfig(
4
+ level=logging.DEBUG,
5
+ format='%(asctime)s %(levelname)s %(message)s',
6
+ datefmt='%Y-%m-%d %H:%M:%S'
7
+ )
8
+
9
+ logger = logging.getLogger(__name__)
@@ -0,0 +1,21 @@
1
+ from django.utils.timezone import datetime as dt
2
+ from django.utils.timezone import make_aware
3
+
4
+
5
+ def make_aware_datetime(start_date: int, end_date: int):
6
+ """
7
+ Convert Unix timestamps to aware datetimes.
8
+
9
+ :param start_date: Unix timestamp (milliseconds)
10
+ :param end_date: Unix timestamp (milliseconds)
11
+
12
+ :return: A tuple of two aware datetimes
13
+ """
14
+ return map(
15
+ lambda timestamp: make_aware(
16
+ dt.fromtimestamp(
17
+ timestamp / 1000
18
+ )
19
+ ),
20
+ [start_date, end_date]
21
+ )
payme/utils/support.py ADDED
@@ -0,0 +1,8 @@
1
+ """
2
+ Author: Muhammadali Akbarov
3
+ Gmail: muhammadali17abc@gmail.com
4
+ Phone: +998888351717
5
+ Telegram: @Muhammadalive
6
+ Twitter: https://twitter.com/muhammadali_abc
7
+ GitHub: https://github.com/Muhammadali-Akbarov/
8
+ """
payme/utils/to_json.py ADDED
@@ -0,0 +1,12 @@
1
+ import json
2
+
3
+ def to_json(**kwargs) -> dict:
4
+ """
5
+ Use this static method to data dumps.
6
+ """
7
+ data: dict = {
8
+ "method": kwargs.pop("method"),
9
+ "params": kwargs.pop("params"),
10
+ }
11
+
12
+ return json.dumps(data)