diff --git a/cuenca_validations/types/__init__.py b/cuenca_validations/types/__init__.py index 44bedae8..8b6d41c1 100644 --- a/cuenca_validations/types/__init__.py +++ b/cuenca_validations/types/__init__.py @@ -14,6 +14,7 @@ 'BankAccountStatus', 'BatchFileMetadata', 'Beneficiary', + 'BeneficiaryRequest', 'BillPaymentQuery', 'CardErrorType', 'CardFundingType', @@ -221,6 +222,7 @@ from .requests import ( ApiKeyUpdateRequest, BankAccountValidationRequest, + BeneficiaryRequest, CurpValidationRequest, EndpointRequest, EndpointUpdateRequest, diff --git a/cuenca_validations/types/identities.py b/cuenca_validations/types/identities.py index 2fd02568..590edf32 100644 --- a/cuenca_validations/types/identities.py +++ b/cuenca_validations/types/identities.py @@ -1,5 +1,5 @@ import datetime as dt -from typing import Annotated, Optional +from typing import Annotated, Optional, Union from pydantic import BaseModel, ConfigDict, Field, SecretStr, StringConstraints from pydantic_extra_types.phone_numbers import PhoneNumber @@ -89,12 +89,12 @@ class AddressRequest(BaseModel): ) -class Beneficiary(BaseModel): +class BaseBeneficiary(BaseModel): name: str birth_date: dt.date - phone_number: PhoneNumber user_relationship: str percentage: Annotated[int, Field(ge=1, le=100)] + model_config = ConfigDict( json_schema_extra={ "example": { @@ -108,6 +108,10 @@ class Beneficiary(BaseModel): ) +class Beneficiary(BaseBeneficiary): + phone_number: Union[PhoneNumber, str] + + class VerificationErrors(BaseModel): identifier: str = Field( description='Unique identifier for the step validation' diff --git a/cuenca_validations/types/requests.py b/cuenca_validations/types/requests.py index f74216b3..dcfdbe00 100644 --- a/cuenca_validations/types/requests.py +++ b/cuenca_validations/types/requests.py @@ -73,7 +73,7 @@ from .helpers import validate_age_requirement from .identities import ( AddressRequest, - Beneficiary, + BaseBeneficiary, Curp, KYCFile, Password, @@ -330,7 +330,7 @@ class UserPldRiskLevelRequest(BaseModel): level: float = Field(ge=0.0, le=1.0) -class CurpValidationRequest(BaseModel): +class CurpValidationRequest(BaseRequest): names: Optional[str] = None first_surname: Optional[str] = None second_surname: Optional[str] = Field( @@ -439,13 +439,13 @@ def __get_pydantic_core_schema__( ) -class UserTOSAgreementRequest(BaseModel): +class UserTOSAgreementRequest(BaseRequest): tos_id: str location: Coordinate signature_image_url: Optional[FileCuencaUrl] = None -class UserRequest(BaseModel): +class UserRequest(BaseRequest): curp: Curp = Field( description=( 'Mexican government ID (18 characters). ' 'Must be pre-validated.' @@ -495,12 +495,16 @@ def validate_profession(cls, profession: Profession) -> Profession: return profession -class UserUpdateRequest(BaseModel): +class BeneficiaryRequest(BaseBeneficiary, BaseRequest): + phone_number: PhoneNumber + + +class UserUpdateRequest(BaseRequest): profession: Optional[Profession] = None email_verification_id: Optional[str] = None phone_verification_id: Optional[str] = None address: Optional[AddressRequest] = None - beneficiaries: Optional[list[Beneficiary]] = None + beneficiaries: Optional[list[BeneficiaryRequest]] = None govt_id: Optional[KYCFile] = None proof_of_address: Optional[KYCFile] = None proof_of_life: Optional[KYCFile] = None @@ -518,7 +522,7 @@ class UserUpdateRequest(BaseModel): @field_validator('beneficiaries') @classmethod def beneficiary_percentage( - cls, beneficiaries: Optional[list[Beneficiary]] = None + cls, beneficiaries: Optional[list[BeneficiaryRequest]] = None ): if beneficiaries and sum(b.percentage for b in beneficiaries) != 100: raise ValueError('The total percentage should be 100%') @@ -590,7 +594,7 @@ class FileBatchUploadRequest(BaseModel): user_id: str -class VerificationRequest(BaseModel): +class VerificationRequest(BaseRequest): type: VerificationType recipient: Union[EmailStr, PhoneNumber] = Field( description='Phone or email to validate' @@ -614,7 +618,7 @@ def validate_sender(cls, recipient: str, values): ) -class VerificationAttemptRequest(BaseModel): +class VerificationAttemptRequest(BaseRequest): code: Annotated[ str, StringConstraints(strict=True, min_length=6, max_length=6), @@ -655,11 +659,11 @@ class KYCValidationRequest(BaseRequest): force: bool = False -class BankAccountValidationRequest(BaseModel): +class BankAccountValidationRequest(BaseRequest): account_number: Union[Clabe, PaymentCardNumber] -class UserListsRequest(BaseModel): +class UserListsRequest(BaseRequest): curp: Optional[Curp] = Field(None, description='Curp to review on lists') rfc: Optional[Rfc] = Field(None, description='Rfc to review on lists') account_number: Optional[Union[Clabe, PaymentCardNumber]] = Field( @@ -758,5 +762,5 @@ class PartnerUpdateRequest(BaseRequest): shareholders: Optional[list[Shareholder]] = None -class PhoneVerificationAssociationRequest(BaseModel): +class PhoneVerificationAssociationRequest(BaseRequest): verification_id: str diff --git a/cuenca_validations/version.py b/cuenca_validations/version.py index 1db5030e..96f86229 100644 --- a/cuenca_validations/version.py +++ b/cuenca_validations/version.py @@ -1 +1 @@ -__version__ = '2.1.16' +__version__ = '2.1.17' diff --git a/tests/test_types.py b/tests/test_types.py index 5d2f66e5..09d0f97f 100644 --- a/tests/test_types.py +++ b/tests/test_types.py @@ -394,7 +394,9 @@ def test_curp_validation_request(): assert all(field in error_msg for field in required_fields) req_curp = CurpValidationRequest(**request) - assert req_curp.model_dump() == request + # exclude_none=False to test that the request equals the original dict, + # since normally exclude_none defaults to True in BaseRequest.model_dump() + assert req_curp.model_dump(exclude_none=False) == request request['date_of_birth'] = dt.date(2006, 5, 17) @@ -435,16 +437,11 @@ def test_user_update_request(): percentage=50, ), ], - curp_document_uri='https://sandbox.cuenca.com/files/EF123', profession=Profession.empleado, ) update_req = UserUpdateRequest(**request) beneficiaries = [b.model_dump() for b in update_req.beneficiaries] assert beneficiaries == request['beneficiaries'] - assert ( - update_req.curp_document_uri.unicode_string() - == request['curp_document_uri'] - ) assert update_req.profession == Profession.empleado request['beneficiaries'] = [ @@ -480,26 +477,6 @@ def test_user_update_request(): assert 'The total percentage should be 100%' in str(v) request.pop('beneficiaries') - tos_request = dict( - terms_of_service=dict( - version='2022-01-01', - ip='127.0.0.1', - location='1111,1111', - type='ifpe', - ) - ) - UserUpdateRequest(**tos_request) - - tos_request = dict( - terms_of_service=dict( - version='2022-01-01', - ip='2001:0db8:0000:0000:0000:ff00:0042:8329', - location='1111,1111', - type='ifpe', - ) - ) - UserUpdateRequest(**tos_request) - kyc_request = dict( govt_id=dict( type='ine',