cuenca-validations 2.1.8.dev5__tar.gz → 2.1.8.dev7__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 (34) hide show
  1. {cuenca_validations-2.1.8.dev5 → cuenca_validations-2.1.8.dev7}/PKG-INFO +1 -1
  2. {cuenca_validations-2.1.8.dev5 → cuenca_validations-2.1.8.dev7}/cuenca_validations/types/__init__.py +2 -0
  3. {cuenca_validations-2.1.8.dev5 → cuenca_validations-2.1.8.dev7}/cuenca_validations/types/enums.py +16 -0
  4. {cuenca_validations-2.1.8.dev5 → cuenca_validations-2.1.8.dev7}/cuenca_validations/types/identities.py +34 -7
  5. {cuenca_validations-2.1.8.dev5 → cuenca_validations-2.1.8.dev7}/cuenca_validations/types/morals.py +3 -2
  6. {cuenca_validations-2.1.8.dev5 → cuenca_validations-2.1.8.dev7}/cuenca_validations/types/queries.py +2 -1
  7. {cuenca_validations-2.1.8.dev5 → cuenca_validations-2.1.8.dev7}/cuenca_validations/types/requests.py +19 -60
  8. cuenca_validations-2.1.8.dev7/cuenca_validations/version.py +1 -0
  9. {cuenca_validations-2.1.8.dev5 → cuenca_validations-2.1.8.dev7}/cuenca_validations.egg-info/PKG-INFO +1 -1
  10. {cuenca_validations-2.1.8.dev5 → cuenca_validations-2.1.8.dev7}/tests/test_types.py +33 -21
  11. cuenca_validations-2.1.8.dev5/cuenca_validations/version.py +0 -1
  12. {cuenca_validations-2.1.8.dev5 → cuenca_validations-2.1.8.dev7}/LICENSE +0 -0
  13. {cuenca_validations-2.1.8.dev5 → cuenca_validations-2.1.8.dev7}/README.md +0 -0
  14. {cuenca_validations-2.1.8.dev5 → cuenca_validations-2.1.8.dev7}/cuenca_validations/__init__.py +0 -0
  15. {cuenca_validations-2.1.8.dev5 → cuenca_validations-2.1.8.dev7}/cuenca_validations/card_bins.py +0 -0
  16. {cuenca_validations-2.1.8.dev5 → cuenca_validations-2.1.8.dev7}/cuenca_validations/errors.py +0 -0
  17. {cuenca_validations-2.1.8.dev5 → cuenca_validations-2.1.8.dev7}/cuenca_validations/py.typed +0 -0
  18. {cuenca_validations-2.1.8.dev5 → cuenca_validations-2.1.8.dev7}/cuenca_validations/types/card.py +0 -0
  19. {cuenca_validations-2.1.8.dev5 → cuenca_validations-2.1.8.dev7}/cuenca_validations/types/files.py +0 -0
  20. {cuenca_validations-2.1.8.dev5 → cuenca_validations-2.1.8.dev7}/cuenca_validations/types/general.py +0 -0
  21. {cuenca_validations-2.1.8.dev5 → cuenca_validations-2.1.8.dev7}/cuenca_validations/types/helpers.py +0 -0
  22. {cuenca_validations-2.1.8.dev5 → cuenca_validations-2.1.8.dev7}/cuenca_validations/typing.py +0 -0
  23. {cuenca_validations-2.1.8.dev5 → cuenca_validations-2.1.8.dev7}/cuenca_validations/validators.py +0 -0
  24. {cuenca_validations-2.1.8.dev5 → cuenca_validations-2.1.8.dev7}/cuenca_validations.egg-info/SOURCES.txt +0 -0
  25. {cuenca_validations-2.1.8.dev5 → cuenca_validations-2.1.8.dev7}/cuenca_validations.egg-info/dependency_links.txt +0 -0
  26. {cuenca_validations-2.1.8.dev5 → cuenca_validations-2.1.8.dev7}/cuenca_validations.egg-info/requires.txt +0 -0
  27. {cuenca_validations-2.1.8.dev5 → cuenca_validations-2.1.8.dev7}/cuenca_validations.egg-info/top_level.txt +0 -0
  28. {cuenca_validations-2.1.8.dev5 → cuenca_validations-2.1.8.dev7}/setup.cfg +0 -0
  29. {cuenca_validations-2.1.8.dev5 → cuenca_validations-2.1.8.dev7}/setup.py +0 -0
  30. {cuenca_validations-2.1.8.dev5 → cuenca_validations-2.1.8.dev7}/tests/__init__.py +0 -0
  31. {cuenca_validations-2.1.8.dev5 → cuenca_validations-2.1.8.dev7}/tests/test_card.py +0 -0
  32. {cuenca_validations-2.1.8.dev5 → cuenca_validations-2.1.8.dev7}/tests/test_errors.py +0 -0
  33. {cuenca_validations-2.1.8.dev5 → cuenca_validations-2.1.8.dev7}/tests/test_helpers.py +0 -0
  34. {cuenca_validations-2.1.8.dev5 → cuenca_validations-2.1.8.dev7}/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.8.dev5
