cuenca-validations 2.1.46__py3-none-any.whl → 2.1.48.dev0__py3-none-any.whl

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.
@@ -67,6 +67,7 @@ __all__ = [
67
67
  'LegalPersonRequest',
68
68
  'LegalPersonUpdateRequest',
69
69
  'OperatorLoginRequest',
70
+ 'OperatorLoginUpdateRequest',
70
71
  'OperatorQuery',
71
72
  'OperatorRequest',
72
73
  'OperatorRole',
@@ -82,6 +83,7 @@ __all__ = [
82
83
  'Profession',
83
84
  'QueryParams',
84
85
  'ReferencedClabeRequest',
86
+ 'RejectTransferOrderRequest',
85
87
  'LegalRfc',
86
88
  'Rfc',
87
89
  'QuestionnairesRequest',
@@ -106,6 +108,11 @@ __all__ = [
106
108
  'TransactionQuery',
107
109
  'TransactionStatus',
108
110
  'TransferNetwork',
111
+ 'TransferOrderLineRequest',
112
+ 'TransferOrderLineStatus',
113
+ 'TransferOrderQuery',
114
+ 'TransferOrderRequest',
115
+ 'TransferOrderStatus',
109
116
  'TransferQuery',
110
117
  'TransferRequest',
111
118
  'UpdateTransferRequest',
@@ -184,6 +191,8 @@ from .enums import (
184
191
  TrackDataMethod,
185
192
  TransactionStatus,
186
193
  TransferNetwork,
194
+ TransferOrderLineStatus,
195
+ TransferOrderStatus,
187
196
  UserCardNotification,
188
197
  UserStatus,
189
198
  UserType,
@@ -238,6 +247,7 @@ from .queries import (
238
247
  StatementQuery,
239
248
  TOSQuery,
240
249
  TransactionQuery,
250
+ TransferOrderQuery,
241
251
  TransferQuery,
242
252
  UserQuery,
243
253
  UsersTOSQuery,
@@ -263,6 +273,7 @@ from .requests import (
263
273
  LegalPersonUpdateRequest,
264
274
  LimitedWalletRequest,
265
275
  OperatorLoginRequest,
276
+ OperatorLoginUpdateRequest,
266
277
  OperatorRequest,
267
278
  OperatorUpdateRequest,
268
279
  PartnerRequest,
@@ -271,11 +282,14 @@ from .requests import (
271
282
  PlatformRequest,
272
283
  QuestionnairesRequest,
273
284
  ReferencedClabeRequest,
285
+ RejectTransferOrderRequest,
274
286
  SavingRequest,
275
287
  SavingUpdateRequest,
276
288
  SessionRequest,
277
289
  StrictTransferRequest,
278
290
  TOSRequest,
291
+ TransferOrderLineRequest,
292
+ TransferOrderRequest,
279
293
  TransferRequest,
280
294
  UpdateTransferRequest,
281
295
  UserCredentialRequest,
@@ -761,3 +761,17 @@ class OperatorRole(str, Enum):
761
761
  class OperatorStatus(str, Enum):
762
762
  active = 'active'
763
763
  deactivated = 'deactivated'
764
+
765
+
766
+ class TransferOrderStatus(str, Enum):
767
+ created = 'created'
768
+ authorizing = 'authorizing'
769
+ authorized = 'authorized'
770
+ rejected = 'rejected'
771
+ expired = 'expired'
772
+
773
+
774
+ class TransferOrderLineStatus(str, Enum):
775
+ pending = 'pending'
776
+ invalid = 'invalid'
777
+ submitted = 'submitted'
@@ -25,6 +25,7 @@ from .enums import (
25
25
  SessionType,
26
26
  TermsOfService,
27
27
  TransferNetwork,
28
+ TransferOrderStatus,
28
29
  UserStatus,
29
30
  )
30
31
  from .general import NormalizedName
@@ -233,3 +234,7 @@ class TOSQuery(QueryParams):
233
234
 
234
235
  class UsersTOSQuery(QueryParams):
235
236
  type: TermsOfService
237
+
238
+
239
+ class TransferOrderQuery(QueryParams):
240
+ status: Optional[TransferOrderStatus] = None
@@ -993,6 +993,16 @@ class OperatorLoginRequest(BaseRequest):
993
993
  return normalize_email(email)
994
994
 
995
995
 
996
+ class OperatorLoginUpdateRequest(BaseRequest):
997
+ """Complete operator login by verifying the emailed OTP code."""
998
+
999
+ code: StrictStr
1000
+
1001
+ model_config = ConfigDict(
1002
+ json_schema_extra={'example': {'code': '123456'}},
1003
+ )
1004
+
1005
+
996
1006
  class ReferencedClabeRequest(BaseRequest):
997
1007
  legal_person_id: str
998
1008
  allowed_curp_rfc: Union[Curp, Rfc]
@@ -1009,3 +1019,90 @@ class ReferencedClabeRequest(BaseRequest):
1009
1019
 
1010
1020
  class PhoneVerificationAssociationRequest(BaseRequest):
1011
1021
  verification_id: str
1022
+
1023
+
1024
+ MAX_TRANSFER_ORDER_BATCH_LINES = 5000
1025
+ MAX_TRANSFER_ORDER_EXPIRATION_HOURS = 24 * 7
1026
+
1027
+
1028
+ class TransferOrderLineRequest(BaseRequest):
1029
+ account_number: str
1030
+ recipient_name: str
1031
+ amount: int
1032
+ descriptor: str
1033
+
1034
+ model_config = ConfigDict(
1035
+ json_schema_extra={
1036
+ 'example': {
1037
+ 'account_number': '646180157034181180',
1038
+ 'recipient_name': 'Doroteo Arango',
1039
+ 'amount': 100_00,
1040
+ 'descriptor': 'Mezcal, pulque y tequila',
1041
+ }
1042
+ },
1043
+ )
1044
+
1045
+
1046
+ class TransferOrderRequest(BaseRequest):
1047
+ account_number: Optional[str] = None
1048
+ recipient_name: Optional[str] = None
1049
+ amount: Optional[int] = None
1050
+ descriptor: Optional[str] = None
1051
+ idempotency_key: str
1052
+ user_id: Optional[str] = None
1053
+ items: Optional[list[TransferOrderLineRequest]] = None
1054
+ expires_in_hours: Optional[int] = Field(
1055
+ default=None,
1056
+ gt=0,
1057
+ le=MAX_TRANSFER_ORDER_EXPIRATION_HOURS,
1058
+ )
1059
+
1060
+ model_config = ConfigDict(
1061
+ json_schema_extra={
1062
+ 'example': {
1063
+ 'account_number': '646180157034181180',
1064
+ 'recipient_name': 'Doroteo Arango',
1065
+ 'amount': 100_00,
1066
+ 'descriptor': 'Mezcal, pulque y tequila',
1067
+ 'idempotency_key': 'UNIQUE-KEY-003',
1068
+ 'user_id': 'USWqY5cvkISJOxHyEKjAKf8w',
1069
+ }
1070
+ },
1071
+ )
1072
+
1073
+ @model_validator(mode='after')
1074
+ def require_unitario_or_batch(self) -> 'TransferOrderRequest':
1075
+ has_items = bool(self.items)
1076
+ has_flat = all(
1077
+ (
1078
+ self.account_number is not None,
1079
+ self.recipient_name is not None,
1080
+ self.amount is not None,
1081
+ self.descriptor is not None,
1082
+ )
1083
+ )
1084
+ if has_items == has_flat:
1085
+ raise ValueError(
1086
+ 'Provide either a single transfer (account_number, '
1087
+ 'recipient_name, amount, descriptor) or items[] for a batch, '
1088
+ 'not both'
1089
+ )
1090
+ if self.items is not None:
1091
+ if len(self.items) > MAX_TRANSFER_ORDER_BATCH_LINES:
1092
+ raise ValueError(
1093
+ 'Batch exceeds maximum of '
1094
+ f'{MAX_TRANSFER_ORDER_BATCH_LINES} lines'
1095
+ )
1096
+ if len(self.items) == 0:
1097
+ raise ValueError('items must not be empty')
1098
+ return self
1099
+
1100
+
1101
+ class RejectTransferOrderRequest(BaseRequest):
1102
+ rejection_reason: str
1103
+
1104
+ model_config = ConfigDict(
1105
+ json_schema_extra={
1106
+ 'example': {'rejection_reason': 'Monto incorrecto'},
1107
+ },
1108
+ )
@@ -1 +1 @@
1
- __version__ = '2.1.46'
1
+ __version__ = '2.1.48.dev0'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cuenca_validations
3
- Version: 2.1.46
3
+ Version: 2.1.48.dev0
4
4
  Summary: Cuenca common validations
5
5
  Home-page: https://github.com/cuenca-mx/cuenca-validations
6
6
  Author: Cuenca
@@ -4,27 +4,27 @@ cuenca_validations/errors.py,sha256=OtM8EgiKqYdz9Hn66AbBO96orL1or7efkyt0vh0Zxbs,
4
4
  cuenca_validations/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  cuenca_validations/typing.py,sha256=1QCu81IbVZZpyInjyeAuO-nF36gpT5Gi4o6V9PozuOU,204
6
6
  cuenca_validations/validators.py,sha256=zXSnU5-EMbQZBD-PfFXgP4Z6G7cm7KFDWXB7Nie6WUk,2682
7
- cuenca_validations/version.py,sha256=qrVkFn9wN3ixgGNyDIl37hQmWG1KAb99ogbPdgnvZUc,23
8
- cuenca_validations/types/__init__.py,sha256=VmGxElYrSqQAb1jGT90s4b_63km_iFuEryQDJ-47y5M,6361
7
+ cuenca_validations/version.py,sha256=sASQTkqyEonq314x5AyyyiBSthTdrHeFL3tD1aNL-yI,28
8
+ cuenca_validations/types/__init__.py,sha256=-xNuGHXmkzEcWsBK6Y48cnFYeLAACBrn6ZAYeQv3LzA,6771
9
9
  cuenca_validations/types/card.py,sha256=UGzz8NTFAverUmdUKAK1oGHnOnjSNTpIRUm93vKSSGY,1295
10
- cuenca_validations/types/enums.py,sha256=w-7dMR_Dg3mcmwn7A16Dy1oq-DUycVNg6CPOQ5UQog8,20960
10
+ cuenca_validations/types/enums.py,sha256=8PgHV_BAaaO_lwFggeAswuUupcjysPOWZnyNzYoR4Dc,21256
11
11
  cuenca_validations/types/files.py,sha256=2CszbwF9ytXV9suFFwyDjYG4XxY8UhCjRw3HttVXXNw,269
12
12
  cuenca_validations/types/general.py,sha256=eYFYwyx_a4_J480GYpqW3DFbZabDFcUjvLRMQbShIUc,5622
13
13
  cuenca_validations/types/helpers.py,sha256=4veeLZbugHHqZk0ezSim978VhH6Vq8XTrEhe1eE_r3A,1531
14
14
  cuenca_validations/types/identities.py,sha256=j2xxh3UYHJe6IbAwr9yNXJkebTth_-g3SUmHeiPez8M,5513
15
15
  cuenca_validations/types/morals.py,sha256=davabh5hAnFVQyM7-yCyDaT5ewXnm0cr1BtqDIwzkX8,1833
16
- cuenca_validations/types/queries.py,sha256=rFbvV70VS2AnSQ6ZGT5NUr0yYzKgIiGronHjnMStF0c,6019
17
- cuenca_validations/types/requests.py,sha256=wUVHN20YG5bsJ4QVIkrPYyLEpVfibbf_3kkL55hjgrs,29678
18
- cuenca_validations-2.1.46.dist-info/licenses/LICENSE,sha256=wR76FmxBbfnQpwELkkE5iMF8sFIafEMgXLTE4N4WPTc,1063
16
+ cuenca_validations/types/queries.py,sha256=yJZGW3p6uWGaBm6mjDp7KBgg7oLh0CUlAJeeVLRzowk,6134
17
+ cuenca_validations/types/requests.py,sha256=-1QE3tFwX5LhKyRXlNryZKQ2KTsu_QRQAcZiRrDEt7o,32553
18
+ cuenca_validations-2.1.48.dev0.dist-info/licenses/LICENSE,sha256=wR76FmxBbfnQpwELkkE5iMF8sFIafEMgXLTE4N4WPTc,1063
19
19
  tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
20
  tests/test_card.py,sha256=QAfRz7e11gWICPnFJZ2tiYgUsFV3C9TwzJXrDnDNXFw,1202
21
21
  tests/test_errors.py,sha256=ixiIgEuBuzfsL5p4uCFdF32XqFRtTPF6EVhGJ0keOrI,930
22
22
  tests/test_helpers.py,sha256=fx2R7y6oQO8XeQzevJe826NuHkBgvtznZicomchB3Gg,899
23
- tests/test_requests.py,sha256=SXumnZ602n5KrOLJlh41SvBQNyIvNUwr7yVeYKEUr-g,6992
23
+ tests/test_requests.py,sha256=mjH-VbU_jCdgjQPAalTcJo76iL6tSBnmyengiAY-M20,8671
24
24
  tests/test_statement.py,sha256=IOE0rRRBgBZSJv_FLaETEyn5NzzXKMNTqgjv99GX-68,1436
25
25
  tests/test_types.py,sha256=rPjqPGfPU73MSdbeJpoW_ai5TAO25hWSnQAt_H7ZIeI,23055
26
26
  tests/test_validators.py,sha256=Jjr9gWTT4cRntGiKvQK4fncqx3JkEuTWkKm1VqpRHTs,1829
27
- cuenca_validations-2.1.46.dist-info/METADATA,sha256=I-ruo3wsej_4x82WCracwJOQCMOyL9k7fvT3iC-w0UM,1595
28
- cuenca_validations-2.1.46.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
29
- cuenca_validations-2.1.46.dist-info/top_level.txt,sha256=4233xdOs2HtuT-GFRjcDcwK0IwdwvWdczOtk0fPB6Gw,25
30
- cuenca_validations-2.1.46.dist-info/RECORD,,
27
+ cuenca_validations-2.1.48.dev0.dist-info/METADATA,sha256=hefgQaOl2YwGK7Z3FBq5b0OPYBw8IEFay_KLV0r95XU,1600
28
+ cuenca_validations-2.1.48.dev0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
29
+ cuenca_validations-2.1.48.dev0.dist-info/top_level.txt,sha256=4233xdOs2HtuT-GFRjcDcwK0IwdwvWdczOtk0fPB6Gw,25
30
+ cuenca_validations-2.1.48.dev0.dist-info/RECORD,,
tests/test_requests.py CHANGED
@@ -9,10 +9,13 @@ from cuenca_validations.types.enums import (
9
9
  )
10
10
  from cuenca_validations.types.queries import OperatorQuery
11
11
  from cuenca_validations.types.requests import (
12
+ MAX_TRANSFER_ORDER_BATCH_LINES,
12
13
  OperatorLoginRequest,
14
+ OperatorLoginUpdateRequest,
13
15
  OperatorRequest,
14
16
  OperatorUpdateRequest,
15
17
  PasswordResetRequest,
18
+ TransferOrderRequest,
16
19
  UpdateTransferRequest,
17
20
  UserTOSAgreementRequest,
18
21
  UserUpdateRequest,
@@ -90,6 +93,19 @@ def test_operator_login_request_forbids_extra() -> None:
90
93
  assert 'Extra inputs are not permitted' in str(ex.value)
91
94
 
92
95
 
96
+ def test_operator_login_update_request_valid() -> None:
97
+ req = OperatorLoginUpdateRequest.model_validate({'code': '123456'})
98
+ assert req.code == '123456'
99
+
100
+
101
+ def test_operator_login_update_request_forbids_extra() -> None:
102
+ with pytest.raises(ValidationError) as ex:
103
+ OperatorLoginUpdateRequest.model_validate(
104
+ {'code': '123456', 'foo': 'bar'}
105
+ )
106
+ assert 'Extra inputs are not permitted' in str(ex.value)
107
+
108
+
93
109
  def test_operator_query_valid() -> None:
94
110
  query = OperatorQuery.model_validate({'email': 'maria.lopez@aceros.com'})
95
111
  assert str(query.email) == 'maria.lopez@aceros.com'
@@ -218,3 +234,36 @@ def test_update_transfer_request_forbids_extra() -> None:
218
234
  {'status': 'succeeded', 'foo': 'bar'}
219
235
  )
220
236
  assert 'Extra inputs are not permitted' in str(ex.value)
237
+
238
+
239
+ def test_transfer_order_request_shape() -> None:
240
+ line = {
241
+ 'account_number': '646180157034181180',
242
+ 'recipient_name': 'Doroteo Arango',
243
+ 'amount': 100_00,
244
+ 'descriptor': 'Mezcal',
245
+ }
246
+ single = TransferOrderRequest.model_validate(
247
+ {**line, 'idempotency_key': 'single'}
248
+ )
249
+ assert single.items is None
250
+ batch = TransferOrderRequest.model_validate(
251
+ {'idempotency_key': 'batch', 'items': [line]}
252
+ )
253
+ assert batch.items is not None
254
+
255
+ with pytest.raises(ValidationError, match='not both'):
256
+ TransferOrderRequest.model_validate(
257
+ {**line, 'idempotency_key': 'both', 'items': [line]}
258
+ )
259
+ with pytest.raises(ValidationError, match='items must not be empty'):
260
+ TransferOrderRequest.model_validate(
261
+ {**line, 'idempotency_key': 'empty', 'items': []}
262
+ )
263
+ with pytest.raises(ValidationError, match='Batch exceeds maximum'):
264
+ TransferOrderRequest.model_validate(
265
+ {
266
+ 'idempotency_key': 'too-many',
267
+ 'items': [line] * (MAX_TRANSFER_ORDER_BATCH_LINES + 1),
268
+ }
269
+ )