Coverage for src/integrify/azericard/schemas/callback.py: 100%
43 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 decimal import Decimal
2from hashlib import md5
3from typing import Optional
5from pydantic import AliasGenerator, BaseModel, ConfigDict, Field, model_validator
6from pydantic.alias_generators import to_pascal
7from typing_extensions import Self
9from integrify.azericard import env
10from integrify.azericard.schemas.common import AzeriCardMinimalWithAmountDataSchema
11from integrify.azericard.schemas.enums import Action, CardStatus
12from integrify.azericard.utils import TimeStampIn
15class AuthCallbackSchema(AzeriCardMinimalWithAmountDataSchema):
16 model_config = ConfigDict(alias_generator=AliasGenerator(validation_alias=str.upper))
18 action: Action
19 """EGateway fəaliyyət kodu"""
21 rc: str = Field(min_length=2, max_length=2)
22 """Əməliyyat cavab kodu (ISO-8583 Sahə 39)"""
24 approval: Optional[str] = Field(..., min_length=6, max_length=6)
25 """Müştəri bankının təsdiq kodu (ISO-8583 Sahə 38). Kart idarəetmə sistemi
26 tərəfindən təmin edilmədikdə boş ola bilər."""
28 rrn: str = Field(min_length=12, max_length=12)
29 """Müştəri bankının axtarış istinad nömrəsi (ISO-8583 Sahə 37)"""
31 int_ref: str = Field(min_length=1, max_length=128)
32 """Elektron ticarət şlüzünün daxili istinad nömrəsi"""
34 p_sign: str = Field(min_length=1, max_length=256)
35 """16-lıq formatda Merchant MAC"""
38class AuthCallbackWithCardDataSchema(AuthCallbackSchema):
39 card: Optional[str]
40 """Masklanmış kart nömrəsi"""
42 token: Optional[str]
43 """Saxlanılacaq kartın TOKEN parametri"""
46class TransferCallbackSchema(BaseModel):
47 model_config = ConfigDict(alias_generator=AliasGenerator(validation_alias=to_pascal))
49 operation_id: str = Field(min_length=16, max_length=20, validation_alias='OperationID')
50 """AzeriCard tərəfindən verilmiş unikal əməliyyat nömrəsi"""
52 srn: str = Field(min_length=1, max_length=12, validation_alias='SRN')
53 """Tərəfinizdən unikal əməliyyat nömrəsi"""
55 amount: Decimal
56 """Müraciətdən gələn məbləğ"""
58 cur: str
59 """Sorğunun valyutası yalnız AZN) olmalıdır"""
61 card_status: CardStatus
62 """Azericard tərəfində istifadəçi kartı statusu"""
64 receiver_pan: str = Field(min_length=16, max_length=16, validation_alias='ReceiverPAN')
65 """Maskalı kart nömrəsi"""
67 status: str
68 """Cari tranzaksiya statusu (məsələn, "pending")"""
70 timestamp: TimeStampIn
71 """Cavab vaxtı"""
73 rc: str = Field(validation_alias='Response Code')
74 """Cavab kodu"""
76 message: str
77 """Cavab mesajı"""
79 signature: str
80 """Hesablanmış dəyər MD5(Bütün sahələr birləşdirilib + Açar)"""
82 @model_validator(mode='after')
83 def validate_signature(self) -> Self:
84 """AzeriCard-dan gələn signature-ni təsdiqləmə funksiyası"""
85 with open(env.AZERICARD_KEY_FILE_PATH, encoding='utf-8') as key_file:
86 key = key_file.read().strip().replace('\r\n', '\n')
88 calc_signature = md5(
89 str(
90 self.operation_id
91 + self.srn
92 + str(self.amount)
93 + self.cur
94 + self.card_status
95 + self.receiver_pan
96 + self.status
97 + self.timestamp.strftime('%Y%m%d%H%M%S')
98 + self.rc
99 + self.message
100 + key
101 ).encode('utf-8'),
102 usedforsecurity=False,
103 ).hexdigest()
105 assert calc_signature == self.signature, 'Signature does not match!'
107 return self