3
+ Version: 2.1.8.dev7
4
4
  Summary: Cuenca common validations
5
5
  Home-page: https://github.com/cuenca-mx/cuenca-validations
6
6
  Author: Cuenca
@@ -56,6 +56,7 @@ __all__ = [
56
56
  'PlatformRequest',
57
57
  'PlatformType',
58
58
  'PosCapability',
59
+ 'Profession',
59
60
  'QueryParams',
60
61
  'Rfc',
61
62
  'QuestionnairesRequest',
@@ -135,6 +136,7 @@ from .enums import (
135
136
  Language,
136
137
  PlatformType,
137
138
  PosCapability,
139
+ Profession,
138
140
  SATRegimeCode,
139
141
  SavingCategory,
140
142
  ServiceProviderCategory,
@@ -688,3 +688,19 @@ class SATRegimeCode(str, Enum):
688
688
  ING_PREM = "615" # Régimen de los ingresos por obtención de premios
689
689
  AE_PLAT_TEC = "625" # Régimen de las Actividades Empresariales con ingresos a través de Plataformas Tecnológicas # noqa: E501
690
690
  RS_CONF = "626" # Régimen Simplificado de Confianza
691
+
692
+
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'
@@ -36,16 +36,24 @@ Rfc = Annotated[
36
36
  ),
37
37
  ]
38
38
 
39
+ # NOTE:
40
+ # The Address model is kept for compatibility with legacy models and data
41
+ # that expect all address fields to be optional. This allows older systems
42
+ # or stored data using Address to continue working without breaking changes.
43
+ # For new request validation, use AddressRequest, which enforces required
44
+ # fields and is intended for validating incoming data.
45
+
39
46
 
40
47
  class Address(BaseModel):
41
- street: NonEmptyStr
42
- ext_number: NonEmptyStr
43
- int_number: Optional[NonEmptyStr] = None
44
- colonia: Optional[NonEmptyStr] = None
45
- postal_code: Optional[NonEmptyStr] = None
48
+ street: Optional[str] = None
49
+ ext_number: Optional[str] = None
50
+ int_number: Optional[str] = None
51
+ colonia: Optional[str] = None
52
+ postal_code: Optional[str] = None
46
53
  state: Optional[State] = None
47
54
  country: Optional[Country] = None
48
- city: Optional[NonEmptyStr] = None
55
+ city: Optional[str] = None
56
+ full_name: Optional[str] = None
49
57
  model_config = ConfigDict(
50
58
  json_schema_extra={
51
59
  "example": {
@@ -62,12 +70,31 @@ class Address(BaseModel):
62
70
  )
63
71
 
64
72
 
73
+ class AddressRequest(BaseModel):
74
+ # This model is mainly for request validation, enforcing required fields.
75
+ street: NonEmptyStr
76
+ ext_number: NonEmptyStr
77
+ int_number: Optional[NonEmptyStr] = None
78
+ postal_code_id: NonEmptyStr
79
+
80
+ model_config = ConfigDict(
81
+ json_schema_extra={
82
+ "example": {
83
+ "street": "Reforma",
84
+ "ext_number": "265",
85
+ "int_number": "5",
86
+ "postal_code_id": "PC2ygq9j2bS9-9tsuVawzErA",
87
+ }
88
+ }
89
+ )
90
+
91
+
65
92
  class Beneficiary(BaseModel):
66
93
  name: str
67
94
  birth_date: dt.date
68
95
  phone_number: PhoneNumber
69
96
  user_relationship: str
70
- percentage: int
97
+ percentage: Annotated[int, Field(ge=1, le=100)]
71
98
  model_config = ConfigDict(
72
99
  json_schema_extra={
73
100
  "example": {
@@ -3,7 +3,8 @@ from typing import Optional
3
3
 
4
4
  from pydantic import BaseModel, EmailStr
5
5
 
6
- from cuenca_validations.types import Address, Curp, PhoneNumber, Rfc
6
+ from ..types import Curp, PhoneNumber, Rfc
7
+ from .identities import AddressRequest
7
8
 
8
9
 
9
10
  class BusinessDetails(BaseModel):
@@ -60,7 +61,7 @@ class LegalRepresentative(PhysicalPerson):
60
61
  job: str
61
62
  phone_number: PhoneNumber
62
63
  email_address: EmailStr
63
- address: Address
64
+ address: AddressRequest
64
65
 
65
66
 
66
67
  class ShareholderPhysical(PhysicalPerson):
@@ -24,6 +24,7 @@ from .enums import (
24
24
  TransferNetwork,
25
25
  UserStatus,
26
26
  )
27
+ from .general import digits
27
28
  from .identities import Curp
28
29
 
29
30
  MAX_PAGE_SIZE = 100
@@ -182,4 +183,4 @@ class BankAccountValidationQuery(QueryParams):
182
183
 
183
184
 
184
185
  class PostalCodeQuery(QueryParams):
185
- postal_code: str
186
+ postal_code: digits(5, 5) # type: ignore
@@ -32,6 +32,7 @@ from ..types.enums import (
32
32
  KYCValidationSource,
33
33
  PlatformType,
34
34
  PosCapability,
35
+ Profession,
35
36
  SavingCategory,
36
37
  SessionType,
37
38
  State,
@@ -39,7 +40,6 @@ from ..types.enums import (
39
40
  TrackDataMethod,
40
41
  TransactionTokenValidationStatus,
41
42
  UserCardNotification,
42
- UserStatus,
43
43
  VerificationType,
44
44
  WalletTransactionType,
45
45
  WebhookEvent,
@@ -64,13 +64,13 @@ from .general import (
64
64
  StrictPositiveInt,
65
65
  )
66
66
  from .identities import (
67
+ AddressRequest,
67
68
  Beneficiary,
68
69
  Curp,
69
70
  KYCFile,
70
71
  Password,
71
72
  PhoneNumber,
72
73
  Rfc,
73
- TOSAgreement,
74
74
  )
75
75
  from .morals import (
76
76
  AuditDetails,
@@ -83,24 +83,6 @@ from .morals import (
83
83
  )
84
84
 
85
85
 
86
- class AddressRequest(BaseModel):
87
- street: NonEmptyStr
88
- ext_number: NonEmptyStr
89
- int_number: Optional[NonEmptyStr] = None
90
- postal_code_id: NonEmptyStr
91
-
92
- model_config = ConfigDict(
93
- json_schema_extra={
94
- "example": {
95
- "street": "Reforma",
96
- "ext_number": "265",
97
- "int_number": "5",
98
- "postal_code_id": "PC2ygq9j2bS9-9tsuVawzErA",
99
- }
100
- }
101
- )
102
-
103
-
104
86
  class BaseRequest(BaseModel):
105
87
  model_config = ConfigDict(extra="forbid")
106
88
 
@@ -427,43 +409,25 @@ class UserTOSAgreementRequest(BaseModel):
427
409
 
428
410
 
429
411
  class UserRequest(BaseModel):
430
- id: Optional[str] = Field(
431
- None, description='if you want to create with specific `id`'
432
- )
433
412
  curp: Curp = Field(
434
- description='Previously validated in `curp_validations`'
435
- )
436
- phone_number: Optional[PhoneNumber] = Field(
437
- None, description='Only if you validated previously on your side'
438
- )
439
- email_address: Optional[EmailStr] = Field(
440
- None, description='Only if you validated previously on your side'
441
- )
442
- profession: Optional[str] = None
443
- address: AddressRequest
444
- status: Optional[UserStatus] = Field(
445
- None,
446
- description='Status that the user will have when created. '
447
- 'Defined by platform',
413
+ description=(
414
+ 'Mexican government ID (18 characters). ' 'Must be pre-validated.'
415
+ )
448
416
  )
449
- required_level: Optional[int] = Field(
450
- None,
451
- ge=1,
452
- le=3,
453
- description='Maximum level a User can reach. Defined by platform',
417
+
418
+ profession: Profession = Field(description='User profession or occupation')
419
+ address: AddressRequest = Field(
420
+ description='User residential address information'
454
421
  )
455
- phone_verification_id: Optional[str] = Field(
456
- None,
457
- description='Only if you validated it previously with the '
458
- 'resource `verifications`',
422
+ phone_verification_id: str = Field(
423
+ ...,
424
+ description='ID of previously validated phone verification',
459
425
  )
460
- email_verification_id: Optional[str] = Field(
461
- None,
462
- description='Only if you validated it previously with the '
463
- 'resource `verifications`',
426
+ email_verification_id: str = Field(
427
+ ...,
428
+ description='ID of previously validated email verification',
464
429
  )
465
- terms_of_service: Optional[TOSRequest] = None
466
- signature: Optional[KYCFile] = None
430
+
467
431
  model_config = ConfigDict(
468
432
  json_schema_extra={
469
433
  'example': {
@@ -496,9 +460,7 @@ class UserRequest(BaseModel):
496
460
 
497
461
 
498
462
  class UserUpdateRequest(BaseModel):
499
- phone_number: Optional[PhoneNumber] = None
500
- email_address: Optional[EmailStr] = None
501
- profession: Optional[str] = None
463
+ profession: Optional[Profession] = None
502
464
  verification_id: Optional[str] = None
503
465
  email_verification_id: Optional[str] = None
504
466
  phone_verification_id: Optional[str] = None
@@ -508,9 +470,6 @@ class UserUpdateRequest(BaseModel):
508
470
  proof_of_address: Optional[KYCFile] = None
509
471
  proof_of_life: Optional[KYCFile] = None
510
472
  signature: Optional[KYCFile] = None
511
- status: Optional[UserStatus] = None
512
- terms_of_service: Optional[TOSRequest] = None
513
- platform_terms_of_service: Optional[TOSAgreement] = None
514
473
  curp_document_uri: Optional[SerializableHttpUrl] = None
515
474
 
516
475
  @field_validator('beneficiaries')
@@ -518,8 +477,8 @@ class UserUpdateRequest(BaseModel):
518
477
  def beneficiary_percentage(
519
478
  cls, beneficiaries: Optional[list[Beneficiary]] = None
520
479
  ):
521
- if beneficiaries and sum(b.percentage for b in beneficiaries) > 100:
522
- raise ValueError('The total percentage is more than 100.')
480
+ if beneficiaries and sum(b.percentage for b in beneficiaries) != 100:
481
+ raise ValueError('The total percentage should be 100%')
523
482
  return beneficiaries
524
483
 
525
484
 
@@ -0,0 +1 @@
1
+ __version__ = '2.1.8.dev7'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cuenca_validations
3
- Version: 2.1.8.dev5
3
+ Version: 2.1.8.dev7
4
4
  Summary: Cuenca common validations
5
5
  Home-page: https://github.com/cuenca-mx/cuenca-validations
6
6
  Author: Cuenca
@@ -21,6 +21,7 @@ from cuenca_validations.types import (
21
21
  )
22
22
  from cuenca_validations.types.enums import (
23
23
  EcommerceIndicator,
24
+ Profession,
24
25
  SessionType,
25
26
  State,
26
27
  )
@@ -304,12 +305,8 @@ def test_saving_update_request():
304
305
  @freeze_time('2022-01-01')
305
306
  def test_user_request():
306
307
  request = dict(
307
- id=None,
308
308
  curp='ABCD920604HDFSRN03',
309
- phone_number='+525555555555',
310
- email_address='email@email.com',
311
- profession='worker',
312
- status='active',
309
+ profession=Profession.empleado,
313
310
  address=dict(
314
311
  street='calle 1',
315
312
  ext_number='2',
@@ -318,17 +315,29 @@ def test_user_request():
318
315
  ),
319
316
  phone_verification_id='VE12345678',
320
317
  email_verification_id='VE0987654321',
321
- required_level=3,
322
- terms_of_service=None,
323
- signature=None,
324
318
  )
325
319
  assert UserRequest(**request).model_dump() == request
326
320
 
327
- # changing curp so user is underage
328
- request['curp'] = 'ABCD060604HDFSRN03'
321
+
322
+ @freeze_time('2022-01-01')
323
+ def test_user_request_underage():
324
+ request = dict(
325
+ curp='ABCD060604HDFSRN03', # underage CURP
326
+ profession='worker',
327
+ address=dict(
328
+ street='calle 1',
329
+ ext_number='2',
330
+ int_number='3',
331
+ postal_code_id='PC2ygq9j2bS9-9tsuVawzErA',
332
+ ),
333
+ phone_verification_id='VE12345678',
334
+ email_verification_id='VE0987654321',
335
+ )
336
+
329
337
  with pytest.raises(ValueError) as v:
330
338
  UserRequest(**request)
331
- assert 'User does not meet age requirement.' in str(v)
339
+
340
+ assert 'User does not meet age requirement.' in str(v)
332
341
 
333
342
 
334
343
  @freeze_time('2022-01-01')
@@ -410,7 +419,7 @@ def test_user_update_request():
410
419
  birth_date=dt.date(2020, 1, 1).isoformat(),
411
420
  phone_number='+525555555555',
412
421
  user_relationship='brother',
413
- percentage=50,
422
+ percentage=100,
414
423
  ),
415
424
  ]
416
425
  assert UserUpdateRequest(**request)
@@ -421,12 +430,21 @@ def test_user_update_request():
421
430
  birth_date=dt.date(2020, 1, 1).isoformat(),
422
431
  phone_number='+525555555555',
423
432
  user_relationship='brother',
424
- percentage=101,
433
+ percentage=50,
434
+ ),
435
+ dict(
436
+ name='José Pérez',
437
+ birth_date=dt.date(2020, 1, 2).isoformat(),
438
+ phone_number='+525544444444',
439
+ user_relationship='brother',
440
+ percentage=51,
425
441
  ),
426
442
  ]
427
- with pytest.raises(ValueError) as v:
443
+ with pytest.raises(ValidationError) as v:
428
444
  UserUpdateRequest(**request)
429
- assert 'The total percentage is more than 100.' in str(v)
445
+
446
+ assert 'The total percentage should be 100%' in str(v)
447
+ request.pop('beneficiaries')
430
448
 
431
449
  tos_request = dict(
432
450
  terms_of_service=dict(
@@ -457,12 +475,6 @@ def test_user_update_request():
457
475
  )
458
476
  UserUpdateRequest(**kyc_request)
459
477
 
460
- # chagning to invalid request
461
- tos_request['terms_of_service']['ip'] = 'not valid ip'
462
- with pytest.raises(ValueError) as v:
463
- UserUpdateRequest(**tos_request)
464
- assert 'not valid ip' in str(v.value)
465
-
466
478
 
467
479
  def test_session_request():
468
480
  data = dict(
@@ -1 +0,0 @@
1
- __version__ = '2.1.8.dev5'