cuenca-validations 0.11.33__tar.gz → 2.0.0__tar.gz
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.
- {cuenca_validations-0.11.33 → cuenca_validations-2.0.0}/PKG-INFO +22 -10
- {cuenca_validations-0.11.33 → cuenca_validations-2.0.0}/cuenca_validations/__init__.py +4 -0
- {cuenca_validations-0.11.33 → cuenca_validations-2.0.0}/cuenca_validations/errors.py +0 -22
- {cuenca_validations-0.11.33 → cuenca_validations-2.0.0}/cuenca_validations/types/__init__.py +3 -8
- cuenca_validations-2.0.0/cuenca_validations/types/card.py +41 -0
- {cuenca_validations-0.11.33 → cuenca_validations-2.0.0}/cuenca_validations/types/files.py +1 -1
- {cuenca_validations-0.11.33 → cuenca_validations-2.0.0}/cuenca_validations/types/general.py +17 -38
- cuenca_validations-2.0.0/cuenca_validations/types/identities.py +173 -0
- {cuenca_validations-0.11.33 → cuenca_validations-2.0.0}/cuenca_validations/types/morals.py +5 -5
- {cuenca_validations-0.11.33 → cuenca_validations-2.0.0}/cuenca_validations/types/queries.py +35 -40
- {cuenca_validations-0.11.33 → cuenca_validations-2.0.0}/cuenca_validations/types/requests.py +234 -283
- cuenca_validations-2.0.0/cuenca_validations/typing.py +5 -0
- {cuenca_validations-0.11.33 → cuenca_validations-2.0.0}/cuenca_validations/validators.py +5 -11
- cuenca_validations-2.0.0/cuenca_validations/version.py +1 -0
- {cuenca_validations-0.11.33 → cuenca_validations-2.0.0}/cuenca_validations.egg-info/PKG-INFO +22 -10
- {cuenca_validations-0.11.33 → cuenca_validations-2.0.0}/cuenca_validations.egg-info/SOURCES.txt +1 -0
- cuenca_validations-2.0.0/cuenca_validations.egg-info/requires.txt +5 -0
- {cuenca_validations-0.11.33 → cuenca_validations-2.0.0}/setup.py +11 -8
- cuenca_validations-2.0.0/tests/test_card.py +35 -0
- cuenca_validations-2.0.0/tests/test_errors.py +32 -0
- {cuenca_validations-0.11.33 → cuenca_validations-2.0.0}/tests/test_statement.py +16 -13
- {cuenca_validations-0.11.33 → cuenca_validations-2.0.0}/tests/test_types.py +70 -45
- cuenca_validations-0.11.33/cuenca_validations/types/card.py +0 -53
- cuenca_validations-0.11.33/cuenca_validations/types/identities.py +0 -180
- cuenca_validations-0.11.33/cuenca_validations/typing.py +0 -5
- cuenca_validations-0.11.33/cuenca_validations/version.py +0 -1
- cuenca_validations-0.11.33/cuenca_validations.egg-info/requires.txt +0 -6
- cuenca_validations-0.11.33/tests/test_card.py +0 -35
- {cuenca_validations-0.11.33 → cuenca_validations-2.0.0}/LICENSE +0 -0
- {cuenca_validations-0.11.33 → cuenca_validations-2.0.0}/README.md +0 -0
- {cuenca_validations-0.11.33 → cuenca_validations-2.0.0}/cuenca_validations/card_bins.py +0 -0
- {cuenca_validations-0.11.33 → cuenca_validations-2.0.0}/cuenca_validations/py.typed +0 -0
- {cuenca_validations-0.11.33 → cuenca_validations-2.0.0}/cuenca_validations/types/enums.py +0 -0
- {cuenca_validations-0.11.33 → cuenca_validations-2.0.0}/cuenca_validations.egg-info/dependency_links.txt +0 -0
- {cuenca_validations-0.11.33 → cuenca_validations-2.0.0}/cuenca_validations.egg-info/top_level.txt +0 -0
- {cuenca_validations-0.11.33 → cuenca_validations-2.0.0}/setup.cfg +0 -0
- {cuenca_validations-0.11.33 → cuenca_validations-2.0.0}/tests/__init__.py +0 -0
|
@@ -1,23 +1,35 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: cuenca_validations
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 2.0.0
|
|
4
4
|
Summary: Cuenca common validations
|
|
5
5
|
Home-page: https://github.com/cuenca-mx/cuenca-validations
|
|
6
6
|
Author: Cuenca
|
|
7
7
|
Author-email: dev@cuenca.com
|
|
8
8
|
Classifier: Programming Language :: Python :: 3
|
|
9
|
-
Classifier: Programming Language :: Python :: 3.
|
|
10
|
-
Classifier: Programming Language :: Python :: 3.
|
|
11
|
-
Classifier: Programming Language :: Python :: 3.
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
12
14
|
Classifier: License :: OSI Approved :: MIT License
|
|
13
15
|
Classifier: Operating System :: OS Independent
|
|
14
|
-
Requires-Python: >=3.
|
|
16
|
+
Requires-Python: >=3.9
|
|
15
17
|
Description-Content-Type: text/markdown
|
|
16
18
|
License-File: LICENSE
|
|
17
|
-
Requires-Dist: clabe
|
|
18
|
-
Requires-Dist: pydantic[email]
|
|
19
|
-
Requires-Dist:
|
|
20
|
-
Requires-Dist: python-dateutil>=2.
|
|
19
|
+
Requires-Dist: clabe>=2.0.0
|
|
20
|
+
Requires-Dist: pydantic[email]>=2.10.0
|
|
21
|
+
Requires-Dist: pydantic-extra-types>=2.10.0
|
|
22
|
+
Requires-Dist: python-dateutil>=2.9.0
|
|
23
|
+
Requires-Dist: phonenumbers>=8.13.0
|
|
24
|
+
Dynamic: author
|
|
25
|
+
Dynamic: author-email
|
|
26
|
+
Dynamic: classifier
|
|
27
|
+
Dynamic: description
|
|
28
|
+
Dynamic: description-content-type
|
|
29
|
+
Dynamic: home-page
|
|
30
|
+
Dynamic: requires-dist
|
|
31
|
+
Dynamic: requires-python
|
|
32
|
+
Dynamic: summary
|
|
21
33
|
|
|
22
34
|
# Cuenca - validations
|
|
23
35
|
|
|
@@ -1,39 +1,17 @@
|
|
|
1
1
|
__all__ = [
|
|
2
2
|
'ApiError',
|
|
3
3
|
'AuthMethodNotAllowedError',
|
|
4
|
-
'CardBinValidationError',
|
|
5
4
|
'CuencaError',
|
|
6
5
|
'ERROR_CODES',
|
|
7
6
|
'InvalidOTPCodeError',
|
|
8
7
|
'MissingAuthorizationHeaderError',
|
|
9
8
|
'NoPasswordFoundError',
|
|
10
|
-
'NotDigitError',
|
|
11
9
|
'TooManyAttemptsError',
|
|
12
10
|
'UserLocationError',
|
|
13
11
|
'UserNotLoggedInError',
|
|
14
12
|
'WrongCredsError',
|
|
15
13
|
]
|
|
16
14
|
|
|
17
|
-
from pydantic.errors import (
|
|
18
|
-
NotDigitError as PydanticNotDigitError,
|
|
19
|
-
PydanticValueError,
|
|
20
|
-
)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
class CardBinValidationError(PydanticValueError):
|
|
24
|
-
code = 'payment_card_number.bin'
|
|
25
|
-
msg_template = (
|
|
26
|
-
'The card number contains a BIN (first six digits) that does not have'
|
|
27
|
-
'a known association with a Mexican bank. To add the association,'
|
|
28
|
-
'please file an issue:'
|
|
29
|
-
'https://github.com/cuenca-mx/cuenca-validations/issues'
|
|
30
|
-
)
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
class NotDigitError(PydanticNotDigitError):
|
|
34
|
-
code = 'digits'
|
|
35
|
-
msg_template = 'value is not all digits'
|
|
36
|
-
|
|
37
15
|
|
|
38
16
|
class CuencaError(Exception):
|
|
39
17
|
"""Exceptions related to ApiKeys, Login, Password, etc"""
|
{cuenca_validations-0.11.33 → cuenca_validations-2.0.0}/cuenca_validations/types/__init__.py
RENAMED
|
@@ -22,7 +22,7 @@ __all__ = [
|
|
|
22
22
|
'CardTransactionType',
|
|
23
23
|
'CardType',
|
|
24
24
|
'Country',
|
|
25
|
-
'
|
|
25
|
+
'Curp',
|
|
26
26
|
'CurpValidationRequest',
|
|
27
27
|
'CommissionType',
|
|
28
28
|
'DepositNetwork',
|
|
@@ -49,10 +49,8 @@ __all__ = [
|
|
|
49
49
|
'KYCVerificationUpdateRequest',
|
|
50
50
|
'Language',
|
|
51
51
|
'LimitedWalletRequest',
|
|
52
|
-
'PageSize',
|
|
53
52
|
'PartnerRequest',
|
|
54
53
|
'PartnerUpdateRequest',
|
|
55
|
-
'PaymentCardNumber',
|
|
56
54
|
'PhoneNumber',
|
|
57
55
|
'PlatformRequest',
|
|
58
56
|
'PlatformType',
|
|
@@ -73,7 +71,6 @@ __all__ = [
|
|
|
73
71
|
'StatementQuery',
|
|
74
72
|
'StrictPaymentCardNumber',
|
|
75
73
|
'StrictPositiveInt',
|
|
76
|
-
'StrictPositiveFloat',
|
|
77
74
|
'StrictTransferRequest',
|
|
78
75
|
'TermsOfService',
|
|
79
76
|
'TOSAgreement',
|
|
@@ -108,7 +105,7 @@ __all__ = [
|
|
|
108
105
|
'get_state_name',
|
|
109
106
|
]
|
|
110
107
|
|
|
111
|
-
from .card import
|
|
108
|
+
from .card import StrictPaymentCardNumber
|
|
112
109
|
from .enums import (
|
|
113
110
|
AuthorizerTransaction,
|
|
114
111
|
BankAccountStatus,
|
|
@@ -155,7 +152,6 @@ from .files import BatchFileMetadata
|
|
|
155
152
|
from .general import (
|
|
156
153
|
JSONEncoder,
|
|
157
154
|
SantizedDict,
|
|
158
|
-
StrictPositiveFloat,
|
|
159
155
|
StrictPositiveInt,
|
|
160
156
|
digits,
|
|
161
157
|
get_state_name,
|
|
@@ -163,7 +159,7 @@ from .general import (
|
|
|
163
159
|
from .identities import (
|
|
164
160
|
Address,
|
|
165
161
|
Beneficiary,
|
|
166
|
-
|
|
162
|
+
Curp,
|
|
167
163
|
KYCFile,
|
|
168
164
|
PhoneNumber,
|
|
169
165
|
Rfc,
|
|
@@ -182,7 +178,6 @@ from .queries import (
|
|
|
182
178
|
EventQuery,
|
|
183
179
|
FileQuery,
|
|
184
180
|
IdentityQuery,
|
|
185
|
-
PageSize,
|
|
186
181
|
QueryParams,
|
|
187
182
|
SessionQuery,
|
|
188
183
|
StatementQuery,
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from typing import Annotated
|
|
2
|
+
|
|
3
|
+
from pydantic import Field, StringConstraints
|
|
4
|
+
from pydantic_core import PydanticCustomError, core_schema
|
|
5
|
+
from pydantic_extra_types.payment import PaymentCardNumber
|
|
6
|
+
|
|
7
|
+
from ..card_bins import CARD_BINS
|
|
8
|
+
|
|
9
|
+
ExpMonth = Annotated[int, Field(strict=True, ge=1, le=12)]
|
|
10
|
+
ExpYear = Annotated[int, Field(strict=True, ge=1, le=99)]
|
|
11
|
+
Cvv = Annotated[
|
|
12
|
+
str,
|
|
13
|
+
StringConstraints(
|
|
14
|
+
strip_whitespace=True,
|
|
15
|
+
min_length=3,
|
|
16
|
+
max_length=3,
|
|
17
|
+
pattern=r'\d{3}',
|
|
18
|
+
),
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class StrictPaymentCardNumber(PaymentCardNumber):
|
|
23
|
+
|
|
24
|
+
@classmethod
|
|
25
|
+
def validate(
|
|
26
|
+
cls, card_number: str, validation_info: core_schema.ValidationInfo
|
|
27
|
+
) -> 'StrictPaymentCardNumber':
|
|
28
|
+
card = super().validate(card_number, validation_info)
|
|
29
|
+
if card.bin not in CARD_BINS:
|
|
30
|
+
raise PydanticCustomError(
|
|
31
|
+
'payment_card_number.bin',
|
|
32
|
+
'The card number contains a BIN (first six digits) that '
|
|
33
|
+
'does not have a known association with a Mexican bank. '
|
|
34
|
+
'To add the association, please file an issue: '
|
|
35
|
+
'https://github.com/cuenca-mx/cuenca-validations/issues',
|
|
36
|
+
)
|
|
37
|
+
return cls(card)
|
|
38
|
+
|
|
39
|
+
@property
|
|
40
|
+
def bank_code(self) -> str:
|
|
41
|
+
return CARD_BINS[self.bin]
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import json
|
|
2
|
-
from typing import
|
|
2
|
+
from typing import Annotated, Any, Optional
|
|
3
3
|
|
|
4
|
-
from pydantic import
|
|
4
|
+
from pydantic import Field, StringConstraints
|
|
5
5
|
|
|
6
|
-
from ..validators import sanitize_dict, sanitize_item
|
|
6
|
+
from ..validators import sanitize_dict, sanitize_item
|
|
7
7
|
from .enums import State
|
|
8
8
|
|
|
9
|
-
if TYPE_CHECKING:
|
|
10
|
-
from pydantic.typing import CallableGenerator
|
|
11
|
-
|
|
12
9
|
|
|
13
10
|
class SantizedDict(dict):
|
|
14
11
|
def __init__(self, *args, **kwargs):
|
|
@@ -21,43 +18,25 @@ class JSONEncoder(json.JSONEncoder):
|
|
|
21
18
|
return sanitize_item(o, default=super().default)
|
|
22
19
|
|
|
23
20
|
|
|
24
|
-
|
|
25
|
-
"""
|
|
26
|
-
- strict: ensures a float isn't passed in by accident
|
|
27
|
-
- gt (greater than): ensures the value is strictly above 0
|
|
28
|
-
"""
|
|
29
|
-
|
|
30
|
-
strict = True
|
|
31
|
-
gt = 0
|
|
32
|
-
le = 21_474_836_47 # Max value in DB
|
|
33
|
-
|
|
34
|
-
...
|
|
35
|
-
|
|
21
|
+
MAX_VALUE_IN_DB = 21_474_836_47
|
|
36
22
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
- ge (greater than or equal): ensures the value is above 0
|
|
41
|
-
"""
|
|
42
|
-
|
|
43
|
-
strict = True
|
|
44
|
-
ge = 0
|
|
45
|
-
|
|
46
|
-
...
|
|
23
|
+
StrictPositiveInt = Annotated[
|
|
24
|
+
int, Field(strict=True, gt=0, le=MAX_VALUE_IN_DB)
|
|
25
|
+
]
|
|
47
26
|
|
|
48
27
|
|
|
49
28
|
def digits(
|
|
50
29
|
min_length: Optional[int] = None, max_length: Optional[int] = None
|
|
51
|
-
) ->
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
30
|
+
) -> Annotated[Any, StringConstraints]:
|
|
31
|
+
return Annotated[
|
|
32
|
+
str,
|
|
33
|
+
StringConstraints(
|
|
34
|
+
strip_whitespace=True,
|
|
35
|
+
min_length=min_length,
|
|
36
|
+
max_length=max_length,
|
|
37
|
+
pattern=r'^\d+$',
|
|
38
|
+
),
|
|
39
|
+
]
|
|
61
40
|
|
|
62
41
|
|
|
63
42
|
names_state = {
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import datetime as dt
|
|
2
|
+
from typing import Annotated, Any, Optional
|
|
3
|
+
|
|
4
|
+
from pydantic import (
|
|
5
|
+
BaseModel,
|
|
6
|
+
ConfigDict,
|
|
7
|
+
Field,
|
|
8
|
+
IPvAnyAddress,
|
|
9
|
+
StringConstraints,
|
|
10
|
+
model_validator,
|
|
11
|
+
)
|
|
12
|
+
from pydantic_extra_types.phone_numbers import PhoneNumber
|
|
13
|
+
|
|
14
|
+
from .enums import Country, KYCFileType, State, VerificationStatus
|
|
15
|
+
|
|
16
|
+
Password = Annotated[
|
|
17
|
+
str,
|
|
18
|
+
Field(
|
|
19
|
+
min_length=6,
|
|
20
|
+
max_length=128,
|
|
21
|
+
description=(
|
|
22
|
+
'Any str with at least 6 characters, maximum 128 characters'
|
|
23
|
+
),
|
|
24
|
+
),
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
Curp = Annotated[
|
|
28
|
+
str,
|
|
29
|
+
StringConstraints(
|
|
30
|
+
min_length=18,
|
|
31
|
+
max_length=18,
|
|
32
|
+
pattern=r'^[A-Z]{4}[0-9]{6}[A-Z]{6}[A-Z|0-9][0-9]$',
|
|
33
|
+
),
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
Rfc = Annotated[
|
|
38
|
+
str,
|
|
39
|
+
StringConstraints(
|
|
40
|
+
min_length=12,
|
|
41
|
+
max_length=13,
|
|
42
|
+
),
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class Address(BaseModel):
|
|
47
|
+
street: Optional[str] = None
|
|
48
|
+
ext_number: Optional[str] = None
|
|
49
|
+
int_number: Optional[str] = None
|
|
50
|
+
colonia: Optional[str] = None
|
|
51
|
+
postal_code: Optional[str] = None
|
|
52
|
+
state: Optional[State] = None
|
|
53
|
+
country: Optional[Country] = None
|
|
54
|
+
city: Optional[str] = None
|
|
55
|
+
full_name: Optional[str] = None
|
|
56
|
+
model_config = ConfigDict(
|
|
57
|
+
json_schema_extra={
|
|
58
|
+
"example": {
|
|
59
|
+
"street": "Reforma",
|
|
60
|
+
"ext_number": "265",
|
|
61
|
+
"int_number": "5",
|
|
62
|
+
"colonia": "Cuauhtémoc",
|
|
63
|
+
"postal_code": "06500",
|
|
64
|
+
"state": "DF",
|
|
65
|
+
"country": "MX",
|
|
66
|
+
"city": "Cuauhtémoc",
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
@model_validator(mode='before')
|
|
72
|
+
@classmethod
|
|
73
|
+
def full_name_complete(cls, values: dict[str, Any]) -> dict[str, Any]:
|
|
74
|
+
if values.get('full_name'):
|
|
75
|
+
return values
|
|
76
|
+
if not values.get('street'):
|
|
77
|
+
raise ValueError('required street')
|
|
78
|
+
if not values.get('ext_number'):
|
|
79
|
+
raise ValueError('required ext_number')
|
|
80
|
+
return values
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class Beneficiary(BaseModel):
|
|
84
|
+
name: str
|
|
85
|
+
birth_date: dt.date
|
|
86
|
+
phone_number: PhoneNumber
|
|
87
|
+
user_relationship: str
|
|
88
|
+
percentage: int
|
|
89
|
+
model_config = ConfigDict(
|
|
90
|
+
json_schema_extra={
|
|
91
|
+
"example": {
|
|
92
|
+
"name": "Juan Perez",
|
|
93
|
+
"birth_date": "1907-07-06",
|
|
94
|
+
"phone_number": "+525500998877",
|
|
95
|
+
"user_relationship": "friend",
|
|
96
|
+
"percentage": 100,
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class VerificationErrors(BaseModel):
|
|
103
|
+
identifier: str = Field(
|
|
104
|
+
description='Unique identifier for the step validation'
|
|
105
|
+
)
|
|
106
|
+
error: str = Field(
|
|
107
|
+
description='Error throwed on validation,'
|
|
108
|
+
' can be StepError or SystemError in case of '
|
|
109
|
+
'KYCProvider intermittence',
|
|
110
|
+
)
|
|
111
|
+
code: str = Field(description='Specific code of the failure in the step.')
|
|
112
|
+
message: Optional[str] = Field(None, description='Error description')
|
|
113
|
+
model_config = ConfigDict(
|
|
114
|
+
json_schema_extra={
|
|
115
|
+
"example": {
|
|
116
|
+
"identifier": "age-check",
|
|
117
|
+
"error": 'StepError',
|
|
118
|
+
"code": "underage.noDOB",
|
|
119
|
+
"message": "The date of birth could not be obtained",
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
class KYCFile(BaseModel):
|
|
126
|
+
type: KYCFileType
|
|
127
|
+
uri_front: str = Field(description='API uri to fetch the file')
|
|
128
|
+
uri_back: Optional[str] = Field(
|
|
129
|
+
None, description='API uri to fetch the file'
|
|
130
|
+
)
|
|
131
|
+
is_mx: bool = True
|
|
132
|
+
data: Optional[dict] = None
|
|
133
|
+
status: Optional[VerificationStatus] = Field(
|
|
134
|
+
None, description='The status of the file depends on KYCValidation'
|
|
135
|
+
)
|
|
136
|
+
errors: Optional[list[VerificationErrors]] = Field(
|
|
137
|
+
None, description='List of document errors found during kyc validation'
|
|
138
|
+
)
|
|
139
|
+
verification_id: Optional[str] = Field(
|
|
140
|
+
None, description='The provider identifier of the validation result'
|
|
141
|
+
)
|
|
142
|
+
attempt: Optional[int] = Field(
|
|
143
|
+
None,
|
|
144
|
+
description='The number of kyc_validation intents for this document',
|
|
145
|
+
)
|
|
146
|
+
model_config = ConfigDict(
|
|
147
|
+
json_schema_extra={
|
|
148
|
+
"example": {
|
|
149
|
+
"type": "ine",
|
|
150
|
+
"is_mx": True,
|
|
151
|
+
"uri_front": "/files/FILE-01",
|
|
152
|
+
"uri_back": "/files/FILE-02",
|
|
153
|
+
"data": {},
|
|
154
|
+
"status": "created",
|
|
155
|
+
"errors": [],
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
class TOSAgreement(BaseModel):
|
|
162
|
+
version: str
|
|
163
|
+
ip: IPvAnyAddress
|
|
164
|
+
location: Optional[str] = None
|
|
165
|
+
model_config = ConfigDict(
|
|
166
|
+
json_schema_extra={
|
|
167
|
+
"example": {
|
|
168
|
+
"version": "2022-01-01",
|
|
169
|
+
"ip": "192.168.0.1",
|
|
170
|
+
"location": "19.427224, -99.168082",
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
)
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import datetime as dt
|
|
2
|
-
from typing import
|
|
2
|
+
from typing import Optional
|
|
3
3
|
|
|
4
4
|
from pydantic import BaseModel, EmailStr
|
|
5
5
|
|
|
6
|
-
from cuenca_validations.types import Address,
|
|
6
|
+
from cuenca_validations.types import Address, Curp, PhoneNumber, Rfc
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class BusinessDetails(BaseModel):
|
|
@@ -52,7 +52,7 @@ class PhysicalPerson(BaseModel):
|
|
|
52
52
|
names: str
|
|
53
53
|
first_surname: str
|
|
54
54
|
second_surname: Optional[str] = None
|
|
55
|
-
curp: Optional[
|
|
55
|
+
curp: Optional[Curp] = None
|
|
56
56
|
rfc: Optional[Rfc] = None
|
|
57
57
|
|
|
58
58
|
|
|
@@ -70,5 +70,5 @@ class ShareholderPhysical(PhysicalPerson):
|
|
|
70
70
|
class Shareholder(BaseModel):
|
|
71
71
|
name: str
|
|
72
72
|
percentage: int
|
|
73
|
-
shareholders:
|
|
74
|
-
legal_representatives:
|
|
73
|
+
shareholders: list[ShareholderPhysical]
|
|
74
|
+
legal_representatives: list[LegalRepresentative]
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import datetime as dt
|
|
2
|
-
from typing import Optional
|
|
3
|
-
|
|
4
|
-
from pydantic import
|
|
5
|
-
|
|
2
|
+
from typing import Annotated, Optional
|
|
3
|
+
|
|
4
|
+
from pydantic import (
|
|
5
|
+
BaseModel,
|
|
6
|
+
ConfigDict,
|
|
7
|
+
EmailStr,
|
|
8
|
+
Field,
|
|
9
|
+
PositiveInt,
|
|
10
|
+
field_validator,
|
|
11
|
+
)
|
|
6
12
|
|
|
7
13
|
from ..typing import DictStrAny
|
|
8
14
|
from ..validators import sanitize_dict
|
|
@@ -18,19 +24,16 @@ from .enums import (
|
|
|
18
24
|
TransferNetwork,
|
|
19
25
|
UserStatus,
|
|
20
26
|
)
|
|
21
|
-
from .identities import
|
|
27
|
+
from .identities import Curp
|
|
22
28
|
|
|
23
29
|
MAX_PAGE_SIZE = 100
|
|
24
30
|
|
|
25
31
|
|
|
26
|
-
class PageSize(ConstrainedInt):
|
|
27
|
-
gt = 0
|
|
28
|
-
le = MAX_PAGE_SIZE
|
|
29
|
-
|
|
30
|
-
|
|
31
32
|
class QueryParams(BaseModel):
|
|
32
33
|
count: bool = False
|
|
33
|
-
page_size:
|
|
34
|
+
page_size: Annotated[
|
|
35
|
+
int, Field(gt=0, le=MAX_PAGE_SIZE, default=MAX_PAGE_SIZE)
|
|
36
|
+
]
|
|
34
37
|
limit: Optional[PositiveInt] = None
|
|
35
38
|
user_id: Optional[str] = None
|
|
36
39
|
created_before: Optional[dt.datetime] = None
|
|
@@ -38,9 +41,9 @@ class QueryParams(BaseModel):
|
|
|
38
41
|
related_transaction: Optional[str] = None
|
|
39
42
|
platform_id: Optional[str] = None
|
|
40
43
|
|
|
41
|
-
|
|
42
|
-
extra
|
|
43
|
-
|
|
44
|
+
model_config = ConfigDict(
|
|
45
|
+
extra="forbid",
|
|
46
|
+
json_schema_extra={
|
|
44
47
|
'count': {'description': 'Set `true` value to get only a counter'},
|
|
45
48
|
'page_size': {'description': 'Number of items per page'},
|
|
46
49
|
'limit': {'description': 'Limit of items to query'},
|
|
@@ -54,12 +57,13 @@ class QueryParams(BaseModel):
|
|
|
54
57
|
'or greater than this value, this field represents the min '
|
|
55
58
|
'creation date.'
|
|
56
59
|
},
|
|
57
|
-
}
|
|
60
|
+
},
|
|
61
|
+
)
|
|
58
62
|
|
|
59
|
-
def
|
|
63
|
+
def model_dump(self, *args, **kwargs) -> DictStrAny:
|
|
60
64
|
kwargs.setdefault('exclude_none', True)
|
|
61
65
|
kwargs.setdefault('exclude_unset', True)
|
|
62
|
-
d = super().
|
|
66
|
+
d = super().model_dump(*args, **kwargs)
|
|
63
67
|
if self.count:
|
|
64
68
|
d['count'] = 1
|
|
65
69
|
sanitize_dict(d)
|
|
@@ -93,43 +97,34 @@ class CardTransactionQuery(TransactionQuery):
|
|
|
93
97
|
class ApiKeyQuery(QueryParams):
|
|
94
98
|
active: Optional[bool] = None
|
|
95
99
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
'
|
|
100
|
-
'
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
100
|
+
model_config = ConfigDict(
|
|
101
|
+
extra="forbid",
|
|
102
|
+
json_schema_extra={
|
|
103
|
+
'properties': {
|
|
104
|
+
'active': {
|
|
105
|
+
'description': 'Set `true` value to fetch active keys or '
|
|
106
|
+
'`false` to fetch deactivated keys'
|
|
107
|
+
},
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
)
|
|
104
111
|
|
|
105
112
|
|
|
106
113
|
class CardQuery(QueryParams):
|
|
107
114
|
number: Optional[str] = None
|
|
108
|
-
exp_month: Optional[int] = None
|
|
109
|
-
exp_year: Optional[int] = None
|
|
110
|
-
cvv: Optional[str] = None
|
|
111
|
-
cvv2: Optional[str] = None
|
|
112
|
-
icvv: Optional[str] = None
|
|
113
|
-
pin_block: Optional[str] = None
|
|
114
115
|
issuer: Optional[CardIssuer] = None
|
|
115
116
|
funding_type: Optional[CardFundingType] = None
|
|
116
117
|
status: Optional[CardStatus] = None
|
|
117
118
|
type: Optional[CardType] = None
|
|
118
119
|
|
|
119
|
-
@validator('exp_month', 'exp_year', 'cvv2', 'cvv')
|
|
120
|
-
def query_by_exp_cvv_if_number_set(cls, v, values):
|
|
121
|
-
if not values['number']:
|
|
122
|
-
raise ValueError('Number must be set to query by exp or cvv')
|
|
123
|
-
return v
|
|
124
|
-
|
|
125
120
|
|
|
126
121
|
class StatementQuery(QueryParams):
|
|
127
122
|
year: int
|
|
128
123
|
month: int
|
|
129
124
|
|
|
130
|
-
@
|
|
125
|
+
@field_validator('month')
|
|
131
126
|
def validate_year_month(cls, month, values):
|
|
132
|
-
year = values['year']
|
|
127
|
+
year = values.data['year']
|
|
133
128
|
month_now = dt.date.today().replace(day=1)
|
|
134
129
|
month_set = dt.date(year, month, 1)
|
|
135
130
|
if month_set >= month_now:
|
|
@@ -163,7 +158,7 @@ class UserQuery(QueryParams):
|
|
|
163
158
|
|
|
164
159
|
|
|
165
160
|
class IdentityQuery(QueryParams):
|
|
166
|
-
curp: Optional[
|
|
161
|
+
curp: Optional[Curp] = None
|
|
167
162
|
rfc: Optional[str] = None
|
|
168
163
|
status: Optional[UserStatus] = None
|
|
169
164
|
|