Coverage for src/integrify/azericard/schemas/response.py: 97%
64 statements
« prev ^ index » next coverage.py v7.9.2, created at 2025-12-29 00:57 +0000
« prev ^ index » next coverage.py v7.9.2, created at 2025-12-29 00:57 +0000
1from datetime import datetime
2from decimal import Decimal
3from hashlib import md5
4from typing import ClassVar, Optional, Union
6from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
7from pydantic.alias_generators import to_pascal
8from typing_extensions import Self
10from integrify.azericard import env
11from integrify.azericard.schemas.enums import (
12 Action,
13 AuthorizationResponseType,
14 AuthorizationType,
15 TransferStatusCode,
16)
17from integrify.azericard.utils import TimeStampIn
20class GetTransactionStatusResponseSchema(BaseModel):
21 action: Action = Field(validation_alias='ACTION')
22 """Sorğu üçün orijinal əməliyyat"""
24 rc: str = Field(validation_alias='Response code')
25 """Sorğu üçün orijinal əməliyyat kodu (ISO-8583 Sahə 39)"""
27 status_message: str = Field(validation_alias='Transaction Status message')
28 """Orijinal əməliyyat statusu mesajı"""
30 terminal: str = Field(validation_alias='TERMINAL')
31 """Orijinal əməliyyat Terminal ID"""
33 card_number: str = Field(validation_alias='Card number')
34 """Orijinal əməliyyat maskalı kart nömrəsi"""
36 amount: Decimal = Field(validation_alias='Transaction amount')
37 """Orijinal əməliyyat məbləği"""
39 currency: str = Field(validation_alias='Transaction currency')
40 """Orijinal əməliyyat valyutası"""
42 date: datetime = Field(validation_alias='Transaction date')
43 """Orijinal əməliyyat tarixi"""
45 state: str = Field(validation_alias='Transaction state')
46 """Orijinal əməliyyat vəziyyəti"""
48 order: str = Field(validation_alias='Merchant order id')
49 """Orijinal əməliyyat ORDER ID-si"""
51 approval: str = Field(validation_alias='Banks approval code')
52 """Orijinal əməliyyatın təsdiq kodu"""
54 rrn: str = Field(validation_alias='Transaction RRN')
55 """Orijinal əməliyyat RRN"""
57 int_ref: str = Field(validation_alias='INT_REF')
58 """Orijinal əməliyyat INT_REF"""
60 trtype: Union[AuthorizationType, AuthorizationResponseType] = Field(
61 validation_alias='Original transaction TRTYPE'
62 )
63 """Orijinal əməliyyat TRTYPE"""
65 timestamp: TimeStampIn = Field(validation_alias='Timestamp')
66 """Sorğunun vaxtı"""
68 nonce: str = Field(validation_alias='Nonce')
69 """Orijinal əməliyyat Nonce"""
71 p_sign: str = Field(validation_alias='P_SIGN')
72 """16-lıq formada E-Commerce Gateway MAC (Message Authentication Code).
73 MAC istifadə edilərsə mövcud olacaq."""
75 @field_validator('timestamp', 'date', mode='before')
76 @classmethod
77 def validate_timestamp(cls, val: Union[datetime, str]) -> datetime:
78 """İnput string dəyərdirsə, datetime obyektinə çevirən funksiya"""
79 if isinstance(val, datetime): 79 ↛ 80line 79 didn't jump to line 80 because the condition on line 79 was never true
80 return val
82 return datetime.strptime(val, '%Y%m%d%H%M%S')
85class TransferDeclineResponseSchema(BaseModel):
86 SIGNATURE_FIELDS: ClassVar[list[str]] = [
87 'operation_id',
88 'srn',
89 'amount',
90 'cur',
91 'status',
92 'timestamp',
93 'response_code',
94 'message',
95 ]
96 """Signature hesablanılması üçün lazım olan field adları"""
98 model_config = ConfigDict(alias_generator=to_pascal)
100 operation_id: str
101 """Sorğu əməliyyatının ID-si"""
103 srn: str = Field(validation_alias='SRN')
104 """Unikal əməliyyat nömrəsi"""
106 amount: Optional[Decimal] = None
107 """Ödəniş məbləği"""
109 cur: Optional[str] = None
110 """Ödəniş valyutası"""
112 status: Optional[str] = None
113 """Status Mesajı"""
115 timestamp: Optional[TimeStampIn] = None
116 """Sorğunun vaxtı"""
118 response_code: Union[TransferStatusCode, int]
119 """Uğur(suz)luq kodu"""
121 message: str
122 """Mesaj"""
124 signature: str
125 """AzeriCard imzası"""
127 @model_validator(mode='after')
128 def validate_signature(self) -> Self:
129 """AzeriCard-dan gələn signature-ni təsdiqləmə funksiyası"""
130 assert self.SIGNATURE_FIELDS
132 source = ''
133 for field in self.SIGNATURE_FIELDS:
134 val = getattr(self, field) or ''
135 source += str(val)
137 with open(env.AZERICARD_KEY_FILE_PATH, encoding='utf-8') as key_file:
138 key = key_file.read().strip().replace('\r\n', '\n')
140 source += key
142 calc_signature = md5(source.encode('utf-8'), usedforsecurity=False).hexdigest()
144 assert calc_signature == self.signature, 'Signature does not match!'
146 return self
149class TransferConfirmResponseSchema(TransferDeclineResponseSchema):
150 SIGNATURE_FIELDS: ClassVar[list[str]] = [
151 'operation_id',
152 'srn',
153 'rrn',
154 'amount',
155 'cur',
156 'receiver_pan',
157 'status',
158 'timestamp',
159 'response_code',
160 'message',
161 ]
162 """Signature hesablanılması üçün lazım olan field adları"""
164 rrn: str = Field(validation_alias='RRN')
165 """Unikal əməliyyat nömrəsi"""
167 receiver_pan: str
168 """Maskalanmış kart nömrəsi"""