@classmethoddefvalidate(cls,__input_value:str,_:core_schema.ValidationInfo)->PaymentCardNumber:"""Validate the `PaymentCardNumber` instance. Args: __input_value: The input value to validate. _: The validation info. Returns: The validated `PaymentCardNumber` instance. """returncls(__input_value)
@classmethoddefvalidate_digits(cls,card_number:str)->None:"""Validate that the card number is all digits. Args: card_number: The card number to validate. Raises: PydanticCustomError: If the card number is not all digits. """ifnotcard_number.isdigit():raisePydanticCustomError('payment_card_number_digits','Card number is not all digits')
@classmethoddefvalidate_luhn_check_digit(cls,card_number:str)->str:"""Validate the payment card number. Based on the [Luhn algorithm](https://en.wikipedia.org/wiki/Luhn_algorithm). Args: card_number: The card number to validate. Returns: The validated card number. Raises: PydanticCustomError: If the card number is not valid. """sum_=int(card_number[-1])length=len(card_number)parity=length%2foriinrange(length-1):digit=int(card_number[i])ifi%2==parity:digit*=2ifdigit>9:digit-=9sum_+=digitvalid=sum_%10==0ifnotvalid:raisePydanticCustomError('payment_card_number_luhn','Card number is not luhn valid')returncard_number
@staticmethoddefvalidate_brand(card_number:str)->PaymentCardBrand:"""Validate length based on [BIN](https://en.wikipedia.org/wiki/Payment_card_number#Issuer_identification_number_(IIN)) for major brands. Args: card_number: The card number to validate. Returns: The validated card brand. Raises: PydanticCustomError: If the card number is not valid. """ifcard_number[0]=='4':brand=PaymentCardBrand.visaelif51<=int(card_number[:2])<=55:brand=PaymentCardBrand.mastercardelifcard_number[:2]in{'34','37'}:brand=PaymentCardBrand.amexelif2200<=int(card_number[:4])<=2204:brand=PaymentCardBrand.mirelse:brand=PaymentCardBrand.otherrequired_length:None|int|str=NoneifbrandinPaymentCardBrand.mastercard:required_length=16valid=len(card_number)==required_lengthelifbrand==PaymentCardBrand.visa:required_length='13, 16 or 19'valid=len(card_number)in{13,16,19}elifbrand==PaymentCardBrand.amex:required_length=15valid=len(card_number)==required_lengthelifbrand==PaymentCardBrand.mir:required_length='in range from 16 to 19'valid=len(card_number)inrange(16,20)else:valid=Trueifnotvalid:raisePydanticCustomError('payment_card_number_brand','Length for a {brand} card must be {required_length}',{'brand':brand,'required_length':required_length},)returnbrand