cuenca-validations 2.1.16.dev100__tar.gz → 2.1.17__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.16.dev100 → cuenca_validations-2.1.17}/PKG-INFO +1 -1
  2. {cuenca_validations-2.1.16.dev100 → cuenca_validations-2.1.17}/cuenca_validations/types/__init__.py +2 -0
  3. {cuenca_validations-2.1.16.dev100 → cuenca_validations-2.1.17}/cuenca_validations/types/enums.py +1 -2
  4. {cuenca_validations-2.1.16.dev100 → cuenca_validations-2.1.17}/cuenca_validations/types/general.py +1 -1
  5. {cuenca_validations-2.1.16.dev100 → cuenca_validations-2.1.17}/cuenca_validations/types/identities.py +7 -3
  6. {cuenca_validations-2.1.16.dev100 → cuenca_validations-2.1.17}/cuenca_validations/types/requests.py +30 -24
  7. cuenca_validations-2.1.17/cuenca_validations/version.py +1 -0
  8. {cuenca_validations-2.1.16.dev100 → cuenca_validations-2.1.17}/cuenca_validations.egg-info/PKG-INFO +1 -1
  9. cuenca_validations-2.1.17/tests/test_requests.py +31 -0
  10. {cuenca_validations-2.1.16.dev100 → cuenca_validations-2.1.17}/tests/test_types.py +26 -26
  11. cuenca_validations-2.1.16.dev100/cuenca_validations/version.py +0 -1
  12. cuenca_validations-2.1.16.dev100/tests/test_requests.py +0 -70
  13. {cuenca_validations-2.1.16.dev100 → cuenca_validations-2.1.17}/LICENSE +0 -0
  14. {cuenca_validations-2.1.16.dev100 → cuenca_validations-2.1.17}/README.md +0 -0
  15. {cuenca_validations-2.1.16.dev100 → cuenca_validations-2.1.17}/cuenca_validations/__init__.py +0 -0
  16. {cuenca_validations-2.1.16.dev100 → cuenca_validations-2.1.17}/cuenca_validations/card_bins.py +0 -0
  17. {cuenca_validations-2.1.16.dev100 → cuenca_validations-2.1.17}/cuenca_validations/errors.py +0 -0
  18. {cuenca_validations-2.1.16.dev100 → cuenca_validations-2.1.17}/cuenca_validations/py.typed +0 -0
  19. {cuenca_validations-2.1.16.dev100 → cuenca_validations-2.1.17}/cuenca_validations/types/card.py +0 -0
  20. {cuenca_validations-2.1.16.dev100 → cuenca_validations-2.1.17}/cuenca_validations/types/files.py +0 -0
  21. {cuenca_validations-2.1.16.dev100 → cuenca_validations-2.1.17}/cuenca_validations/types/helpers.py +0 -0
  22. {cuenca_validations-2.1.16.dev100 → cuenca_validations-2.1.17}/cuenca_validations/types/morals.py +0 -0
  23. {cuenca_validations-2.1.16.dev100 → cuenca_validations-2.1.17}/cuenca_validations/types/queries.py +0 -0
  24. {cuenca_validations-2.1.16.dev100 → cuenca_validations-2.1.17}/cuenca_validations/typing.py +0 -0
  25. {cuenca_validations-2.1.16.dev100 → cuenca_validations-2.1.17}/cuenca_validations/validators.py +0 -0
  26. {cuenca_validations-2.1.16.dev100 → cuenca_validations-2.1.17}/cuenca_validations.egg-info/SOURCES.txt +0 -0
  27. {cuenca_validations-2.1.16.dev100 → cuenca_validations-2.1.17}/cuenca_validations.egg-info/dependency_links.txt +0 -0
  28. {cuenca_validations-2.1.16.dev100 → cuenca_validations-2.1.17}/cuenca_validations.egg-info/requires.txt +0 -0
  29. {cuenca_validations-2.1.16.dev100 → cuenca_validations-2.1.17}/cuenca_validations.egg-info/top_level.txt +0 -0
  30. {cuenca_validations-2.1.16.dev100 → cuenca_validations-2.1.17}/setup.cfg +0 -0
  31. {cuenca_validations-2.1.16.dev100 → cuenca_validations-2.1.17}/setup.py +0 -0
  32. {cuenca_validations-2.1.16.dev100 → cuenca_validations-2.1.17}/tests/__init__.py +0 -0
  33. {cuenca_validations-2.1.16.dev100 → cuenca_validations-2.1.17}/tests/test_card.py +0 -0
  34. {cuenca_validations-2.1.16.dev100 → cuenca_validations-2.1.17}/tests/test_errors.py +0 -0
  35. {cuenca_validations-2.1.16.dev100 → cuenca_validations-2.1.17}/tests/test_helpers.py +0 -0
  36. {cuenca_validations-2.1.16.dev100 → cuenca_validations-2.1.17}/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.16.dev100
