Coverage for packages/epoint/src/integrify/epoint/handlers.py: 100%
79 statements
« prev ^ index » next coverage.py v7.16.0, created at 2026-10-19 02:39 +0000
« prev ^ index » next coverage.py v7.16.0, created at 2026-10-19 02:39 +0000
1import base64
2import json
4import httpx
5from integrify.api import APIPayloadHandler
6from integrify.epoint import env
7from integrify.epoint.helpers import generate_signature
8from integrify.epoint.schemas.enums import TransactionStatus, TransactionStatusExtended
9from integrify.epoint.schemas.request import (
10 ApplePayRequestSchema,
11 ApplePaySessionRequestSchema,
12 CreateTokenPaymentRequestSchema,
13 CreateWidgetRequestSchema,
14 GetTransactionStatusRequestSchema,
15 GooglePayRequestSchema,
16 PayAndSaveCardRequestSchema,
17 PaymentRequestSchema,
18 PayoutRequestSchema,
19 PayWithSavedCardRequestSchema,
20 RefundRequestSchema,
21 SaveCardRequestSchema,
22 SplitPayAndSaveCardRequestSchema,
23 SplitPayRequestSchema,
24 SplitPayWithSavedCardRequestSchema,
25)
26from integrify.epoint.schemas.response import (
27 BaseResponseSchema,
28 MinimalResponseSchema,
29 RedirectUrlResponseSchema,
30 RedirectUrlWithCardIdResponseSchema,
31 SplitPayWithSavedCardResponseSchema,
32 TokenPaymentResponseSchema,
33 TokenPayResponseSchema,
34 TransactionStatusResponseSchema,
35 WidgetResponseSchema,
36)
37from integrify.schemas import APIResponse, _ResponseT
40class BasePayloadHandler(APIPayloadHandler):
41 """EPoint üçün baza handler. `req_model`/`resp_model` alt class-larda
42 ClassVar kimi təyin olunur."""
44 def pre_handle_payload(self, *args, **kwds):
45 return {
46 'public_key': env.EPOINT_PUBLIC_KEY,
47 'language': env.EPOINT_INTERFACE_LANG,
48 }
50 def post_handle_payload(self, data: dict):
51 b64data = base64.b64encode(json.dumps(data).encode()).decode()
52 return {
53 'data': b64data,
54 'signature': generate_signature(b64data),
55 }
57 def handle_response(self, resp: httpx.Response) -> APIResponse[_ResponseT]:
58 api_resp: APIResponse[MinimalResponseSchema] = super().handle_response(resp)
60 # EPoint həmişə 200 qaytarır, error olsa belə
61 if isinstance(api_resp.body.status, TransactionStatusExtended):
62 api_resp.ok = api_resp.body.status != TransactionStatusExtended.SERVER_ERROR
63 else:
64 api_resp.ok = api_resp.body.status == TransactionStatus.SUCCESS
66 return api_resp
69class PaymentPayloadHandler(BasePayloadHandler):
70 req_model = PaymentRequestSchema
71 resp_model = RedirectUrlResponseSchema
74class GetTransactionStatusPayloadHandler(BasePayloadHandler):
75 req_model = GetTransactionStatusRequestSchema
76 resp_model = TransactionStatusResponseSchema
79class SaveCardPayloadHandler(BasePayloadHandler):
80 req_model = SaveCardRequestSchema
81 resp_model = RedirectUrlWithCardIdResponseSchema
84class PayWithSavedCardPayloadHandler(BasePayloadHandler):
85 req_model = PayWithSavedCardRequestSchema
86 resp_model = BaseResponseSchema
89class PayAndSaveCardPayloadHandler(BasePayloadHandler):
90 req_model = PayAndSaveCardRequestSchema
91 resp_model = RedirectUrlWithCardIdResponseSchema
94class PayoutPayloadHandler(BasePayloadHandler):
95 req_model = PayoutRequestSchema
96 resp_model = BaseResponseSchema
99class RefundPayloadHandler(BasePayloadHandler):
100 req_model = RefundRequestSchema
101 resp_model = MinimalResponseSchema
104class SplitPayPayloadHandler(BasePayloadHandler):
105 req_model = SplitPayRequestSchema
106 resp_model = RedirectUrlResponseSchema
109class SplitPayWithSavedCardPayloadHandler(BasePayloadHandler):
110 req_model = SplitPayWithSavedCardRequestSchema
111 resp_model = SplitPayWithSavedCardResponseSchema
114class SplitPayAndSaveCardPayloadHandler(BasePayloadHandler):
115 req_model = SplitPayAndSaveCardRequestSchema
116 resp_model = RedirectUrlWithCardIdResponseSchema
119##############################################################################
120# Apple Pay & Google Pay
121_ERROR_STATUSES = {
122 TransactionStatus.ERROR.value,
123 TransactionStatus.SERVER_ERROR.value,
124 TransactionStatus.FAILED.value,
125}
128class BaseTokenPayloadHandler(BasePayloadHandler):
129 """Apple/Google Pay sorğuları üçün baza handler: data-ya yalnız `public_key` əlavə olunur"""
131 def pre_handle_payload(self, *args, **kwds):
132 return {'public_key': env.EPOINT_PUBLIC_KEY}
135class CreateWidgetPayloadHandler(BaseTokenPayloadHandler):
136 req_model = CreateWidgetRequestSchema
137 resp_model = WidgetResponseSchema
140class CreateTokenPaymentPayloadHandler(BasePayloadHandler):
141 req_model = CreateTokenPaymentRequestSchema
142 resp_model = TokenPaymentResponseSchema
144 def handle_response(self, resp: httpx.Response) -> APIResponse[_ResponseT]:
145 # Uğurlu cavabda `status` field-i yoxdur, ödəniş obyekti birbaşa qayıdır
146 api_resp: APIResponse[TokenPaymentResponseSchema] = APIPayloadHandler.handle_response(
147 self, resp
148 )
149 api_resp.ok = (
150 api_resp.ok
151 and api_resp.body.id is not None
152 and api_resp.body.status not in _ERROR_STATUSES
153 )
154 return api_resp
157class ApplePaySessionPayloadHandler(BaseTokenPayloadHandler):
158 req_model = ApplePaySessionRequestSchema
159 resp_model = dict
161 def handle_response(self, resp: httpx.Response) -> APIResponse[_ResponseT]:
162 # Apple merchant session obyekti olduğu kimi qaytarılır (SDK-ya ötürmək üçün)
163 api_resp: APIResponse[dict] = APIPayloadHandler.handle_response(self, resp)
164 api_resp.ok = api_resp.ok and api_resp.body.get('status') not in _ERROR_STATUSES
165 return api_resp
168class ApplePayPayloadHandler(BaseTokenPayloadHandler):
169 req_model = ApplePayRequestSchema
170 resp_model = TokenPayResponseSchema
173class GooglePayPayloadHandler(BaseTokenPayloadHandler):
174 req_model = GooglePayRequestSchema
175 resp_model = TokenPayResponseSchema