Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🚀 - Better payment system detection #2755

Closed
AlexXanderGrib opened this issue Sep 24, 2022 · 1 comment · Fixed by #4410
Closed

🚀 - Better payment system detection #2755

AlexXanderGrib opened this issue Sep 24, 2022 · 1 comment · Fixed by #4410
Assignees
Labels
contributions welcome Architecture is clear and community can help P2 This issue has medium priority S1 This issue has high severity

Comments

@AlexXanderGrib
Copy link
Contributor

Which @taiga-ui/* package(s) are relevant/releated to the feature request?

addon-commerce

Description

My solution is code down below. There are it's advantages

  1. Declarative
  2. Detects co-badged cards

What to do:

  1. Make TuiPaymentSystem enum-alike for better readability and add more payment systems:
const enum TuiPaymentSystem {
  Mastercard = "mastercard",
  Electron = "electron",
  Visa = "visa",
  Maestro = "maestro",
  Mir = "mir",
  AmericanExpress = "amex",
  DinersClub = "dinersclub",
  Discover = "discover",
  JCB = "jcb",
  UnionPay = "unionpay",
}
  1. Change detection algorithm:
// https://en.wikipedia.org/wiki/Payment_card_number#Issuer_identification_number_(IIN)
const paymentSystems: readonly [string, TuiPaymentSystem][] = [
  ["2200-2204", TuiPaymentSystem.Mir],
  ["2221-2720", TuiPaymentSystem.Mastercard],
  ["3528-3589", TuiPaymentSystem.JCB],
  ["34", TuiPaymentSystem.AmericanExpress],
  ["37", TuiPaymentSystem.AmericanExpress],
  ["36", TuiPaymentSystem.DinersClub],
  ["417500", TuiPaymentSystem.Electron],
  ["4026", TuiPaymentSystem.Electron],
  ["4508", TuiPaymentSystem.Electron],
  ["4844", TuiPaymentSystem.Electron],
  ["4913", TuiPaymentSystem.Electron],
  ["4917", TuiPaymentSystem.Electron],
  ["4", TuiPaymentSystem.Visa],
  ["5018", TuiPaymentSystem.Maestro],
  ["5020", TuiPaymentSystem.Maestro],
  ["5038", TuiPaymentSystem.Maestro],
  ["5893", TuiPaymentSystem.Maestro],
  ["54", TuiPaymentSystem.DinersClub],
  ["51-55", TuiPaymentSystem.Mastercard],
  ["622126-622925", TuiPaymentSystem.Discover],
  ["6011", TuiPaymentSystem.Discover],
  ["6304", TuiPaymentSystem.Maestro],
  ["6759", TuiPaymentSystem.Maestro],
  ["6761", TuiPaymentSystem.Maestro],
  ["6762", TuiPaymentSystem.Maestro],
  ["6763", TuiPaymentSystem.Maestro],
  ["676770", TuiPaymentSystem.Maestro],
  ["676774", TuiPaymentSystem.Maestro],
  ["644-649", TuiPaymentSystem.Discover],
  ["65", TuiPaymentSystem.Discover],
  
  // this is for detection of Mir-UnionPay cards. 629157 is only bin i know
  ["629157", TuiPaymentSystem.Mir], 
  ["62", TuiPaymentSystem.UnionPay],
];

function matchRange(range: string, cardNumber: string): boolean {
  if (!range.includes("-")) {
    return cardNumber.startsWith(range);
  }

  const rangeStart = parseInt(range.split("-")[0], 10);
  const rangeEnd = parseInt(range.split("-")[1], 10);
  const cardNumberNumeric = parseInt(cardNumber.slice(0, rangeStart.toString().length), 10);

  return cardNumberNumeric >= rangeStart && cardNumberNumeric <= rangeEnd;
}

function detectPaymentSystems(cardNumber: string, available?: TuiPaymentSystem[]) {
  if (typeof cardNumber !== "string" || cardNumber === "") return [];
  
  const paymentSystem = paymentSystems
    .filter(([range, system]) => {
      if (Array.isArray(available) && !available.includes(system)) {
        return false;
      }

      return matchRange(range, cardNumber);
    })
    .map((x) => x[1]);

  return paymentSystem;
}
  1. Add backwards compatibility
function cardNumberIs(cardNumber: string, paymentSystem: TuiPaymentSystem) {
  return detectPaymentSystems(cardNumber, [paymentSystem]).length === 1;
}

export function tuiGetPaymentSystem(
  cardNumber: string,
  available: TuiPaymentSystem[] = [
    TuiPaymentSystem.Maestro,
    TuiPaymentSystem.Mastercard,
    TuiPaymentSystem.Electron,
    TuiPaymentSystem.Visa,
    TuiPaymentSystem.Mir
  ]
) {
  return detectPaymentSystems(cardNumber, available)[0];
}

export function tuiIsMaestro(cardNumber: string) {
  return cardNumberIs(cardNumber, TuiPaymentSystem.Maestro);
}

export function tuiIsMastercard(cardNumber: string) {
  return cardNumberIs(cardNumber, TuiPaymentSystem.Mastercard);
}

export function tuiIsMir(cardNumber: string) {
  return cardNumberIs(cardNumber, TuiPaymentSystem.Mir);
}

export function tuiIsElectron(cardNumber: string) {
  return cardNumberIs(cardNumber, TuiPaymentSystem.Electron);
}

export function tuiIsVisa(cardNumber: string) {
  return cardNumberIs(cardNumber, TuiPaymentSystem.Visa);
}
@waterplea
Copy link
Collaborator

That's an interesting approach. Do you want to make a PR for it? Payment systems used to be a enum but we switch to union type so it's easier to use in templates as input. I'd like to stick to that for now. Another comment is that split methods create an array and therefore a heavy operations not fit for getters. As well as filter and map. Keep that in mind.

@waterplea waterplea added contributions welcome Architecture is clear and community can help P3 This issue has low priority and removed state: need triage labels Sep 27, 2022
@splincode splincode self-assigned this Apr 21, 2023
@splincode splincode added P2 This issue has medium priority S1 This issue has high severity and removed P3 This issue has low priority labels Apr 21, 2023
@splincode splincode removed their assignment May 11, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
contributions welcome Architecture is clear and community can help P2 This issue has medium priority S1 This issue has high severity
Development

Successfully merging a pull request may close this issue.

3 participants