@open-tender/utils
Version:
A library of utils for use with Open Tender applications that utilize our cloud-based Order API.
164 lines (163 loc) • 5.75 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.validateCreditCard = exports.formatCard = exports.formatCardField = exports.makeAcctNumber = exports.makeAlphaNumeric = exports.makeNumeric = exports.getCardType = exports.cardNumbersRegex = exports.cardNames = void 0;
const helpers_1 = require("./helpers");
exports.cardNames = {
VISA: 'Visa',
MC: 'Mastercard',
DISC: 'Discover',
AMEX: 'American Express',
OTHER: 'Other Credit Card'
};
// https://github.com/jasminmif/react-interactive-paycard
exports.cardNumbersRegex = {
VISA: '^4',
MC: '^5[1-5]',
DISC: '^6011',
AMEX: '^(34|37)'
// unionpay: '^62',
// troy: '^9792'
};
const getCardType = (cardNumber) => {
const number = cardNumber;
let re;
for (const [card, pattern] of Object.entries(exports.cardNumbersRegex)) {
re = new RegExp(pattern);
if (number.match(re) !== null) {
return card;
}
}
return 'OTHER'; // default type
};
exports.getCardType = getCardType;
const chunks = [
[0, 4],
[4, 8],
[8, 12],
[12, 16]
];
const amexChunks = [
[0, 4],
[4, 10],
[10, 15]
];
const makeNumeric = (str) => {
const strMatches = str.match(/\d+/g); // limit to numerical input, returns an array
if (!strMatches)
return '';
return strMatches.join('').replace(/\s/g, '');
};
exports.makeNumeric = makeNumeric;
const makeAlphaNumeric = (str) => {
const strMatches = str.match(/[a-zA-Z0-9]+/g); // limit to alphanumeric input, returns an array
if (!strMatches)
return '';
return strMatches.join('').replace(/\s/g, '');
};
exports.makeAlphaNumeric = makeAlphaNumeric;
const makeAcctNumber = (str, cardType) => {
const strMatches = str.match(/\d+/g); // limit to numerical input, returns an array
if (!strMatches)
return '';
str = strMatches.join('').replace(/\s/g, '');
if (cardType === 'AMEX') {
return amexChunks
.map(([start, end]) => str.slice(start, end))
.filter(i => i.length)
.join(' ')
.slice(0, 18);
}
else {
return chunks
.map(([start, end]) => str.slice(start, end))
.filter(i => i.length)
.join(' ')
.slice(0, 19);
}
};
exports.makeAcctNumber = makeAcctNumber;
const formatCardField = (field, value) => {
const cleanValue = field === 'addr' || field === 'cardholder_name' || field === 'zip'
? value
: (0, exports.makeNumeric)(value);
switch (field) {
case 'acct': {
const currentType = (0, exports.getCardType)(value.replace(/\s/g, ''));
return (0, exports.makeAcctNumber)(value, currentType);
}
case 'exp': {
value = cleanValue.slice(0, 4);
if (value.length > 2) {
value = `${value.slice(0, 2)} / ${value.slice(2, 4)}`;
}
return value;
}
case 'cvv':
return cleanValue.slice(0, 4);
case 'zip':
return (0, exports.makeAlphaNumeric)(cleanValue);
default:
return cleanValue;
}
};
exports.formatCardField = formatCardField;
const formatCard = (card) => {
if (!card)
return [null, null];
const creditCardType = (0, exports.getCardType)(card.acct.replace(/\s/g, ''));
const creditCard = {
acct: (0, exports.formatCardField)('acct', card.acct),
exp: (0, exports.formatCardField)('exp', card.exp),
cvv: (0, exports.formatCardField)('cvv', card.cvv),
zip: (0, exports.formatCardField)('zip', card.zip),
save: card.save || true
};
if ('addr' in card)
creditCard.addr = card.addr;
if ('cardholder_name' in card)
creditCard.cardholder_name = card.cardholder_name;
return [creditCard, creditCardType];
};
exports.formatCard = formatCard;
const validateCreditCard = (card, cardType, requireCardholderName = false) => {
const errors = {};
let { acct, exp, cvv, cardholder_name } = card;
const acctLength = cardType === 'AMEX' ? 15 : 16;
acct = acct ? acct.replace(/\s/g, '') : '';
if (acct.length !== acctLength) {
errors.acct = `Card number must be ${acctLength} digits`;
}
else if (!(0, helpers_1.isNum)(acct)) {
errors.acct = 'Card number must be only numbers';
}
exp = (exp ? exp.replace(/\s/g, '') : '').replace('/', '').padStart(4, '0');
const expMonth = parseInt(exp.slice(0, 2));
const expYear = parseInt(exp.slice(2, 4));
if (!(0, helpers_1.isNum)(exp) || exp.length !== 4) {
errors.exp = 'Expiration must be 4 digits in MMYY format';
}
else if (expMonth < 1 || expMonth > 12) {
errors.exp = 'Expiration month must be number between 1 and 12';
}
else if (expYear < 20) {
errors.exp = 'Expiration year must be 2020 or later';
}
const cvvLength = cardType === 'AMEX' ? 4 : 3;
cvv = cvv ? cvv.replace(/\s/g, '') : '';
if (cvv.length !== cvvLength) {
errors.cvv = `CVV must be ${cvvLength} digits for this card type`;
}
else if (!(0, helpers_1.isNum)(cvv)) {
errors.cvv = 'CVV must be only numbers';
}
cardholder_name = cardholder_name === null || cardholder_name === void 0 ? void 0 : cardholder_name.trim();
if (requireCardholderName && !cardholder_name) {
errors.cardholder_name = 'Cardholder name is required';
}
if (!(0, helpers_1.isEmpty)(errors)) {
return { card, cardType, errors };
}
card = Object.assign(Object.assign({}, card), { acct, exp, cvv, cardholder_name });
return { card, cardType, errors: null };
};
exports.validateCreditCard = validateCreditCard;