Processing credit cards is an important aspect of e-commerce. Some
card types such as Visa and Mastercard are widely accepted, while
others such as Diner's Club are not. When a shopper types their credit
card number in a web browser, we would like to verify that the card is
accepted and the number is valid before contacting the credit card
company.
The typical credit card has a 15- or 16-digit number embossed on the
front. There is a lot of information packed into this number, but we
will focus on just the type of card and the checksum.
The type of a credit card can be identified by the first few digits. The following table lists prefixes used for several popular credit card types.
Card Type | Prefix | Example
numbers (fake!) |
---|---|---|
American Express |
34, 37 |
378 2822 4631
0005 371 4496 3539 8431 |
Discover | 6011, 644, 65 |
6011 1111 1111
1117 6011 0009 9013 9424 |
MasterCard | 51—55 | 5105 1051 0510
5100 5394 1291 0548 2350 5555 5555 5555 4444 |
Visa | 4 | 4111 1111 1111
1111 4012 8888 8888 1881 4222 2222 2222 2 |
Note
that American Express card numbers are 15 digits, while most other card
numbers are 16 digits. The final Visa number, which is only 13 digits,
is also valid.
Of course, people sometimes type their credit card numbers incorrectly. To catch simple errors (e.g,. transpositions, off-by-one, etc.), the rightmost digit of the card number is actually a checksum. In other words, the value of the rightmost digit is the result of a carefully designed calculation involving the other digits. It is an example of a Luhn Algorithm, which is itself part of a much larger class of error detecting codes. If the checksum is inconsistent with the other digits, the card number is invalid and should be re-entered. By pre-checking the number before contacting the card provider, this approach can provide feedback quickly and avoid invalid transactions.
The checksum is validated as follows:
Consider the following example of a valid 15-digit number:
Original card number |
3 |
7 |
1 |
4 |
4 |
9 |
6 |
3 |
5 |
3 |
9 |
8 |
4 |
3 |
1 |
Sum |
Valid |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Doubled digits |
14 |
8 |
18 |
6 |
6 |
16 |
6 |
||||||||||
Doubled digits, reduced to a
single digit |
5 |
8 |
9 |
6 |
6 |
7 |
6 |
47 |
|||||||||
Unchanged digits |
3 |
1 |
4 |
6 |
5 |
9 |
4 |
1 |
33 |
||||||||
Check |
80 |
True |
And here is an example of an invalid 16-digit number:
Original card number |
4 |
0 |
1 |
2 |
3 |
4 |
5 |
6 | 7 | 8 |
9 |
0 |
1 |
2 |
3 |
4 |
Sum |
Valid |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Doubled digits |
8 |
2 |
6 |
10 |
14 |
18 |
2 |
6 |
||||||||||
Doubled digits, reduced to a
single digit |
8 |
2 |
6 | 1 |
5 | 9 |
2 |
6 |
39 |
|||||||||
Unchanged digits |
0 |
2 |
4 |
6 |
8 |
0 |
2 |
4 |
26 |
|||||||||
Check |
65 |
False |
Create two files: one named credit_card.py
and one
named test_credit_card.py
.
In the credit_card
module, you will implement the
functions partially documented
below:
def is_type_accepted(card_number):
'''Checks if the given card is of an accepted type.
Parameter: A string representing a credit card number.
Return value: True if the number is an American Express, Discover, MasterCard, or Visa number;
False otherwise.
'''
def is_checksum_valid(card_number):
'''Checks if a credit card number is valid.
Parameter: A string representing an integer.
Return value: True if the number passes the Luhn checksum algorithm;
False if it does not.
'''
def main():
'''Asks the user for a credit card number. Reports whether the number is accepted and valid.
'''
if __name__=='__main__':
main()
Follow the pattern suggested by
How to Solve It:
Begin by carefully reading the examples
above to understand the
problem. Work additional examples. Try checking one of your own credit
card numbers: You know who issued the card, and you know the number is
valid. Change one of the digits to create an invalid number, and make
sure you can show it is invalid. Destroy any scratch paper when you are
done so you don't give your card number away!
Then develop a top-down design and write
pseudocode. How can you break down the problems into smaller
parts? There are many different ways. We will compare ideas in class on
Wednesday; make sure you have
developed a top-down design and written pseudocode by then.
Next, implement these functions. As you go along,
main
function. Put your unit tests in the test_credit_card
module. Make sure you do not
use your real credit card numbers in your tests!Finally, review your code for clarity,
correctness, and
efficiency.
Remember this process is iterative: At any point you may need to go back to revise your work at an earlier step.
To help you get started with your unit tests, here is a unit test
for is_checksum_valid
.
from credit_card import *
def test_is_checksum_valid():
assert is_checksum_valid("378 2822 4631 0005") == True
assert is_checksum_valid("378 2822 4631 0000") == False # Changed check digit
assert is_checksum_valid("379 2822 4631 0005") == False # Changed undoubled digit
assert is_checksum_valid("378 5822 4631 0005") == False # Changed doubled digit
assert is_checksum_valid("738 2822 4631 0005") == False # Transposed two digits
assert is_checksum_valid("6011 0009 9013 9424") == True
assert is_checksum_valid("5394 1291 0548 2350") == True
assert is_checksum_valid("2000 0000 0000 0006") == True
assert is_checksum_valid("7000 0000 0000 0005") == False
assert is_checksum_valid("240") == True
assert is_checksum_valid("345") == False
assert is_checksum_valid("1010101010") == True
assert is_checksum_valid("2010101010") == False
assert is_checksum_valid("4222 2222 2222 2") == True
assert is_checksum_valid("4111 1111 1111 1") == False
assert is_checksum_valid("5555 5555 5555 4444") == True
assert is_checksum_valid("5555 5555 5555 0101") == False
assert is_checksum_valid("6011111111111117") == True
assert is_checksum_valid("6011111111111110") == False
print("is_checksum_valid: All tests pass!")
Please style your code per section 3.4 of the textbook.
Submit two files, credit_card.py
and test_credit_card.py
,
through the online turnin form.
2 points - |
is_type_accepted |
4 points - |
is_checksum_valid |
1 point - |
main |
6 points - |
Supporting functions based on
top-down design |
6 points - |
Documentation for supporting
functions |
3 points - |
Unit tests for is_type_accepted |
6 points - |
Unit tests for supporting
functions |
2 points - |
Style and following instrutions |
Created October 27, 2016
Last revised November 28, 2016, 09:53:50 AM PST
This
work is licensed under a Creative
Commons Attribution-Noncommercial-Share Alike 3.0 United States License.