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

1import base64 

2import json 

3 

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 

38 

39 

40class BasePayloadHandler(APIPayloadHandler): 

41 """EPoint üçün baza handler. `req_model`/`resp_model` alt class-larda 

42 ClassVar kimi təyin olunur.""" 

43 

44 def pre_handle_payload(self, *args, **kwds): 

45 return { 

46 'public_key': env.EPOINT_PUBLIC_KEY, 

47 'language': env.EPOINT_INTERFACE_LANG, 

48 } 

49 

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 } 

56 

57 def handle_response(self, resp: httpx.Response) -> APIResponse[_ResponseT]: 

58 api_resp: APIResponse[MinimalResponseSchema] = super().handle_response(resp) 

59 

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 

65 

66 return api_resp 

67 

68 

69class PaymentPayloadHandler(BasePayloadHandler): 

70 req_model = PaymentRequestSchema 

71 resp_model = RedirectUrlResponseSchema 

72 

73 

74class GetTransactionStatusPayloadHandler(BasePayloadHandler): 

75 req_model = GetTransactionStatusRequestSchema 

76 resp_model = TransactionStatusResponseSchema 

77 

78 

79class SaveCardPayloadHandler(BasePayloadHandler): 

80 req_model = SaveCardRequestSchema 

81 resp_model = RedirectUrlWithCardIdResponseSchema 

82 

83 

84class PayWithSavedCardPayloadHandler(BasePayloadHandler): 

85 req_model = PayWithSavedCardRequestSchema 

86 resp_model = BaseResponseSchema 

87 

88 

89class PayAndSaveCardPayloadHandler(BasePayloadHandler): 

90 req_model = PayAndSaveCardRequestSchema 

91 resp_model = RedirectUrlWithCardIdResponseSchema 

92 

93 

94class PayoutPayloadHandler(BasePayloadHandler): 

95 req_model = PayoutRequestSchema 

96 resp_model = BaseResponseSchema 

97 

98 

99class RefundPayloadHandler(BasePayloadHandler): 

100 req_model = RefundRequestSchema 

101 resp_model = MinimalResponseSchema 

102 

103 

104class SplitPayPayloadHandler(BasePayloadHandler): 

105 req_model = SplitPayRequestSchema 

106 resp_model = RedirectUrlResponseSchema 

107 

108 

109class SplitPayWithSavedCardPayloadHandler(BasePayloadHandler): 

110 req_model = SplitPayWithSavedCardRequestSchema 

111 resp_model = SplitPayWithSavedCardResponseSchema 

112 

113 

114class SplitPayAndSaveCardPayloadHandler(BasePayloadHandler): 

115 req_model = SplitPayAndSaveCardRequestSchema 

116 resp_model = RedirectUrlWithCardIdResponseSchema 

117 

118 

119############################################################################## 

120# Apple Pay & Google Pay 

121_ERROR_STATUSES = { 

122 TransactionStatus.ERROR.value, 

123 TransactionStatus.SERVER_ERROR.value, 

124 TransactionStatus.FAILED.value, 

125} 

126 

127 

128class BaseTokenPayloadHandler(BasePayloadHandler): 

129 """Apple/Google Pay sorğuları üçün baza handler: data-ya yalnız `public_key` əlavə olunur""" 

130 

131 def pre_handle_payload(self, *args, **kwds): 

132 return {'public_key': env.EPOINT_PUBLIC_KEY} 

133 

134 

135class CreateWidgetPayloadHandler(BaseTokenPayloadHandler): 

136 req_model = CreateWidgetRequestSchema 

137 resp_model = WidgetResponseSchema 

138 

139 

140class CreateTokenPaymentPayloadHandler(BasePayloadHandler): 

141 req_model = CreateTokenPaymentRequestSchema 

142 resp_model = TokenPaymentResponseSchema 

143 

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 

155 

156 

157class ApplePaySessionPayloadHandler(BaseTokenPayloadHandler): 

158 req_model = ApplePaySessionRequestSchema 

159 resp_model = dict 

160 

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 

166 

167 

168class ApplePayPayloadHandler(BaseTokenPayloadHandler): 

169 req_model = ApplePayRequestSchema 

170 resp_model = TokenPayResponseSchema 

171 

172 

173class GooglePayPayloadHandler(BaseTokenPayloadHandler): 

174 req_model = GooglePayRequestSchema 

175 resp_model = TokenPayResponseSchema