cuenca-validations 2.1.40.dev1__tar.gz → 2.1.41.dev1__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 (37) hide show
  1. {cuenca_validations-2.1.40.dev1 → cuenca_validations-2.1.41.dev1}/PKG-INFO +1 -1
  2. {cuenca_validations-2.1.40.dev1 → cuenca_validations-2.1.41.dev1}/cuenca_validations/types/__init__.py +26 -0
  3. {cuenca_validations-2.1.40.dev1 → cuenca_validations-2.1.41.dev1}/cuenca_validations/types/enums.py +22 -0
  4. {cuenca_validations-2.1.40.dev1 → cuenca_validations-2.1.41.dev1}/cuenca_validations/types/queries.py +6 -0
  5. {cuenca_validations-2.1.40.dev1 → cuenca_validations-2.1.41.dev1}/cuenca_validations/types/requests.py +161 -0
  6. cuenca_validations-2.1.41.dev1/cuenca_validations/version.py +1 -0
  7. {cuenca_validations-2.1.40.dev1 → cuenca_validations-2.1.41.dev1}/cuenca_validations.egg-info/PKG-INFO +1 -1
  8. cuenca_validations-2.1.41.dev1/tests/test_requests.py +279 -0
  9. cuenca_validations-2.1.40.dev1/cuenca_validations/version.py +0 -1
  10. cuenca_validations-2.1.40.dev1/tests/test_requests.py +0 -130
  11. {cuenca_validations-2.1.40.dev1 → cuenca_validations-2.1.41.dev1}/LICENSE +0 -0
  12. {cuenca_validations-2.1.40.dev1 → cuenca_validations-2.1.41.dev1}/README.md +0 -0
  13. {cuenca_validations-2.1.40.dev1 → cuenca_validations-2.1.41.dev1}/cuenca_validations/__init__.py +0 -0
  14. {cuenca_validations-2.1.40.dev1 → cuenca_validations-2.1.41.dev1}/cuenca_validations/card_bins.py +0 -0
  15. {cuenca_validations-2.1.40.dev1 → cuenca_validations-2.1.41.dev1}/cuenca_validations/errors.py +0 -0
  16. {cuenca_validations-2.1.40.dev1 → cuenca_validations-2.1.41.dev1}/cuenca_validations/py.typed +0 -0
  17. {cuenca_validations-2.1.40.dev1 → cuenca_validations-2.1.41.dev1}/cuenca_validations/types/card.py +0 -0
  18. {cuenca_validations-2.1.40.dev1 → cuenca_validations-2.1.41.dev1}/cuenca_validations/types/files.py +0 -0
  19. {cuenca_validations-2.1.40.dev1 → cuenca_validations-2.1.41.dev1}/cuenca_validations/types/general.py +0 -0
  20. {cuenca_validations-2.1.40.dev1 → cuenca_validations-2.1.41.dev1}/cuenca_validations/types/helpers.py +0 -0
  21. {cuenca_validations-2.1.40.dev1 → cuenca_validations-2.1.41.dev1}/cuenca_validations/types/identities.py +0 -0
  22. {cuenca_validations-2.1.40.dev1 → cuenca_validations-2.1.41.dev1}/cuenca_validations/types/morals.py +0 -0
  23. {cuenca_validations-2.1.40.dev1 → cuenca_validations-2.1.41.dev1}/cuenca_validations/typing.py +0 -0
  24. {cuenca_validations-2.1.40.dev1 → cuenca_validations-2.1.41.dev1}/cuenca_validations/validators.py +0 -0
  25. {cuenca_validations-2.1.40.dev1 → cuenca_validations-2.1.41.dev1}/cuenca_validations.egg-info/SOURCES.txt +0 -0
  26. {cuenca_validations-2.1.40.dev1 → cuenca_validations-2.1.41.dev1}/cuenca_validations.egg-info/dependency_links.txt +0 -0
  27. {cuenca_validations-2.1.40.dev1 → cuenca_validations-2.1.41.dev1}/cuenca_validations.egg-info/requires.txt +0 -0
  28. {cuenca_validations-2.1.40.dev1 → cuenca_validations-2.1.41.dev1}/cuenca_validations.egg-info/top_level.txt +0 -0
  29. {cuenca_validations-2.1.40.dev1 → cuenca_validations-2.1.41.dev1}/setup.cfg +0 -0
  30. {cuenca_validations-2.1.40.dev1 → cuenca_validations-2.1.41.dev1}/setup.py +0 -0
  31. {cuenca_validations-2.1.40.dev1 → cuenca_validations-2.1.41.dev1}/tests/__init__.py +0 -0
  32. {cuenca_validations-2.1.40.dev1 → cuenca_validations-2.1.41.dev1}/tests/test_card.py +0 -0
  33. {cuenca_validations-2.1.40.dev1 → cuenca_validations-2.1.41.dev1}/tests/test_errors.py +0 -0
  34. {cuenca_validations-2.1.40.dev1 → cuenca_validations-2.1.41.dev1}/tests/test_helpers.py +0 -0
  35. {cuenca_validations-2.1.40.dev1 → cuenca_validations-2.1.41.dev1}/tests/test_statement.py +0 -0
  36. {cuenca_validations-2.1.40.dev1 → cuenca_validations-2.1.41.dev1}/tests/test_types.py +0 -0
  37. {cuenca_validations-2.1.40.dev1 → cuenca_validations-2.1.41.dev1}/tests/test_validators.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cuenca_validations
