module Duckling.CreditCardNumber.Helpers
( otherCreditCardNumberRegex
, visaCreditCardNumberRegex
, amexCreditCardNumberRegex
, discoverCreditCardNumberRegex
, mastercardCreditCardNumberRegex
, dinerClubCreditCardNumberRegex
, isValidCreditCardNumber
, minNumberDigits
, maxNumberDigits
, creditCard
) where
import Data.Text (Text)
import Prelude
import Data.String
import Duckling.CreditCardNumber.Types (CreditCardNumberData(..))
import qualified Duckling.CreditCardNumber.Types as TCreditCardNumber
import qualified Data.Text as T
import qualified Data.Char as C
import qualified Data.Bits as B
otherCreditCardNumberRegex :: String
otherCreditCardNumberRegex :: String
otherCreditCardNumberRegex =
[String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [ String
"("
, String
"(?!" , String
visaCreditCardNumberRegex, String
")"
, String
"(?!" , String
amexCreditCardNumberRegex, String
")"
, String
"(?!" , String
discoverCreditCardNumberRegex, String
")"
, String
"(?!" , String
mastercardCreditCardNumberRegex, String
")"
, String
"(?!" , String
dinerClubCreditCardNumberRegex, String
")"
, String
"\\d{" , Int -> String
forall a. Show a => a -> String
show Int
minNumberDigits , String
"," , Int -> String
forall a. Show a => a -> String
show Int
maxNumberDigits , String
"}"
, String
")"
]
visaCreditCardNumberRegex :: String
visaCreditCardNumberRegex :: String
visaCreditCardNumberRegex = String
"(" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
withoutDashes String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"|" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
withDashes String -> String -> String
forall a. [a] -> [a] -> [a]
++String
")"
where
withoutDashes :: String
withoutDashes = String
"4[0-9]{15}"
withDashes :: String
withDashes = String
"4[0-9]{3}-[0-9]{4}-[0-9]{4}-[0-9]{4}"
amexCreditCardNumberRegex :: String
amexCreditCardNumberRegex :: String
amexCreditCardNumberRegex = String
"(" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
withoutDashes String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"|" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
withDashes String -> String -> String
forall a. [a] -> [a] -> [a]
++String
")"
where
withoutDashes :: String
withoutDashes = String
"3[47][0-9]{13}"
withDashes :: String
withDashes = String
"3[47][0-9]{2}-[0-9]{6}-[0-9]{5}"
discoverCreditCardNumberRegex :: String
discoverCreditCardNumberRegex :: String
discoverCreditCardNumberRegex = String
"(" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
withoutDashes String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"|" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
withDashes String -> String -> String
forall a. [a] -> [a] -> [a]
++String
")"
where
withoutDashes :: String
withoutDashes = String
"6(?:011|[45][0-9]{2})[0-9]{12}"
withDashes :: String
withDashes = String
"6(?:011|[45][0-9]{2})-[0-9]{4}-[0-9]{4}-[0-9]{4}"
mastercardCreditCardNumberRegex :: String
mastercardCreditCardNumberRegex :: String
mastercardCreditCardNumberRegex =
String
"(" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
withoutDashes String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"|" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
withDashes String -> String -> String
forall a. [a] -> [a] -> [a]
++String
")"
where
withoutDashes :: String
withoutDashes = String
"5[1-5][0-9]{14}"
withDashes :: String
withDashes = String
"5[1-5][0-9]{2}-[0-9]{4}-[0-9]{4}-[0-9]{4}"
dinerClubCreditCardNumberRegex :: String
dinerClubCreditCardNumberRegex :: String
dinerClubCreditCardNumberRegex = String
"(" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
withoutDashes String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"|" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
withDashes String -> String -> String
forall a. [a] -> [a] -> [a]
++String
")"
where
withoutDashes :: String
withoutDashes = String
"3(?:0[0-5]|[68][0-9])[0-9]{11}"
withDashes :: String
withDashes = String
"3(?:0[0-5]|[68][0-9])[0-9]-[0-9]{6}-[0-9]{4}"
isValidCreditCardNumber :: Text -> Bool
isValidCreditCardNumber :: Text -> Bool
isValidCreditCardNumber Text
ccNum =
Text -> Int
T.length Text
ccNum Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
minNumberDigits Bool -> Bool -> Bool
&&
Text -> Int
T.length Text
ccNum Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
maxNumberDigits Bool -> Bool -> Bool
&&
Bool
validCheckSum
where
validCheckSum :: Bool
validCheckSum :: Bool
validCheckSum =
(Char -> Bool) -> Text -> Bool
T.all Char -> Bool
C.isDigit Text
ccNum Bool -> Bool -> Bool
&&
(Int, Int) -> Int
forall a b. (a, b) -> a
fst ((Char -> (Int, Int) -> (Int, Int))
-> (Int, Int) -> Text -> (Int, Int)
forall a. (Char -> a -> a) -> a -> Text -> a
T.foldr Char -> (Int, Int) -> (Int, Int)
f (Int
0, Int
0) Text
ccNum) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`rem` Int
10 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0
where
f :: Char -> (Int, Int) -> (Int, Int)
f Char
char (Int
checksum, Int
e) =
let
val :: Int
val = Char -> Int
C.digitToInt Char
char
d :: Int
d = Int -> Int
forall p. (Ord p, Num p) => p -> p
sumDigits (Int -> Int -> Int
forall a. Bits a => a -> Int -> a
B.shift Int
val Int
e)
in (Int
checksum Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
d, Int
1 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
e)
sumDigits :: p -> p
sumDigits p
a
| p
a p -> p -> Bool
forall a. Ord a => a -> a -> Bool
> p
9 = p
a p -> p -> p
forall a. Num a => a -> a -> a
- p
9
| Bool
otherwise = p
a
minNumberDigits :: Int
minNumberDigits :: Int
minNumberDigits = Int
8
maxNumberDigits :: Int
maxNumberDigits :: Int
maxNumberDigits = Int
19
creditCard :: Text -> TCreditCardNumber.Issuer -> CreditCardNumberData
creditCard :: Text -> Issuer -> CreditCardNumberData
creditCard Text
ccNum Issuer
i =
CreditCardNumberData :: Text -> Issuer -> CreditCardNumberData
CreditCardNumberData { number :: Text
TCreditCardNumber.number = Text
ccNum
, issuer :: Issuer
TCreditCardNumber.issuer = Issuer
i
}