This is an alternative site for discovering Elm packages. You may be looking for the official Elm package site instead.
1.0.0 1.0.1
README

Payment.CreditCard.Validation

This library can be used to validate a credit card number. It implements the Luhn algorithm which checks for the checksum of the card. In general it works with credit card numbers of all types (Visa, Mastercard, Maestro, American Express, ...).

Behind the scenes it transforms the given number into a list of strings to create single digits. This implementation may change in future. API will stay as is.

The main use case is the validation of credit card numbers entered by users in an input field. To avoid dependencies to parser libraries there is no function with the signature of String -> Bool.

Definition

isValid : String -> Bool

Check the given credit card number for validity

module Payment.CreditCard.Validation exposing (isValid)

{-| This library can be used to validate a credit card number. It implements
the Luhn algorithm which checks for the checksum of the card. In general it
works with credit card numbers of all types (Visa, Mastercard, Maestro,
American Express, ...).

Behind the scenes it transforms the given number into a list of strings to
create single digits. This implementation may change in future. API will stay
as is.

The main use case is the validation of credit card numbers entered by users in
an input field. To avoid dependencies to parser libraries there is no
function with the signature of String -> Bool.


# Definition

@docs isValid

-}

import String exposing (toInt, toList, fromList)
import Regex


{-| Check the given credit card number for validity
-}
isValid : String -> Bool
isValid input =
  Just input
    |> Maybe.andThen isNumber
    |> Maybe.andThen checkLength
    |> Maybe.andThen checkLuhn
    |> Maybe.withDefault False


isNumber : String -> Maybe String
isNumber input =
  let
    regexRule =
      Regex.regex "^[\\d]+$"
  in
    if
      Regex.find Regex.All regexRule input
        |> List.isEmpty
    then
      Nothing
    else
      Just input


checkLength : String -> Maybe String
checkLength input =
  if input /= "" && String.length input <= 19 then
    Just input
  else
    Nothing


checkLuhn : String -> Maybe Bool
checkLuhn input =
  let
    lastDigit =
      input
        |> String.right 1
        |> parseInt

    dropLastAndReverse =
      List.reverse >> List.tail

    multiplyOdds =
      List.indexedMap
        (\i item ->
          if i % 2 == 0 then
            let
              result =
                (parseInt item) * 2
            in
              if result > 9 then
                result - 9
              else
                result
          else
            parseInt item
        )

    checkSumMod n =
      10 - (n % 10) == lastDigit
  in
    input
      |> String.split ""
      |> dropLastAndReverse
      |> Maybe.map multiplyOdds
      |> Maybe.map List.sum
      |> Maybe.map checkSumMod



-- Simple parseInt helper (since we rely on the Int -> Bool signature for input)


parseInt : String -> Int
parseInt input =
  Result.withDefault 0 (String.toInt input)