3
- Version: 2.1.40.dev1
3
+ Version: 2.1.41.dev1
4
4
  Summary: Cuenca common validations
5
5
  Home-page: https://github.com/cuenca-mx/cuenca-validations
6
6
  Author: Cuenca
@@ -1,6 +1,9 @@
1
1
  __all__ = [
2
2
  'AccountUseType',
3
3
  'AccountQuery',
4
+ 'AccountRequest',
5
+ 'AccountUpdateRequest',
6
+ 'AccountValidationStatus',
4
7
  'Address',
5
8
  'AgentQuery',
6
9
  'AgentRequest',
@@ -60,6 +63,16 @@ __all__ = [
60
63
  'LimitedWalletRequest',
61
64
  'MonthlyMovementsType',
62
65
  'MonthlySpendingType',
66
+ 'MoralPersonRequest',
67
+ 'MoralPersonUpdateRequest',
68
+ 'OperationalEventAction',
69
+ 'OperationalEventQuery',
70
+ 'OperatorLoginRequest',
71
+ 'OperatorLoginResponse',
72
+ 'OperatorRequest',
73
+ 'OperatorRole',
74
+ 'OperatorStatus',
75
+ 'OperatorUpdateRequest',
63
76
  'PartnerRequest',
64
77
  'PartnerUpdateRequest',
65
78
  'PasswordResetRequest',
@@ -129,6 +142,7 @@ __all__ = [
129
142
  from .card import StrictPaymentCardNumber
130
143
  from .enums import (
131
144
  AccountUseType,
145
+ AccountValidationStatus,
132
146
  AuthorizerTransaction,
133
147
  BankAccountStatus,
134
148
  CardErrorType,
@@ -155,6 +169,9 @@ from .enums import (
155
169
  Language,
156
170
  MonthlyMovementsType,
157
171
  MonthlySpendingType,
172
+ OperationalEventAction,
173
+ OperatorRole,
174
+ OperatorStatus,
158
175
  PlatformType,
159
176
  PosCapability,
160
177
  Profession,
@@ -213,6 +230,7 @@ from .queries import (
213
230
  EventQuery,
214
231
  FileQuery,
215
232
  IdentityQuery,
233
+ OperationalEventQuery,
216
234
  PostalCodeQuery,
217
235
  QueryParams,
218
236
  SessionQuery,
@@ -226,6 +244,8 @@ from .queries import (
226
244
  WalletTransactionQuery,
227
245
  )
228
246
  from .requests import (
247
+ AccountRequest,
248
+ AccountUpdateRequest,
229
249
  AgentRequest,
230
250
  ApiKeyUpdateRequest,
231
251
  BankAccountValidationRequest,
@@ -239,6 +259,12 @@ from .requests import (
239
259
  FraudFundsTransferRequest,
240
260
  KYCValidationRequest,
241
261
  LimitedWalletRequest,
262
+ MoralPersonRequest,
263
+ MoralPersonUpdateRequest,
264
+ OperatorLoginRequest,
265
+ OperatorLoginResponse,
266
+ OperatorRequest,
267
+ OperatorUpdateRequest,
242
268
  PartnerRequest,
243
269
  PartnerUpdateRequest,
244
270
  PasswordResetRequest,
@@ -744,3 +744,25 @@ class RequiredAction(str, Enum):
744
744
  level_up_required = 'level_up_required'
745
745
  level_up_invitation = 'level_up_invitation'
746
746
  fix_documents = 'fix_documents'
747
+
748
+
749
+ class AccountValidationStatus(str, Enum):
750
+ verified = 'verified'
751
+ pending = 'pending'
752
+
753
+
754
+ class OperationalEventAction(str, Enum):
755
+ account_created = 'account_created'
756
+ account_updated = 'account_updated'
757
+ transfer_created = 'transfer_created'
758
+ statement_downloaded = 'statement_downloaded'
759
+
760
+
761
+ class OperatorRole(str, Enum):
762
+ operator = 'operator'
763
+ authorizer = 'authorizer'
764
+
765
+
766
+ class OperatorStatus(str, Enum):
767
+ active = 'active'
768
+ disabled = 'disabled'
@@ -22,6 +22,7 @@ from .enums import (
22
22
  CardType,
23
23
  EventType,
24
24
  KYCFileType,
25
+ OperationalEventAction,
25
26
  SessionType,
26
27
  TermsOfService,
27
28
  TransferNetwork,
@@ -153,6 +154,11 @@ class AccountQuery(QueryParams):
153
154
  account_number: Optional[str] = None
154
155
 
155
156
 
157
+ class OperationalEventQuery(QueryParams):
158
+ actor_id: Optional[str] = None
159
+ action: Optional[OperationalEventAction] = None
160
+
161
+
156
162
  class BalanceEntryQuery(QueryParams):
157
163
  funding_instrument_uri: Optional[str] = None
158
164
  wallet_id: str = 'default'
@@ -18,6 +18,7 @@ from pydantic_extra_types.coordinate import Coordinate
18
18
 
19
19
  from ..types.enums import (
20
20
  AccountUseType,
21
+ AccountValidationStatus,
21
22
  AuthorizerTransaction,
22
23
  CardDesign,
23
24
  CardFundingType,
@@ -36,6 +37,8 @@ from ..types.enums import (
36
37
  KYCValidationSource,
37
38
  MonthlyMovementsType,
38
39
  MonthlySpendingType,
40
+ OperatorRole,
41
+ OperatorStatus,
39
42
  PlatformType,
40
43
  PosCapability,
41
44
  Profession,
@@ -735,6 +738,39 @@ class LimitedWalletRequest(BaseRequest):
735
738
  allowed_rfc: Optional[Rfc] = None
736
739
 
737
740
 
741
+ class AccountRequest(BaseRequest):
742
+ name: StrictStr
743
+ account_number: Clabe
744
+ alias: Optional[StrictStr] = None
745
+ curp: Optional[Curp] = None
746
+ rfc: Optional[Rfc] = None
747
+
748
+ model_config = ConfigDict(
749
+ json_schema_extra={
750
+ 'example': {
751
+ 'name': 'Aceros del Norte SA de CV',
752
+ 'account_number': '072691004495711499',
753
+ 'alias': 'Proveedor acero',
754
+ }
755
+ },
756
+ )
757
+
758
+
759
+ class AccountUpdateRequest(BaseRequest):
760
+ name: Optional[StrictStr] = None
761
+ alias: Optional[StrictStr] = None
762
+ validation_status: Optional[AccountValidationStatus] = None
763
+
764
+ model_config = ConfigDict(
765
+ json_schema_extra={
766
+ 'example': {
767
+ 'alias': 'Fletes',
768
+ 'validation_status': 'verified',
769
+ }
770
+ },
771
+ )
772
+
773
+
738
774
  class PlatformRequest(BaseModel):
739
775
  name: str
740
776
  rfc: Optional[str] = None
@@ -863,5 +899,130 @@ class PartnerUpdateRequest(BaseRequest):
863
899
  shareholders: Optional[list[Shareholder]] = None
864
900
 
865
901
 
902
+ class MoralPersonRequest(BaseRequest):
903
+ legal_name: str
904
+ rfc: Rfc
905
+ legal_representatives: list[LegalRepresentative]
906
+
907
+ model_config = ConfigDict(
908
+ json_schema_extra={
909
+ 'example': {
910
+ 'legal_name': 'Aceros del Norte SA de CV',
911
+ 'rfc': 'ADN850101ABC',
912
+ 'legal_representatives': [
913
+ {
914
+ 'names': 'Juan',
915
+ 'first_surname': 'Perez',
916
+ 'job': 'Director General',
917
+ 'phone_number': '+525512345678',
918
+ 'email_address': 'juan.perez@aceros.com',
919
+ 'address': AddressRequest.model_json_schema().get(
920
+ 'example'
921
+ ),
922
+ }
923
+ ],
924
+ }
925
+ },
926
+ )
927
+
928
+ @field_validator('rfc')
929
+ @classmethod
930
+ def validate_moral_rfc(cls, rfc: Rfc) -> Rfc:
931
+ if len(rfc) != 12:
932
+ raise ValueError('RFC must be 12 characters for moral persons')
933
+ return rfc
934
+
935
+
936
+ class MoralPersonUpdateRequest(BaseRequest):
937
+ legal_name: Optional[str] = None
938
+ rfc: Optional[Rfc] = None
939
+ legal_representatives: Optional[list[LegalRepresentative]] = None
940
+
941
+ @model_validator(mode="before")
942
+ @classmethod
943
+ def check_at_least_one_param(cls, values: DictStrAny) -> DictStrAny:
944
+ if not values:
945
+ raise ValueError('At least one parameter must be provided')
946
+ return values
947
+
948
+ @field_validator('rfc')
949
+ @classmethod
950
+ def validate_moral_rfc(cls, rfc: Optional[Rfc]) -> Optional[Rfc]:
951
+ if rfc is not None and len(rfc) != 12:
952
+ raise ValueError('RFC must be 12 characters for moral persons')
953
+ return rfc
954
+
955
+
956
+ class OperatorRequest(BaseRequest):
957
+ name: str
958
+ email: EmailStr
959
+ phone: PhoneNumber
960
+ company_user_id: str
961
+ role: OperatorRole
962
+ status: OperatorStatus = OperatorStatus.active
963
+
964
+ model_config = ConfigDict(
965
+ json_schema_extra={
966
+ 'example': {
967
+ 'name': 'Maria Lopez',
968
+ 'email': 'maria.lopez@aceros.com',
969
+ 'phone': '+525512345678',
970
+ 'company_user_id': 'USWqY5cvkISJOxHyEKjAKf8w',
971
+ 'role': 'operator',
972
+ }
973
+ },
974
+ )
975
+
976
+ @field_validator('email', mode='before')
977
+ @classmethod
978
+ def validate_email(cls, email: str) -> str:
979
+ return normalize_email(email)
980
+
981
+
982
+ class OperatorUpdateRequest(BaseRequest):
983
+ name: Optional[str] = None
984
+ phone: Optional[PhoneNumber] = None
985
+ role: Optional[OperatorRole] = None
986
+ status: Optional[OperatorStatus] = None
987
+
988
+ @model_validator(mode="before")
989
+ @classmethod
990
+ def check_at_least_one_param(cls, values: DictStrAny) -> DictStrAny:
991
+ if not values:
992
+ raise ValueError('At least one parameter must be provided')
993
+ return values
994
+
995
+
996
+ class OperatorLoginRequest(BaseRequest):
997
+ email: EmailStr
998
+ password: Annotated[Password, LogConfig(masked=True)]
999
+
1000
+ model_config = ConfigDict(
1001
+ json_schema_extra={
1002
+ 'example': {
1003
+ 'email': 'maria.lopez@aceros.com',
1004
+ 'password': 'supersecret',
1005
+ }
1006
+ },
1007
+ )
1008
+
1009
+ @field_validator('email', mode='before')
1010
+ @classmethod
1011
+ def validate_email(cls, email: str) -> str:
1012
+ return normalize_email(email)
1013
+
1014
+
1015
+ class OperatorLoginResponse(BaseModel):
1016
+ session_token: str
1017
+
1018
+ model_config = ConfigDict(
1019
+ json_schema_extra={
1020
+ 'example': {
1021
+ 'session_token': 'SEWqY5cvkISJOxHyEKjAKf8w',
1022
+ }
1023
+ },
1024
+ )
1025
+
1026
+
866
1027
  class PhoneVerificationAssociationRequest(BaseRequest):
867
1028
  verification_id: str
@@ -0,0 +1 @@
1
+ __version__ = '2.1.41.dev1'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cuenca_validations
3
- Version: 2.1.40.dev1
3
+ Version: 2.1.41.dev1
4
4
  Summary: Cuenca common validations
5
5
  Home-page: https://github.com/cuenca-mx/cuenca-validations
6
6
  Author: Cuenca
@@ -0,0 +1,279 @@
1
+ import pytest
2
+ from pydantic import ValidationError
3
+ from pydantic_extra_types.phone_numbers import PhoneNumber
4
+
5
+ from cuenca_validations.types.enums import (
6
+ Country,
7
+ OperatorRole,
8
+ OperatorStatus,
9
+ VerificationType,
10
+ )
11
+ from cuenca_validations.types.requests import (
12
+ MoralPersonRequest,
13
+ MoralPersonUpdateRequest,
14
+ OperatorLoginRequest,
15
+ OperatorLoginResponse,
16
+ OperatorRequest,
17
+ OperatorUpdateRequest,
18
+ PasswordResetRequest,
19
+ UpdateTransferRequest,
20
+ UserTOSAgreementRequest,
21
+ UserUpdateRequest,
22
+ VerificationRequest,
23
+ )
24
+ from cuenca_validations.typing import DictStrAny
25
+
26
+ LEGAL_REPRESENTATIVE: DictStrAny = {
27
+ 'names': 'Juan',
28
+ 'first_surname': 'Perez',
29
+ 'job': 'Director General',
30
+ 'phone_number': '+525512345678',
31
+ 'email_address': 'juan.perez@aceros.com',
32
+ 'address': {
33
+ 'street': 'Reforma',
34
+ 'ext_number': '265',
35
+ 'postal_code_id': 'PC2ygq9j2bS9-9tsuVawzErA',
36
+ },
37
+ }
38
+
39
+ MORAL_PERSON_REQUEST: DictStrAny = {
40
+ 'legal_name': 'Aceros del Norte SA de CV',
41
+ 'rfc': 'ADN850101ABC',
42
+ 'legal_representatives': [LEGAL_REPRESENTATIVE],
43
+ }
44
+
45
+
46
+ def test_moral_person_request_valid() -> None:
47
+ req = MoralPersonRequest.model_validate(MORAL_PERSON_REQUEST)
48
+ assert req.legal_name == 'Aceros del Norte SA de CV'
49
+ assert req.rfc == 'ADN850101ABC'
50
+
51
+
52
+ def test_moral_person_request_rejects_physical_rfc() -> None:
53
+ with pytest.raises(ValidationError) as ex:
54
+ MoralPersonRequest.model_validate(
55
+ {**MORAL_PERSON_REQUEST, 'rfc': 'GOCG650418TJ1'}
56
+ )
57
+ assert 'RFC must be 12 characters for moral persons' in str(ex.value)
58
+
59
+
60
+ def test_moral_person_request_forbids_extra() -> None:
61
+ with pytest.raises(ValidationError) as ex:
62
+ MoralPersonRequest.model_validate(
63
+ {**MORAL_PERSON_REQUEST, 'foo': 'bar'}
64
+ )
65
+ assert 'Extra inputs are not permitted' in str(ex.value)
66
+
67
+
68
+ def test_moral_person_update_requires_at_least_one_param() -> None:
69
+ with pytest.raises(ValueError) as ex:
70
+ MoralPersonUpdateRequest()
71
+ assert 'At least one parameter must be provided' in str(ex.value)
72
+
73
+
74
+ def test_moral_person_update_valid() -> None:
75
+ req = MoralPersonUpdateRequest.model_validate({'legal_name': 'New name'})
76
+ assert req.legal_name == 'New name'
77
+
78
+
79
+ def test_moral_person_update_accepts_moral_rfc() -> None:
80
+ req = MoralPersonUpdateRequest.model_validate({'rfc': 'ADN850101ABC'})
81
+ assert req.rfc == 'ADN850101ABC'
82
+
83
+
84
+ def test_moral_person_update_rejects_physical_rfc() -> None:
85
+ with pytest.raises(ValidationError) as ex:
86
+ MoralPersonUpdateRequest.model_validate({'rfc': 'GOCG650418TJ1'})
87
+ assert 'RFC must be 12 characters for moral persons' in str(ex.value)
88
+
89
+
90
+ def test_operator_request_valid() -> None:
91
+ req = OperatorRequest(
92
+ name='Maria Lopez',
93
+ email='Maria+Tag@Aceros.com',
94
+ phone=PhoneNumber('+525512345678'),
95
+ company_user_id='USWqY5cvkISJOxHyEKjAKf8w',
96
+ role=OperatorRole.operator,
97
+ )
98
+ assert req.email == 'maria@aceros.com'
99
+ assert req.status == OperatorStatus.active
100
+
101
+
102
+ def test_operator_request_rejects_invalid_role() -> None:
103
+ with pytest.raises(ValidationError) as ex:
104
+ OperatorRequest.model_validate(
105
+ {
106
+ 'name': 'Maria Lopez',
107
+ 'email': 'maria@aceros.com',
108
+ 'phone': '+525512345678',
109
+ 'company_user_id': 'USWqY5cvkISJOxHyEKjAKf8w',
110
+ 'role': 'admin',
111
+ }
112
+ )
113
+ assert 'role' in str(ex.value)
114
+
115
+
116
+ def test_operator_update_requires_at_least_one_param() -> None:
117
+ with pytest.raises(ValueError) as ex:
118
+ OperatorUpdateRequest()
119
+ assert 'At least one parameter must be provided' in str(ex.value)
120
+
121
+
122
+ def test_operator_update_valid() -> None:
123
+ req = OperatorUpdateRequest.model_validate({'name': 'New name'})
124
+ assert req.name == 'New name'
125
+
126
+
127
+ def test_operator_login_request_valid() -> None:
128
+ req = OperatorLoginRequest.model_validate(
129
+ {
130
+ 'email': 'Operator+Tag@Aceros.com',
131
+ 'password': 'supersecret',
132
+ }
133
+ )
134
+ assert req.email == 'operator@aceros.com'
135
+
136
+
137
+ def test_operator_login_request_rejects_short_password() -> None:
138
+ with pytest.raises(ValidationError) as ex:
139
+ OperatorLoginRequest.model_validate(
140
+ {
141
+ 'email': 'operator@aceros.com',
142
+ 'password': 'short',
143
+ }
144
+ )
145
+ assert 'password' in str(ex.value)
146
+
147
+
148
+ def test_operator_login_request_forbids_extra() -> None:
149
+ with pytest.raises(ValidationError) as ex:
150
+ OperatorLoginRequest.model_validate(
151
+ {
152
+ 'email': 'operator@aceros.com',
153
+ 'password': 'supersecret',
154
+ 'foo': 'bar',
155
+ }
156
+ )
157
+ assert 'Extra inputs are not permitted' in str(ex.value)
158
+
159
+
160
+ def test_operator_login_response_valid() -> None:
161
+ resp = OperatorLoginResponse(session_token='SEWqY5cvkISJOxHyEKjAKf8w')
162
+ assert resp.session_token == 'SEWqY5cvkISJOxHyEKjAKf8w'
163
+
164
+
165
+ @pytest.mark.parametrize('environment', ['api.stage', 'api.sandbox', 'api'])
166
+ def test_file_cuenca_url(environment: str) -> None:
167
+ request_data: DictStrAny = dict(
168
+ tos_id='TS67dcae8e74e81bba5a77bf47',
169
+ location=(19.432607, -99.133209),
170
+ signature_image_url=(
171
+ f'https://{environment}.cuenca.com/files/EFQL8_ohvoRp-PkOTYgvQYFA'
172
+ ),
173
+ )
174
+ utos = UserTOSAgreementRequest(**request_data)
175
+ assert utos.signature_image_url is not None
176
+ assert utos.signature_image_url.file_id == 'EFQL8_ohvoRp-PkOTYgvQYFA'
177
+
178
+
179
+ def test_file_cuenca_url_invalid() -> None:
180
+ request_data: DictStrAny = dict(
181
+ tos_id='TS67dcae8e74e81bba5a77bf47',
182
+ location=(19.432607, -99.133209),
183
+ signature_image_url=(
184
+ 'https://cuenca.com/files/EFQL87ohvoRp-PkOTYgvQYFA/invalid'
185
+ ),
186
+ )
187
+ with pytest.raises(ValidationError):
188
+ UserTOSAgreementRequest(**request_data)
189
+
190
+
191
+ def test_password_reset_request_serializes() -> None:
192
+ payload: DictStrAny = {'location': (19.432607, -99.133209)}
193
+ req = PasswordResetRequest.model_validate(payload)
194
+ assert req.model_dump() == {
195
+ 'location': {
196
+ 'latitude': 19.432607,
197
+ 'longitude': -99.133209,
198
+ },
199
+ }
200
+
201
+
202
+ def test_update_user_requires_at_least_one_param():
203
+ with pytest.raises(ValueError) as ex:
204
+ UserUpdateRequest()
205
+ assert 'At least one parameter must be provided' in str(ex.value)
206
+
207
+
208
+ def test_extra_params_are_not_allowed():
209
+ with pytest.raises(ValueError) as ex:
210
+ UserUpdateRequest(foo='bar')
211
+ assert 'Extra inputs are not permitted' in str(ex.value)
212
+
213
+
214
+ def test_update_user_update_govt() -> None:
215
+ govt_id: DictStrAny = {
216
+ "govt_id": {"type": "ine", "uri_front": "files/123"}
217
+ }
218
+ with pytest.raises(ValueError) as ex:
219
+ UserUpdateRequest(**govt_id)
220
+ assert 'uri_back must be provided for type ine' in str(ex.value)
221
+
222
+
223
+ def test_verification_request_normalizes_email() -> None:
224
+ req = VerificationRequest(
225
+ recipient='user+cuenca@Gmail.com',
226
+ type=VerificationType.email,
227
+ )
228
+ assert req.recipient == 'user@gmail.com'
229
+
230
+
231
+ def test_verification_request_normalizes_phone() -> None:
232
+ req = VerificationRequest(
233
+ recipient='+116504401222',
234
+ type=VerificationType.phone,
235
+ )
236
+ assert req.recipient == '+16504401222'
237
+
238
+
239
+ def test_user_update_request_normalizes_email() -> None:
240
+ req = UserUpdateRequest(email_address='user+tag@Gmail.com')
241
+ assert req.email_address == 'user@gmail.com'
242
+
243
+
244
+ def test_user_update_request_normalizes_phone() -> None:
245
+ req = UserUpdateRequest(phone_number=PhoneNumber('+116504401222'))
246
+ assert req.phone_number == '+16504401222'
247
+
248
+
249
+ def test_user_update_request_accepts_country_of_birth() -> None:
250
+ req = UserUpdateRequest(country_of_birth=Country.CA)
251
+ assert req.country_of_birth == Country.CA
252
+
253
+
254
+ @pytest.mark.parametrize('status', ['succeeded', 'failed'])
255
+ def test_update_transfer_request_valid_status(status: str) -> None:
256
+ req = UpdateTransferRequest.model_validate({'status': status})
257
+ assert req.status == status
258
+ assert req.model_dump() == {'status': status}
259
+
260
+
261
+ @pytest.mark.parametrize('status', ['created', 'submitted', 'in_review'])
262
+ def test_update_transfer_request_invalid_status(status: str) -> None:
263
+ with pytest.raises(ValidationError) as ex:
264
+ UpdateTransferRequest.model_validate({'status': status})
265
+ assert 'status' in str(ex.value)
266
+
267
+
268
+ def test_update_transfer_request_missing_status() -> None:
269
+ with pytest.raises(ValidationError) as ex:
270
+ UpdateTransferRequest.model_validate({})
271
+ assert 'status' in str(ex.value)
272
+
273
+
274
+ def test_update_transfer_request_forbids_extra() -> None:
275
+ with pytest.raises(ValidationError) as ex:
276
+ UpdateTransferRequest.model_validate(
277
+ {'status': 'succeeded', 'foo': 'bar'}
278
+ )
279
+ assert 'Extra inputs are not permitted' in str(ex.value)
@@ -1 +0,0 @@
1
- __version__ = '2.1.40.dev1'
@@ -1,130 +0,0 @@
1
- import pytest
2
- from pydantic import ValidationError
3
- from pydantic_extra_types.phone_numbers import PhoneNumber
4
-
5
- from cuenca_validations.types.enums import Country, VerificationType
6
- from cuenca_validations.types.requests import (
7
- PasswordResetRequest,
8
- UpdateTransferRequest,
9
- UserTOSAgreementRequest,
10
- UserUpdateRequest,
11
- VerificationRequest,
12
- )
13
- from cuenca_validations.typing import DictStrAny
14
-
15
-
16
- @pytest.mark.parametrize('environment', ['api.stage', 'api.sandbox', 'api'])
17
- def test_file_cuenca_url(environment: str) -> None:
18
- request_data: DictStrAny = dict(
19
- tos_id='TS67dcae8e74e81bba5a77bf47',
20
- location=(19.432607, -99.133209),
21
- signature_image_url=(
22
- f'https://{environment}.cuenca.com/files/EFQL8_ohvoRp-PkOTYgvQYFA'
23
- ),
24
- )
25
- utos = UserTOSAgreementRequest(**request_data)
26
- assert utos.signature_image_url is not None
27
- assert utos.signature_image_url.file_id == 'EFQL8_ohvoRp-PkOTYgvQYFA'
28
-
29
-
30
- def test_file_cuenca_url_invalid() -> None:
31
- request_data: DictStrAny = dict(
32
- tos_id='TS67dcae8e74e81bba5a77bf47',
33
- location=(19.432607, -99.133209),
34
- signature_image_url=(
35
- 'https://cuenca.com/files/EFQL87ohvoRp-PkOTYgvQYFA/invalid'
36
- ),
37
- )
38
- with pytest.raises(ValidationError):
39
- UserTOSAgreementRequest(**request_data)
40
-
41
-
42
- def test_password_reset_request_serializes() -> None:
43
- payload: DictStrAny = {'location': (19.432607, -99.133209)}
44
- req = PasswordResetRequest.model_validate(payload)
45
- assert req.model_dump() == {
46
- 'location': {
47
- 'latitude': 19.432607,
48
- 'longitude': -99.133209,
49
- },
50
- }
51
-
52
-
53
- def test_update_user_requires_at_least_one_param():
54
- with pytest.raises(ValueError) as ex:
55
- UserUpdateRequest()
56
- assert 'At least one parameter must be provided' in str(ex.value)
57
-
58
-
59
- def test_extra_params_are_not_allowed():
60
- with pytest.raises(ValueError) as ex:
61
- UserUpdateRequest(foo='bar')
62
- assert 'Extra inputs are not permitted' in str(ex.value)
63
-
64
-
65
- def test_update_user_update_govt() -> None:
66
- govt_id: DictStrAny = {
67
- "govt_id": {"type": "ine", "uri_front": "files/123"}
68
- }
69
- with pytest.raises(ValueError) as ex:
70
- UserUpdateRequest(**govt_id)
71
- assert 'uri_back must be provided for type ine' in str(ex.value)
72
-
73
-
74
- def test_verification_request_normalizes_email() -> None:
75
- req = VerificationRequest(
76
- recipient='user+cuenca@Gmail.com',
77
- type=VerificationType.email,
78
- )
79
- assert req.recipient == 'user@gmail.com'
80
-
81
-
82
- def test_verification_request_normalizes_phone() -> None:
83
- req = VerificationRequest(
84
- recipient='+116504401222',
85
- type=VerificationType.phone,
86
- )
87
- assert req.recipient == '+16504401222'
88
-
89
-
90
- def test_user_update_request_normalizes_email() -> None:
91
- req = UserUpdateRequest(email_address='user+tag@Gmail.com')
92
- assert req.email_address == 'user@gmail.com'
93
-
94
-
95
- def test_user_update_request_normalizes_phone() -> None:
96
- req = UserUpdateRequest(phone_number=PhoneNumber('+116504401222'))
97
- assert req.phone_number == '+16504401222'
98
-
99
-
100
- def test_user_update_request_accepts_country_of_birth() -> None:
101
- req = UserUpdateRequest(country_of_birth=Country.CA)
102
- assert req.country_of_birth == Country.CA
103
-
104
-
105
- @pytest.mark.parametrize('status', ['succeeded', 'failed'])
106
- def test_update_transfer_request_valid_status(status: str) -> None:
107
- req = UpdateTransferRequest.model_validate({'status': status})
108
- assert req.status == status
109
- assert req.model_dump() == {'status': status}
110
-
111
-
112
- @pytest.mark.parametrize('status', ['created', 'submitted', 'in_review'])
113
- def test_update_transfer_request_invalid_status(status: str) -> None:
114
- with pytest.raises(ValidationError) as ex:
115
- UpdateTransferRequest.model_validate({'status': status})
116
- assert 'status' in str(ex.value)
117
-
118
-
119
- def test_update_transfer_request_missing_status() -> None:
120
- with pytest.raises(ValidationError) as ex:
121
- UpdateTransferRequest.model_validate({})
122
- assert 'status' in str(ex.value)
123
-
124
-
125
- def test_update_transfer_request_forbids_extra() -> None:
126
- with pytest.raises(ValidationError) as ex:
127
- UpdateTransferRequest.model_validate(
128
- {'status': 'succeeded', 'foo': 'bar'}
129
- )
130
- assert 'Extra inputs are not permitted' in str(ex.value)