cuenca-validations 2.1.15__tar.gz → 2.1.16__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.
Files changed (36) hide show
  1. {cuenca_validations-2.1.15 → cuenca_validations-2.1.16}/PKG-INFO +1 -1
  2. {cuenca_validations-2.1.15 → cuenca_validations-2.1.16}/cuenca_validations/types/__init__.py +18 -0
  3. {cuenca_validations-2.1.15 → cuenca_validations-2.1.16}/cuenca_validations/types/enums.py +44 -13
  4. cuenca_validations-2.1.16/cuenca_validations/types/general.py +194 -0
  5. {cuenca_validations-2.1.15 → cuenca_validations-2.1.16}/cuenca_validations/types/requests.py +29 -3
  6. cuenca_validations-2.1.16/cuenca_validations/version.py +1 -0
  7. {cuenca_validations-2.1.15 → cuenca_validations-2.1.16}/cuenca_validations.egg-info/PKG-INFO +1 -1
  8. {cuenca_validations-2.1.15 → cuenca_validations-2.1.16}/tests/test_types.py +63 -2
  9. cuenca_validations-2.1.15/cuenca_validations/types/general.py +0 -107
  10. cuenca_validations-2.1.15/cuenca_validations/version.py +0 -1
  11. {cuenca_validations-2.1.15 → cuenca_validations-2.1.16}/LICENSE +0 -0
  12. {cuenca_validations-2.1.15 → cuenca_validations-2.1.16}/README.md +0 -0
  13. {cuenca_validations-2.1.15 → cuenca_validations-2.1.16}/cuenca_validations/__init__.py +0 -0
  14. {cuenca_validations-2.1.15 → cuenca_validations-2.1.16}/cuenca_validations/card_bins.py +0 -0
  15. {cuenca_validations-2.1.15 → cuenca_validations-2.1.16}/cuenca_validations/errors.py +0 -0
  16. {cuenca_validations-2.1.15 → cuenca_validations-2.1.16}/cuenca_validations/py.typed +0 -0
  17. {cuenca_validations-2.1.15 → cuenca_validations-2.1.16}/cuenca_validations/types/card.py +0 -0
  18. {cuenca_validations-2.1.15 → cuenca_validations-2.1.16}/cuenca_validations/types/files.py +0 -0
  19. {cuenca_validations-2.1.15 → cuenca_validations-2.1.16}/cuenca_validations/types/helpers.py +0 -0
  20. {cuenca_validations-2.1.15 → cuenca_validations-2.1.16}/cuenca_validations/types/identities.py +0 -0
  21. {cuenca_validations-2.1.15 → cuenca_validations-2.1.16}/cuenca_validations/types/morals.py +0 -0
  22. {cuenca_validations-2.1.15 → cuenca_validations-2.1.16}/cuenca_validations/types/queries.py +0 -0
  23. {cuenca_validations-2.1.15 → cuenca_validations-2.1.16}/cuenca_validations/typing.py +0 -0
  24. {cuenca_validations-2.1.15 → cuenca_validations-2.1.16}/cuenca_validations/validators.py +0 -0
  25. {cuenca_validations-2.1.15 → cuenca_validations-2.1.16}/cuenca_validations.egg-info/SOURCES.txt +0 -0
  26. {cuenca_validations-2.1.15 → cuenca_validations-2.1.16}/cuenca_validations.egg-info/dependency_links.txt +0 -0
  27. {cuenca_validations-2.1.15 → cuenca_validations-2.1.16}/cuenca_validations.egg-info/requires.txt +0 -0
  28. {cuenca_validations-2.1.15 → cuenca_validations-2.1.16}/cuenca_validations.egg-info/top_level.txt +0 -0
  29. {cuenca_validations-2.1.15 → cuenca_validations-2.1.16}/setup.cfg +0 -0
  30. {cuenca_validations-2.1.15 → cuenca_validations-2.1.16}/setup.py +0 -0
  31. {cuenca_validations-2.1.15 → cuenca_validations-2.1.16}/tests/__init__.py +0 -0
  32. {cuenca_validations-2.1.15 → cuenca_validations-2.1.16}/tests/test_card.py +0 -0
  33. {cuenca_validations-2.1.15 → cuenca_validations-2.1.16}/tests/test_errors.py +0 -0
  34. {cuenca_validations-2.1.15 → cuenca_validations-2.1.16}/tests/test_helpers.py +0 -0
  35. {cuenca_validations-2.1.15 → cuenca_validations-2.1.16}/tests/test_requests.py +0 -0
  36. {cuenca_validations-2.1.15 → cuenca_validations-2.1.16}/tests/test_statement.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cuenca_validations