3
+ Version: 2.1.17
4
4
  Summary: Cuenca common validations
5
5
  Home-page: https://github.com/cuenca-mx/cuenca-validations
6
6
  Author: Cuenca
@@ -14,6 +14,7 @@ __all__ = [
14
14
  'BankAccountStatus',
15
15
  'BatchFileMetadata',
16
16
  'Beneficiary',
17
+ 'BeneficiaryRequest',
17
18
  'BillPaymentQuery',
18
19
  'CardErrorType',
19
20
  'CardFundingType',
@@ -221,6 +222,7 @@ from .queries import (
221
222
  from .requests import (
222
223
  ApiKeyUpdateRequest,
223
224
  BankAccountValidationRequest,
225
+ BeneficiaryRequest,
224
226
  CurpValidationRequest,
225
227
  EndpointRequest,
226
228
  EndpointUpdateRequest,
@@ -588,7 +588,6 @@ class SessionType(str, Enum):
588
588
  account_entries = 'session.account_entries'
589
589
  download_file = 'session.download_file'
590
590
  upload_file = 'session.upload_file'
591
- metamap_verification = 'session.metamap_verification'
592
591
 
593
592
 
594
593
  class WebhookObject(str, Enum):
@@ -705,7 +704,7 @@ class Profession(str, Enum):
705
704
  sistemas = 'sistemas'
706
705
  independiente = 'independiente'
707
706
  oficios = 'oficios'
708
- otros = 'otros'
707
+ otro = 'otro'
709
708
 
710
709
 
711
710
  class AccountUseType(str, Enum):
@@ -121,7 +121,7 @@ names_professions = {
121
121
  Profession.sistemas: 'Sistemas y Comunicaciones',
122
122
  Profession.independiente: 'Trabajador(a/e) Independiente',
123
123
  Profession.oficios: 'Oficios Varios',
124
- Profession.otros: 'Otros',
124
+ Profession.otro: 'Otro',
125
125
  }
126
126
 
127
127
 
@@ -1,5 +1,5 @@
1
1
  import datetime as dt
2
- from typing import Annotated, Optional
2
+ from typing import Annotated, Optional, Union
3
3
 
4
4
  from pydantic import BaseModel, ConfigDict, Field, SecretStr, StringConstraints
5
5
  from pydantic_extra_types.phone_numbers import PhoneNumber
@@ -89,12 +89,12 @@ class AddressRequest(BaseModel):
89
89
  )
90
90
 
91
91
 
92
- class Beneficiary(BaseModel):
92
+ class BaseBeneficiary(BaseModel):
93
93
  name: str
94
94
  birth_date: dt.date
95
- phone_number: PhoneNumber
96
95
  user_relationship: str
97
96
  percentage: Annotated[int, Field(ge=1, le=100)]
97
+
98
98
  model_config = ConfigDict(
99
99
  json_schema_extra={
100
100
  "example": {
@@ -108,6 +108,10 @@ class Beneficiary(BaseModel):
108
108
  )
109
109
 
110
110
 
111
+ class Beneficiary(BaseBeneficiary):
112
+ phone_number: Union[PhoneNumber, str]
113
+
114
+
111
115
  class VerificationErrors(BaseModel):
112
116
  identifier: str = Field(
113
117
  description='Unique identifier for the step validation'
@@ -73,7 +73,7 @@ from .general import (
73
73
  from .helpers import validate_age_requirement
74
74
  from .identities import (
75
75
  AddressRequest,
76
- Beneficiary,
76
+ BaseBeneficiary,
77
77
  Curp,
78
78
  KYCFile,
79
79
  Password,
@@ -330,7 +330,7 @@ class UserPldRiskLevelRequest(BaseModel):
330
330
  level: float = Field(ge=0.0, le=1.0)
331
331
 
332
332
 
333
- class CurpValidationRequest(BaseModel):
333
+ class CurpValidationRequest(BaseRequest):
334
334
  names: Optional[str] = None
335
335
  first_surname: Optional[str] = None
336
336
  second_surname: Optional[str] = Field(
@@ -439,13 +439,13 @@ class FileCuencaUrl(str):
439
439
  )
440
440
 
441
441
 
442
- class UserTOSAgreementRequest(BaseModel):
442
+ class UserTOSAgreementRequest(BaseRequest):
443
443
  tos_id: str
444
444
  location: Coordinate
445
445
  signature_image_url: Optional[FileCuencaUrl] = None
446
446
 
447
447
 
448
- class UserRequest(BaseModel):
448
+ class UserRequest(BaseRequest):
449
449
  curp: Curp = Field(
450
450
  description=(
451
451
  'Mexican government ID (18 characters). ' 'Must be pre-validated.'
@@ -487,13 +487,24 @@ class UserRequest(BaseModel):
487
487
  validate_age_requirement(curp)
488
488
  return curp
489
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
+
497
+
498
+ class BeneficiaryRequest(BaseBeneficiary, BaseRequest):
499
+ phone_number: PhoneNumber
500
+
490
501
 
491
- class UserUpdateRequest(BaseModel):
502
+ class UserUpdateRequest(BaseRequest):
492
503
  profession: Optional[Profession] = None
493
504
  email_verification_id: Optional[str] = None
494
505
  phone_verification_id: Optional[str] = None
495
506
  address: Optional[AddressRequest] = None
496
- beneficiaries: Optional[list[Beneficiary]] = None
507
+ beneficiaries: Optional[list[BeneficiaryRequest]] = None
497
508
  govt_id: Optional[KYCFile] = None
498
509
  proof_of_address: Optional[KYCFile] = None
499
510
  proof_of_life: Optional[KYCFile] = None
@@ -511,12 +522,19 @@ class UserUpdateRequest(BaseModel):
511
522
  @field_validator('beneficiaries')
512
523
  @classmethod
513
524
  def beneficiary_percentage(
514
- cls, beneficiaries: Optional[list[Beneficiary]] = None
525
+ cls, beneficiaries: Optional[list[BeneficiaryRequest]] = None
515
526
  ):
516
527
  if beneficiaries and sum(b.percentage for b in beneficiaries) != 100:
517
528
  raise ValueError('The total percentage should be 100%')
518
529
  return beneficiaries
519
530
 
531
+ @field_validator('profession')
532
+ @classmethod
533
+ def validate_profession(cls, profession: Profession) -> Profession:
534
+ if profession == Profession.otro:
535
+ raise ValueError('Profession "otro" is not allowed')
536
+ return profession
537
+
520
538
 
521
539
  class UserLoginRequest(BaseRequest):
522
540
  password: Annotated[
@@ -533,17 +551,6 @@ class SessionRequest(BaseRequest):
533
551
  type: SessionType
534
552
  success_url: Optional[SerializableAnyUrl] = None
535
553
  failure_url: Optional[SerializableAnyUrl] = None
536
- metadata: Optional[dict] = None
537
-
538
- @model_validator(mode='before')
539
- @classmethod
540
- def validate_metadata(cls, values: dict) -> dict:
541
- if values[
542
- 'type'
543
- ] == SessionType.metamap_verification and not values.get('metadata'):
544
- raise ValueError('Metadata expected for this session')
545
- return values
546
-
547
554
  model_config = ConfigDict(
548
555
  json_schema_extra={
549
556
  'example': {
@@ -551,7 +558,6 @@ class SessionRequest(BaseRequest):
551
558
  'type': 'session.registration',
552
559
  'success_url': 'http://example_success.com',
553
560
  'failure_url': 'http://example_failure.com',
554
- 'metadata': {'verification_id': 'some_verification_id'},
555
561
  }
556
562
  }
557
563
  )
@@ -588,7 +594,7 @@ class FileBatchUploadRequest(BaseModel):
588
594
  user_id: str
589
595
 
590
596
 
591
- class VerificationRequest(BaseModel):
597
+ class VerificationRequest(BaseRequest):
592
598
  type: VerificationType
593
599
  recipient: Union[EmailStr, PhoneNumber] = Field(
594
600
  description='Phone or email to validate'
@@ -612,7 +618,7 @@ class VerificationRequest(BaseModel):
612
618
  )
613
619
 
614
620
 
615
- class VerificationAttemptRequest(BaseModel):
621
+ class VerificationAttemptRequest(BaseRequest):
616
622
  code: Annotated[
617
623
  str,
618
624
  StringConstraints(strict=True, min_length=6, max_length=6),
@@ -653,11 +659,11 @@ class KYCValidationRequest(BaseRequest):
653
659
  force: bool = False
654
660
 
655
661
 
656
- class BankAccountValidationRequest(BaseModel):
662
+ class BankAccountValidationRequest(BaseRequest):
657
663
  account_number: Union[Clabe, PaymentCardNumber]
658
664
 
659
665
 
660
- class UserListsRequest(BaseModel):
666
+ class UserListsRequest(BaseRequest):
661
667
  curp: Optional[Curp] = Field(None, description='Curp to review on lists')
662
668
  rfc: Optional[Rfc] = Field(None, description='Rfc to review on lists')
663
669
  account_number: Optional[Union[Clabe, PaymentCardNumber]] = Field(
@@ -756,5 +762,5 @@ class PartnerUpdateRequest(BaseRequest):
756
762
  shareholders: Optional[list[Shareholder]] = None
757
763
 
758
764
 
759
- class PhoneVerificationAssociationRequest(BaseModel):
765
+ class PhoneVerificationAssociationRequest(BaseRequest):
760
766
  verification_id: str
@@ -0,0 +1 @@
1
+ __version__ = '2.1.17'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cuenca_validations
3
- Version: 2.1.16.dev100
3
+ Version: 2.1.17
4
4
  Summary: Cuenca common validations
5
5
  Home-page: https://github.com/cuenca-mx/cuenca-validations
6
6
  Author: Cuenca
@@ -0,0 +1,31 @@
1
+ import pytest
2
+ from pydantic import ValidationError
3
+
4
+ from cuenca_validations.types.requests import UserTOSAgreementRequest
5
+ from cuenca_validations.typing import DictStrAny
6
+
7
+
8
+ @pytest.mark.parametrize('environment', ['stage', 'sandbox', 'api'])
9
+ def test_file_cuenca_url(environment: str) -> None:
10
+ request_data: DictStrAny = dict(
11
+ tos_id='TS67dcae8e74e81bba5a77bf47',
12
+ location=(19.432607, -99.133209),
13
+ signature_image_url=(
14
+ f'https://{environment}.cuenca.com/files/EFQL8_ohvoRp-PkOTYgvQYFA'
15
+ ),
16
+ )
17
+ utos = UserTOSAgreementRequest(**request_data)
18
+ assert utos.signature_image_url is not None
19
+ assert utos.signature_image_url.file_id == 'EFQL8_ohvoRp-PkOTYgvQYFA'
20
+
21
+
22
+ def test_file_cuenca_url_invalid() -> None:
23
+ request_data: DictStrAny = dict(
24
+ tos_id='TS67dcae8e74e81bba5a77bf47',
25
+ location=(19.432607, -99.133209),
26
+ signature_image_url=(
27
+ 'https://cuenca.com/files/EFQL87ohvoRp-PkOTYgvQYFA/invalid'
28
+ ),
29
+ )
30
+ with pytest.raises(ValidationError):
31
+ UserTOSAgreementRequest(**request_data)
@@ -328,6 +328,23 @@ def test_user_request():
328
328
  assert UserRequest(**request).model_dump(exclude_none=True) == request
329
329
 
330
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)
346
+
347
+
331
348
  @freeze_time('2022-01-01')
332
349
  def test_user_request_underage():
333
350
  request = dict(
@@ -377,7 +394,9 @@ def test_curp_validation_request():
377
394
  assert all(field in error_msg for field in required_fields)
378
395
 
379
396
  req_curp = CurpValidationRequest(**request)
380
- assert req_curp.model_dump() == request
397
+ # exclude_none=False to test that the request equals the original dict,
398
+ # since normally exclude_none defaults to True in BaseRequest.model_dump()
399
+ assert req_curp.model_dump(exclude_none=False) == request
381
400
 
382
401
  request['date_of_birth'] = dt.date(2006, 5, 17)
383
402
 
@@ -418,15 +437,12 @@ def test_user_update_request():
418
437
  percentage=50,
419
438
  ),
420
439
  ],
421
- curp_document_uri='https://sandbox.cuenca.com/files/EF123',
440
+ profession=Profession.empleado,
422
441
  )
423
442
  update_req = UserUpdateRequest(**request)
424
443
  beneficiaries = [b.model_dump() for b in update_req.beneficiaries]
425
444
  assert beneficiaries == request['beneficiaries']
426
- assert (
427
- update_req.curp_document_uri.unicode_string()
428
- == request['curp_document_uri']
429
- )
445
+ assert update_req.profession == Profession.empleado
430
446
 
431
447
  request['beneficiaries'] = [
432
448
  dict(
@@ -461,26 +477,6 @@ def test_user_update_request():
461
477
  assert 'The total percentage should be 100%' in str(v)
462
478
  request.pop('beneficiaries')
463
479
 
464
- tos_request = dict(
465
- terms_of_service=dict(
466
- version='2022-01-01',
467
- ip='127.0.0.1',
468
- location='1111,1111',
469
- type='ifpe',
470
- )
471
- )
472
- UserUpdateRequest(**tos_request)
473
-
474
- tos_request = dict(
475
- terms_of_service=dict(
476
- version='2022-01-01',
477
- ip='2001:0db8:0000:0000:0000:ff00:0042:8329',
478
- location='1111,1111',
479
- type='ifpe',
480
- )
481
- )
482
- UserUpdateRequest(**tos_request)
483
-
484
480
  kyc_request = dict(
485
481
  govt_id=dict(
486
482
  type='ine',
@@ -490,6 +486,10 @@ def test_user_update_request():
490
486
  )
491
487
  UserUpdateRequest(**kyc_request)
492
488
 
489
+ request['profession'] = Profession.otro
490
+ with pytest.raises(ValidationError) as v:
491
+ UserUpdateRequest(**request)
492
+
493
493
 
494
494
  def test_session_request():
495
495
  data = dict(
@@ -1 +0,0 @@
1
- __version__ = '2.1.16.dev100'
@@ -1,70 +0,0 @@
1
- import pytest
2
- from pydantic import ValidationError
3
-
4
- from cuenca_validations.types.enums import SessionType
5
- from cuenca_validations.types.requests import (
6
- SessionRequest,
7
- UserTOSAgreementRequest,
8
- )
9
- from cuenca_validations.typing import DictStrAny
10
-
11
-
12
- @pytest.mark.parametrize('environment', ['stage', 'sandbox', 'api'])
13
- def test_file_cuenca_url(environment: str) -> None:
14
- request_data: DictStrAny = dict(
15
- tos_id='TS67dcae8e74e81bba5a77bf47',
16
- location=(19.432607, -99.133209),
17
- signature_image_url=(
18
- f'https://{environment}.cuenca.com/files/EFQL8_ohvoRp-PkOTYgvQYFA'
19
- ),
20
- )
21
- utos = UserTOSAgreementRequest(**request_data)
22
- assert utos.signature_image_url is not None
23
- assert utos.signature_image_url.file_id == 'EFQL8_ohvoRp-PkOTYgvQYFA'
24
-
25
-
26
- def test_file_cuenca_url_invalid() -> None:
27
- request_data: DictStrAny = dict(
28
- tos_id='TS67dcae8e74e81bba5a77bf47',
29
- location=(19.432607, -99.133209),
30
- signature_image_url=(
31
- 'https://cuenca.com/files/EFQL87ohvoRp-PkOTYgvQYFA/invalid'
32
- ),
33
- )
34
- with pytest.raises(ValidationError):
35
- UserTOSAgreementRequest(**request_data)
36
-
37
-
38
- def test_session_request_without_metadata():
39
- request_data = {
40
- 'user_id': 'USWqY5cvkISJOxHyEKjAKf8w',
41
- 'type': 'session.curp_validation',
42
- }
43
- request = SessionRequest(**request_data)
44
- assert request.type == SessionType.curp_validation
45
- assert request.user_id == 'USWqY5cvkISJOxHyEKjAKf8w'
46
-
47
-
48
- def test_session_request_with_metadata():
49
- request_data = {
50
- 'user_id': 'USWqY5cvkISJOxHyEKjAKf8w',
51
- 'type': 'session.metamap_verification',
52
- 'metadata': {'verification_id': 'some_verification'},
53
- }
54
- request = SessionRequest(**request_data)
55
- assert request.type == SessionType.metamap_verification
56
- assert request.user_id == 'USWqY5cvkISJOxHyEKjAKf8w'
57
- assert request.metadata
58
- assert request.metadata['verification_id'] == 'some_verification'
59
-
60
-
61
- def test_metamap_session_request_without_metadata():
62
- request_data = {
63
- 'user_id': 'USWqY5cvkISJOxHyEKjAKf8w',
64
- 'type': 'session.metamap_verification',
65
- }
66
-
67
- with pytest.raises(ValidationError) as exception:
68
- SessionRequest(**request_data)
69
-
70
- assert 'Metadata expected for this session' in str(exception)