Skip to content

Commit c8883e3

Browse files
AlexanderSovAlexander Plaxinsamuelcolvin
authored
Added support for 13/19 digits VISA credit cards in PaymentCardNumber type (pydantic#2286)
* Added support for 13/19 digits VISA credit cards * Added changes md-file * Fixed tests VALID_VISA_19 length, changed constants order * tiny tweaks Co-authored-by: Alexander Plaxin <[email protected]> Co-authored-by: Samuel Colvin <[email protected]>
1 parent 3f849a3 commit c8883e3

File tree

3 files changed

+15
-7
lines changed

3 files changed

+15
-7
lines changed

changes/1416-AlexanderSov.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Added support for 13/19 digits VISA credit cards in `PaymentCardNumber` type

pydantic/types.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -903,10 +903,13 @@ def validate_length_for_brand(cls, card_number: 'PaymentCardNumber') -> 'Payment
903903
Validate length based on BIN for major brands:
904904
https://en.wikipedia.org/wiki/Payment_card_number#Issuer_identification_number_(IIN)
905905
"""
906-
required_length: Optional[int] = None
907-
if card_number.brand in {PaymentCardBrand.visa, PaymentCardBrand.mastercard}:
906+
required_length: Union[None, int, str] = None
907+
if card_number.brand in PaymentCardBrand.mastercard:
908908
required_length = 16
909909
valid = len(card_number) == required_length
910+
elif card_number.brand == PaymentCardBrand.visa:
911+
required_length = '13, 16 or 19'
912+
valid = len(card_number) in {13, 16, 19}
910913
elif card_number.brand == PaymentCardBrand.amex:
911914
required_length = 15
912915
valid = len(card_number) == required_length

tests/test_types_payment_card_number.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99

1010
VALID_AMEX = '370000000000002'
1111
VALID_MC = '5100000000000003'
12-
VALID_VISA = '4050000000000001'
12+
VALID_VISA_13 = '4050000000001'
13+
VALID_VISA_16 = '4050000000000001'
14+
VALID_VISA_19 = '4050000000000000001'
1315
VALID_OTHER = '2000000000000000008'
1416
LUHN_INVALID = '4000000000000000'
1517
LEN_INVALID = '40000000000000006'
@@ -73,7 +75,9 @@ def test_validate_luhn_check_digit(card_number: str, valid: bool):
7375
@pytest.mark.parametrize(
7476
'card_number, brand, valid',
7577
[
76-
(VALID_VISA, PaymentCardBrand.visa, True),
78+
(VALID_VISA_13, PaymentCardBrand.visa, True),
79+
(VALID_VISA_16, PaymentCardBrand.visa, True),
80+
(VALID_VISA_19, PaymentCardBrand.visa, True),
7781
(VALID_MC, PaymentCardBrand.mastercard, True),
7882
(VALID_AMEX, PaymentCardBrand.amex, True),
7983
(VALID_OTHER, PaymentCardBrand.other, True),
@@ -95,7 +99,7 @@ def test_length_for_brand(card_number: str, brand: PaymentCardBrand, valid: bool
9599
[
96100
(VALID_AMEX, PaymentCardBrand.amex),
97101
(VALID_MC, PaymentCardBrand.mastercard),
98-
(VALID_VISA, PaymentCardBrand.visa),
102+
(VALID_VISA_16, PaymentCardBrand.visa),
99103
(VALID_OTHER, PaymentCardBrand.other),
100104
],
101105
)
@@ -104,8 +108,8 @@ def test_get_brand(card_number: str, brand: PaymentCardBrand):
104108

105109

106110
def test_valid():
107-
card = PaymentCard(card_number=VALID_VISA)
108-
assert str(card.card_number) == VALID_VISA
111+
card = PaymentCard(card_number=VALID_VISA_16)
112+
assert str(card.card_number) == VALID_VISA_16
109113
assert card.card_number.masked == '405000******0001'
110114

111115

0 commit comments

Comments
 (0)