3
- Version: 2.1.15
3
+ Version: 2.1.16
4
4
  Summary: Cuenca common validations
5
5
  Home-page: https://github.com/cuenca-mx/cuenca-validations
6
6
  Author: Cuenca
@@ -1,4 +1,5 @@
1
1
  __all__ = [
2
+ 'AccountUseType',
2
3
  'AccountQuery',
3
4
  'Address',
4
5
  'ApiKeyQuery',
@@ -43,6 +44,7 @@ __all__ = [
43
44
  'FileRequest',
44
45
  'FileUploadRequest',
45
46
  'Gender',
47
+ 'IncomeType',
46
48
  'IssuerNetwork',
47
49
  'IdentityQuery',
48
50
  'JSONEncoder',
@@ -52,6 +54,8 @@ __all__ = [
52
54
  'KYCValidationSource',
53
55
  'Language',
54
56
  'LimitedWalletRequest',
57
+ 'MonthlyMovementsType',
58
+ 'MonthlySpendingType',
55
59
  'PartnerRequest',
56
60
  'PartnerUpdateRequest',
57
61
  'PhoneNumber',
@@ -107,12 +111,18 @@ __all__ = [
107
111
  'WebhookEvent',
108
112
  'digits',
109
113
  'get_state_name',
114
+ 'get_profession_name',
115
+ 'get_income_type_name',
116
+ 'get_account_use_type_name',
117
+ 'get_monthly_movements_type_name',
118
+ 'get_monthly_spending_type_name',
110
119
  'uuid_field',
111
120
  'LogConfig',
112
121
  ]
113
122
 
114
123
  from .card import StrictPaymentCardNumber
115
124
  from .enums import (
125
+ AccountUseType,
116
126
  AuthorizerTransaction,
117
127
  BankAccountStatus,
118
128
  CardErrorType,
@@ -132,10 +142,13 @@ from .enums import (
132
142
  FileExtension,
133
143
  FileFormat,
134
144
  Gender,
145
+ IncomeType,
135
146
  IssuerNetwork,
136
147
  KYCFileType,
137
148
  KYCValidationSource,
138
149
  Language,
150
+ MonthlyMovementsType,
151
+ MonthlySpendingType,
139
152
  PlatformType,
140
153
  PosCapability,
141
154
  Profession,
@@ -163,6 +176,11 @@ from .general import (
163
176
  SantizedDict,
164
177
  StrictPositiveInt,
165
178
  digits,
179
+ get_account_use_type_name,
180
+ get_income_type_name,
181
+ get_monthly_movements_type_name,
182
+ get_monthly_spending_type_name,
183
+ get_profession_name,
166
184
  get_state_name,
167
185
  )
168
186
  from .helpers import uuid_field
@@ -691,16 +691,47 @@ class SATRegimeCode(str, Enum):
691
691
 
692
692
 
693
693
  class Profession(str, Enum):
694
- artisticas = 'Actividades Artísticas'
695
- agropecuario = 'Agricultura, Ganadería o Pesca'
696
- comercio = 'Comercio'
697
- estudiante = 'Estudiante'
698
- empleado = 'Empleado(a/e)'
699
- emprendimiento = 'Emprendimiento'
700
- hogar = 'Hogar'
701
- profesor = 'Profesor(a/e)'
702
- profesionista = 'Profesionista'
703
- servidor_publico = 'Servidor(a/e) Público'
704
- sistemas = 'Sistemas y Comunicaciones'
705
- independiente = 'Trabajador(a/e) Independiente'
706
- oficios = 'Oficios Varios'
694
+ artisticas = 'artisticas'
695
+ agropecuario = 'agropecuario'
696
+ comercio = 'comercio'
697
+ estudiante = 'estudiante'
698
+ empleado = 'empleado'
699
+ emprendimiento = 'emprendimiento'
700
+ hogar = 'hogar'
701
+ profesor = 'profesor'
702
+ profesionista = 'profesionista'
703
+ servidor_publico = 'servidor_publico'
704
+ sistemas = 'sistemas'
705
+ independiente = 'independiente'
706
+ oficios = 'oficios'
707
+ otro = 'otro'
708
+
709
+
710
+ class AccountUseType(str, Enum):
711
+ personal_expenses = 'personal_expenses'
712
+ business_expenses = 'business_expenses'
713
+ payment_of_goods_or_services = 'payment_of_goods_or_services'
714
+ send_or_receive_transfers = 'send_or_receive_transfers'
715
+
716
+
717
+ class MonthlyMovementsType(str, Enum):
718
+ between_1_and_20 = 'between_1_and_20'
719
+ between_20_and_40 = 'between_20_and_40'
720
+ between_40_and_60 = 'between_40_and_60'
721
+ more_than_60 = 'more_than_60'
722
+
723
+
724
+ class MonthlySpendingType(str, Enum):
725
+ less_than_1k = 'less_than_1k'
726
+ between_1k_and_10k = 'between_1k_and_10k'
727
+ between_10k_and_20k = 'between_10k_and_20k'
728
+ between_20k_and_50k = 'between_20k_and_50k'
729
+ between_50k_and_100k = 'between_50k_and_100k'
730
+ more_than_100k = 'more_than_100k'
731
+
732
+
733
+ class IncomeType(str, Enum):
734
+ salary = 'salary'
735
+ freelance = 'freelance'
736
+ support_from_third_party = 'support_from_third_party'
737
+ variable = 'variable'
@@ -0,0 +1,194 @@
1
+ import json
2
+ from dataclasses import dataclass
3
+ from typing import Annotated, Any, Optional
4
+
5
+ from pydantic import (
6
+ AnyUrl,
7
+ Field,
8
+ HttpUrl,
9
+ IPvAnyAddress,
10
+ PlainSerializer,
11
+ StringConstraints,
12
+ )
13
+
14
+ from ..validators import sanitize_dict, sanitize_item
15
+ from .enums import (
16
+ AccountUseType,
17
+ IncomeType,
18
+ MonthlyMovementsType,
19
+ MonthlySpendingType,
20
+ Profession,
21
+ State,
22
+ )
23
+
24
+ # We use custom serializers for IP addresses and URLs because
25
+ # Pydantic's IPvAnyAddress, AnyUrl, HttpUrl types are not JSON serializable.
26
+ SerializableHttpUrl = Annotated[HttpUrl, PlainSerializer(str, return_type=str)]
27
+ SerializableAnyUrl = Annotated[AnyUrl, PlainSerializer(str, return_type=str)]
28
+ SerializableIPvAnyAddress = Annotated[
29
+ IPvAnyAddress, PlainSerializer(str, return_type=str)
30
+ ]
31
+
32
+ NonEmptyStr = Annotated[
33
+ str, StringConstraints(strip_whitespace=True, min_length=1)
34
+ ]
35
+
36
+
37
+ class SantizedDict(dict):
38
+ def __init__(self, *args, **kwargs):
39
+ super().__init__(*args, **kwargs)
40
+ sanitize_dict(self)
41
+
42
+
43
+ class JSONEncoder(json.JSONEncoder):
44
+ def default(self, o):
45
+ return sanitize_item(o, default=super().default)
46
+
47
+
48
+ MAX_VALUE_IN_DB = 21_474_836_47
49
+
50
+ StrictPositiveInt = Annotated[
51
+ int, Field(strict=True, gt=0, le=MAX_VALUE_IN_DB)
52
+ ]
53
+
54
+
55
+ def digits(
56
+ min_length: Optional[int] = None, max_length: Optional[int] = None
57
+ ) -> Annotated[Any, StringConstraints]:
58
+ return Annotated[
59
+ str,
60
+ StringConstraints(
61
+ strip_whitespace=True,
62
+ min_length=min_length,
63
+ max_length=max_length,
64
+ pattern=r'^\d+$',
65
+ ),
66
+ ]
67
+
68
+
69
+ names_state = {
70
+ State.NE: 'Nacido en el Extranjero',
71
+ State.AS: 'Aguascalientes',
72
+ State.BC: 'Baja California',
73
+ State.BS: 'Baja California Sur',
74
+ State.CC: 'Campeche',
75
+ State.CS: 'Chiapas',
76
+ State.CH: 'Chihuahua',
77
+ State.CL: 'Coahuila',
78
+ State.CM: 'Colima',
79
+ State.DF: 'Ciudad de México',
80
+ State.DG: 'Durango',
81
+ State.GT: 'Guanajuato',
82
+ State.GR: 'Guerrero',
83
+ State.HG: 'Hidalgo',
84
+ State.JC: 'Jalisco',
85
+ State.MC: 'México',
86
+ State.MN: 'Michoacán',
87
+ State.MS: 'Morelos',
88
+ State.NT: 'Nayarit',
89
+ State.NL: 'Nuevo León',
90
+ State.OC: 'Oaxaca',
91
+ State.PL: 'Puebla',
92
+ State.QT: 'Querétaro',
93
+ State.QR: 'Quintana Roo',
94
+ State.SP: 'San Luis Potosí',
95
+ State.SL: 'Sinaloa',
96
+ State.SR: 'Sonora',
97
+ State.TC: 'Tabasco',
98
+ State.TL: 'Tlaxcala',
99
+ State.TS: 'Tamaulipas',
100
+ State.VZ: 'Veracruz',
101
+ State.YN: 'Yucatán',
102
+ State.ZS: 'Zacatecas',
103
+ }
104
+
105
+
106
+ def get_state_name(state: State) -> str:
107
+ return names_state[state]
108
+
109
+
110
+ names_professions = {
111
+ Profession.artisticas: 'Actividades Artísticas',
112
+ Profession.agropecuario: 'Agricultura, Ganadería o Pesca',
113
+ Profession.comercio: 'Comercio',
114
+ Profession.estudiante: 'Estudiante',
115
+ Profession.empleado: 'Empleado(a/e)',
116
+ Profession.emprendimiento: 'Emprendimiento',
117
+ Profession.hogar: 'Hogar',
118
+ Profession.profesor: 'Profesor(a/e)',
119
+ Profession.profesionista: 'Profesionista',
120
+ Profession.servidor_publico: 'Servidor(a/e) Público',
121
+ Profession.sistemas: 'Sistemas y Comunicaciones',
122
+ Profession.independiente: 'Trabajador(a/e) Independiente',
123
+ Profession.oficios: 'Oficios Varios',
124
+ Profession.otro: 'Otro',
125
+ }
126
+
127
+
128
+ def get_profession_name(profession: Profession) -> str:
129
+ return names_professions[profession]
130
+
131
+
132
+ names_account_use_types = {
133
+ AccountUseType.personal_expenses: 'Gastos personales o familiares',
134
+ AccountUseType.business_expenses: (
135
+ 'Gastos relacionados con tu actividad económica'
136
+ ),
137
+ AccountUseType.payment_of_goods_or_services: 'Pago de bienes o servicios',
138
+ AccountUseType.send_or_receive_transfers: (
139
+ 'Enviar o recibir transferencias'
140
+ ),
141
+ }
142
+
143
+
144
+ def get_account_use_type_name(account_use_type: AccountUseType) -> str:
145
+ return names_account_use_types[account_use_type]
146
+
147
+
148
+ names_monthly_movements_types = {
149
+ MonthlyMovementsType.between_1_and_20: 'Entre 1 y 20 movimientos',
150
+ MonthlyMovementsType.between_20_and_40: 'Entre 20 y 40 movimientos',
151
+ MonthlyMovementsType.between_40_and_60: 'Entre 40 y 60 movimientos',
152
+ MonthlyMovementsType.more_than_60: 'Más de 60 movimientos',
153
+ }
154
+
155
+
156
+ def get_monthly_movements_type_name(
157
+ monthly_movements_type: MonthlyMovementsType,
158
+ ) -> str:
159
+ return names_monthly_movements_types[monthly_movements_type]
160
+
161
+
162
+ names_monthly_spending_types = {
163
+ MonthlySpendingType.less_than_1k: 'Menos de $1,000',
164
+ MonthlySpendingType.between_1k_and_10k: 'Entre $1,000 y $10,000',
165
+ MonthlySpendingType.between_10k_and_20k: 'Entre $10,000 y $20,000',
166
+ MonthlySpendingType.between_20k_and_50k: 'Entre $20,000 y $50,000',
167
+ MonthlySpendingType.between_50k_and_100k: 'Entre $50,000 y $100,000',
168
+ MonthlySpendingType.more_than_100k: 'Más de $100,000',
169
+ }
170
+
171
+
172
+ def get_monthly_spending_type_name(
173
+ monthly_spending_type: MonthlySpendingType,
174
+ ) -> str:
175
+ return names_monthly_spending_types[monthly_spending_type]
176
+
177
+
178
+ names_income_types = {
179
+ IncomeType.salary: 'Sueldo o salario fijo',
180
+ IncomeType.freelance: 'Independiente',
181
+ IncomeType.support_from_third_party: 'Apoyo de terceros o familiares',
182
+ IncomeType.variable: 'Variable',
183
+ }
184
+
185
+
186
+ def get_income_type_name(income_type: IncomeType) -> str:
187
+ return names_income_types[income_type]
188
+
189
+
190
+ @dataclass
191
+ class LogConfig:
192
+ masked: bool = False
193
+ unmasked_chars_length: int = 0
194
+ excluded: bool = False
@@ -17,6 +17,7 @@ from pydantic_core import core_schema
17
17
  from pydantic_extra_types.coordinate import Coordinate
18
18
 
19
19
  from ..types.enums import (
20
+ AccountUseType,
20
21
  AuthorizerTransaction,
21
22
  CardDesign,
22
23
  CardFundingType,
@@ -29,9 +30,12 @@ from ..types.enums import (
29
30
  EcommerceIndicator,
30
31
  FileExtension,
31
32
  Gender,
33
+ IncomeType,
32
34
  IssuerNetwork,
33
35
  KYCFileType,
34
36
  KYCValidationSource,
37
+ MonthlyMovementsType,
38
+ MonthlySpendingType,
35
39
  PlatformType,
36
40
  PosCapability,
37
41
  Profession,
@@ -447,7 +451,6 @@ class UserRequest(BaseModel):
447
451
  'Mexican government ID (18 characters). ' 'Must be pre-validated.'
448
452
  )
449
453
  )
450
-
451
454
  profession: Profession = Field(description='User profession or occupation')
452
455
  address: AddressRequest = Field(
453
456
  description='User residential address information'
@@ -460,13 +463,17 @@ class UserRequest(BaseModel):
460
463
  ...,
461
464
  description='ID of previously validated email verification',
462
465
  )
466
+ account_use_type: Optional[AccountUseType] = None
467
+ monthly_movements_type: Optional[MonthlyMovementsType] = None
468
+ monthly_spending_type: Optional[MonthlySpendingType] = None
469
+ income_type: Optional[IncomeType] = None
463
470
 
464
471
  model_config = ConfigDict(
465
472
  json_schema_extra={
466
473
  'example': {
467
474
  'curp': 'GOCG650418HVZNML08',
468
- 'phone_number': '+525511223344',
469
- 'email_address': 'user@example.com',
475
+ 'phone_verification_id': 'VEKp662Yrf6lMztl0-9qzk7Q',
476
+ 'email_verification_id': 'VEwjDEcCMWZIk3JJ3p7P6T_A',
470
477
  'profession': 'engineer',
471
478
  'address': AddressRequest.model_json_schema().get('example'),
472
479
  }
@@ -480,6 +487,13 @@ class UserRequest(BaseModel):
480
487
  validate_age_requirement(curp)
481
488
  return curp
482
489
 
490
+ @field_validator('profession')
491
+ @classmethod
492
+ def validate_profession(cls, profession: Profession) -> Profession:
493
+ if profession == Profession.otro:
494
+ raise ValueError('Profession "otro" is not allowed')
495
+ return profession
496
+
483
497
 
484
498
  class UserUpdateRequest(BaseModel):
485
499
  profession: Optional[Profession] = None
@@ -492,9 +506,14 @@ class UserUpdateRequest(BaseModel):
492
506
  proof_of_life: Optional[KYCFile] = None
493
507
  curp_document_uri: Optional[SerializableHttpUrl] = None
494
508
  fiscal_regime_code: Optional[SATRegimeCode] = None
509
+ fiscal_address: Optional[AddressRequest] = None
495
510
  pronouns: Optional[str] = None
496
511
  status: Optional[UserStatus] = None
497
512
  required_level: Optional[int] = None
513
+ account_use_type: Optional[AccountUseType] = None
514
+ monthly_movements_type: Optional[MonthlyMovementsType] = None
515
+ monthly_spending_type: Optional[MonthlySpendingType] = None
516
+ income_type: Optional[IncomeType] = None
498
517
 
499
518
  @field_validator('beneficiaries')
500
519
  @classmethod
@@ -505,6 +524,13 @@ class UserUpdateRequest(BaseModel):
505
524
  raise ValueError('The total percentage should be 100%')
506
525
  return beneficiaries
507
526
 
527
+ @field_validator('profession')
528
+ @classmethod
529
+ def validate_profession(cls, profession: Profession) -> Profession:
530
+ if profession == Profession.otro:
531
+ raise ValueError('Profession "otro" is not allowed')
532
+ return profession
533
+
508
534
 
509
535
  class UserLoginRequest(BaseRequest):
510
536
  password: Annotated[
@@ -0,0 +1 @@
1
+ __version__ = '2.1.16'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cuenca_validations
3
- Version: 2.1.15
3
+ Version: 2.1.16
4
4
  Summary: Cuenca common validations
5
5
  Home-page: https://github.com/cuenca-mx/cuenca-validations
6
6
  Author: Cuenca
@@ -17,10 +17,19 @@ from cuenca_validations.types import (
17
17
  SessionRequest,
18
18
  TransactionStatus,
19
19
  digits,
20
+ get_account_use_type_name,
21
+ get_income_type_name,
22
+ get_monthly_movements_type_name,
23
+ get_monthly_spending_type_name,
24
+ get_profession_name,
20
25
  get_state_name,
21
26
  )
22
27
  from cuenca_validations.types.enums import (
28
+ AccountUseType,
23
29
  EcommerceIndicator,
30
+ IncomeType,
31
+ MonthlyMovementsType,
32
+ MonthlySpendingType,
24
33
  Profession,
25
34
  SessionType,
26
35
  State,
@@ -316,7 +325,24 @@ def test_user_request():
316
325
  phone_verification_id='VE12345678',
317
326
  email_verification_id='VE0987654321',
318
327
  )
319
- assert UserRequest(**request).model_dump() == request
328
+ assert UserRequest(**request).model_dump(exclude_none=True) == request
329
+
330
+
331
+ def test_user_request_invalid_profession():
332
+ request = dict(
333
+ curp='ABCD920604HDFSRN03',
334
+ profession=Profession.otro,
335
+ address=dict(
336
+ street='calle 1',
337
+ ext_number='2',
338
+ int_number='3',
339
+ postal_code_id='PC2ygq9j2bS9-9tsuVawzErA',
340
+ ),
341
+ phone_verification_id='VE12345678',
342
+ email_verification_id='VE0987654321',
343
+ )
344
+ with pytest.raises(ValidationError):
345
+ UserRequest(**request)
320
346
 
321
347
 
322
348
  @freeze_time('2022-01-01')
@@ -410,6 +436,7 @@ def test_user_update_request():
410
436
  ),
411
437
  ],
412
438
  curp_document_uri='https://sandbox.cuenca.com/files/EF123',
439
+ profession=Profession.empleado,
413
440
  )
414
441
  update_req = UserUpdateRequest(**request)
415
442
  beneficiaries = [b.model_dump() for b in update_req.beneficiaries]
@@ -418,6 +445,7 @@ def test_user_update_request():
418
445
  update_req.curp_document_uri.unicode_string()
419
446
  == request['curp_document_uri']
420
447
  )
448
+ assert update_req.profession == Profession.empleado
421
449
 
422
450
  request['beneficiaries'] = [
423
451
  dict(
@@ -481,6 +509,10 @@ def test_user_update_request():
481
509
  )
482
510
  UserUpdateRequest(**kyc_request)
483
511
 
512
+ request['profession'] = Profession.otro
513
+ with pytest.raises(ValidationError) as v:
514
+ UserUpdateRequest(**request)
515
+
484
516
 
485
517
  def test_session_request():
486
518
  data = dict(
@@ -544,10 +576,39 @@ def test_limited_wallet_request():
544
576
  assert LimitedWalletRequest(allowed_curp=curp, allowed_rfc=rfc)
545
577
 
546
578
 
547
- def test_get_state_name():
579
+ def test_get_state_name() -> None:
548
580
  assert get_state_name(State.VZ) == 'Veracruz'
549
581
 
550
582
 
583
+ def test_get_profession_name() -> None:
584
+ assert get_profession_name(Profession.empleado) == 'Empleado(a/e)'
585
+
586
+
587
+ def test_get_income_type_name() -> None:
588
+ assert get_income_type_name(IncomeType.salary) == 'Sueldo o salario fijo'
589
+
590
+
591
+ def test_get_account_use_type_name() -> None:
592
+ assert (
593
+ get_account_use_type_name(AccountUseType.personal_expenses)
594
+ == 'Gastos personales o familiares'
595
+ )
596
+
597
+
598
+ def test_get_monthly_spending_type_name() -> None:
599
+ assert (
600
+ get_monthly_spending_type_name(MonthlySpendingType.less_than_1k)
601
+ == 'Menos de $1,000'
602
+ )
603
+
604
+
605
+ def test_get_monthly_movements_type_name() -> None:
606
+ assert (
607
+ get_monthly_movements_type_name(MonthlyMovementsType.between_1_and_20)
608
+ == 'Entre 1 y 20 movimientos'
609
+ )
610
+
611
+
551
612
  def test_bank_account_validation_clabe_request():
552
613
  assert BankAccountValidationRequest(account_number='646180157098510917')
553
614
 
@@ -1,107 +0,0 @@
1
- import json
2
- from dataclasses import dataclass
3
- from typing import Annotated, Any, Optional
4
-
5
- from pydantic import (
6
- AnyUrl,
7
- Field,
8
- HttpUrl,
9
- IPvAnyAddress,
10
- PlainSerializer,
11
- StringConstraints,
12
- )
13
-
14
- from ..validators import sanitize_dict, sanitize_item
15
- from .enums import State
16
-
17
- # We use custom serializers for IP addresses and URLs because
18
- # Pydantic's IPvAnyAddress, AnyUrl, HttpUrl types are not JSON serializable.
19
- SerializableHttpUrl = Annotated[HttpUrl, PlainSerializer(str, return_type=str)]
20
- SerializableAnyUrl = Annotated[AnyUrl, PlainSerializer(str, return_type=str)]
21
- SerializableIPvAnyAddress = Annotated[
22
- IPvAnyAddress, PlainSerializer(str, return_type=str)
23
- ]
24
-
25
- NonEmptyStr = Annotated[
26
- str, StringConstraints(strip_whitespace=True, min_length=1)
27
- ]
28
-
29
-
30
- class SantizedDict(dict):
31
- def __init__(self, *args, **kwargs):
32
- super().__init__(*args, **kwargs)
33
- sanitize_dict(self)
34
-
35
-
36
- class JSONEncoder(json.JSONEncoder):
37
- def default(self, o):
38
- return sanitize_item(o, default=super().default)
39
-
40
-
41
- MAX_VALUE_IN_DB = 21_474_836_47
42
-
43
- StrictPositiveInt = Annotated[
44
- int, Field(strict=True, gt=0, le=MAX_VALUE_IN_DB)
45
- ]
46
-
47
-
48
- def digits(
49
- min_length: Optional[int] = None, max_length: Optional[int] = None
50
- ) -> Annotated[Any, StringConstraints]:
51
- return Annotated[
52
- str,
53
- StringConstraints(
54
- strip_whitespace=True,
55
- min_length=min_length,
56
- max_length=max_length,
57
- pattern=r'^\d+$',
58
- ),
59
- ]
60
-
61
-
62
- names_state = {
63
- State.NE: 'Nacido en el Extranjero',
64
- State.AS: 'Aguascalientes',
65
- State.BC: 'Baja California',
66
- State.BS: 'Baja California Sur',
67
- State.CC: 'Campeche',
68
- State.CS: 'Chiapas',
69
- State.CH: 'Chihuahua',
70
- State.CL: 'Coahuila',
71
- State.CM: 'Colima',
72
- State.DF: 'Ciudad de México',
73
- State.DG: 'Durango',
74
- State.GT: 'Guanajuato',
75
- State.GR: 'Guerrero',
76
- State.HG: 'Hidalgo',
77
- State.JC: 'Jalisco',
78
- State.MC: 'México',
79
- State.MN: 'Michoacan',
80
- State.MS: 'Morelos',
81
- State.NT: 'Nayarit',
82
- State.NL: 'Nuevo León',
83
- State.OC: 'Oaxaca',
84
- State.PL: 'Puebla',
85
- State.QT: 'Querétaro',
86
- State.QR: 'Quintana Roo',
87
- State.SP: 'San Luis Potosí',
88
- State.SL: 'Sinaloa',
89
- State.SR: 'Sonora',
90
- State.TC: 'Tabasco',
91
- State.TL: 'Tlaxcala',
92
- State.TS: 'Tamaulipas',
93
- State.VZ: 'Veracruz',
94
- State.YN: 'Yucatán',
95
- State.ZS: 'Zacatecas',
96
- }
97
-
98
-
99
- def get_state_name(state: State):
100
- return names_state[state]
101
-
102
-
103
- @dataclass
104
- class LogConfig:
105
- masked: bool = False
106
- unmasked_chars_length: int = 0
107
- excluded: bool = False
@@ -1 +0,0 @@
1
- __version__ = '2.1.15'