From 5493329b2eed7e151f4a323c108caad2253b08bb Mon Sep 17 00:00:00 2001 From: Rutger Broekhoff Date: Sat, 22 Mar 2025 14:52:35 +0100 Subject: Refactor parser for current account statement --- app/Import/Ing/CurrentAccountCsv.hs | 44 ++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 22 deletions(-) (limited to 'app/Import/Ing/CurrentAccountCsv.hs') diff --git a/app/Import/Ing/CurrentAccountCsv.hs b/app/Import/Ing/CurrentAccountCsv.hs index bf28730..1456be1 100644 --- a/app/Import/Ing/CurrentAccountCsv.hs +++ b/app/Import/Ing/CurrentAccountCsv.hs @@ -17,12 +17,12 @@ import Data.Time.Zones (TZ, loadTZFromDB) import Data.Vector qualified as V import Import.Ing.Shared ( DebitCredit (Credit, Debit), - dateCP, - decimalCP, - ibanCP, maybeCP, + parseDateM, + parseDecimalM, + parseIbanM, + parseTimestampM, scsvOptions, - timestampCP, ) import System.IO (Handle) import Text.Regex.TDFA ((=~~)) @@ -155,7 +155,7 @@ maybeNotProvided :: T.Text -> Maybe T.Text maybeNotProvided t = if t == "NOTPROVIDED" then Nothing else Just t valueDateCP :: T.Text -> C.Parser Day -valueDateCP = dateCP "%d/%m/%Y" +valueDateCP = parseDateM "%d/%m/%Y" data PartTx = PartTx !Day !TransactionType !DebitCredit @@ -163,7 +163,7 @@ notificationsCP :: TZ -> PartTx -> T.Text -> C.Parser MoreData notificationsCP _ (PartTx _ Transfer Credit) t = do let regex = "^Name: (.*) Description: (.*) IBAN: ([A-Z0-9]+) Reference: (.*) Value date: ([0-9]{2}/[0-9]{2}/[0-9]{4})$" :: String (_, _, _, [name, desc, ibanTxt, ref, valDateTxt]) <- t =~~ regex :: C.Parser (T.Text, T.Text, T.Text, [T.Text]) - iban <- ibanCP ibanTxt + iban <- parseIbanM ibanTxt valDate <- valueDateCP valDateTxt return $ DepositTransferData @@ -185,7 +185,7 @@ notificationsCP _ (PartTx _ Transfer Debit) t = do notificationsCP amsTz (PartTx _ PaymentTerminal Debit) t = do let regex = "^Card sequence no.: ([0-9]+) ? ([0-9]{2}/[0-9]{2}/[0-9]{4} [0-9]{2}:[0-9]{2}) Transaction: (.*) Term: ((.+) Google Pay|(.+)) Value date: ([0-9]{2}/[0-9]{2}/[0-9]{4})$" :: String (_, _, _, [cardSeqNo, timestampTxt, transaction, _, gpayTerm, noGpayTerm, valDateTxt]) <- t =~~ regex :: C.Parser (T.Text, T.Text, T.Text, [T.Text]) - timestamp <- timestampCP "%d/%m/%Y %H:%M" amsTz timestampTxt + timestamp <- parseTimestampM "%d/%m/%Y %H:%M" amsTz timestampTxt valDate <- valueDateCP valDateTxt return $ PaymentTerminalData @@ -199,7 +199,7 @@ notificationsCP amsTz (PartTx _ PaymentTerminal Debit) t = do notificationsCP amsTz (PartTx _ PaymentTerminal Credit) t = do let regex = "^Card sequence no.: ([0-9]+) ? ([0-9]{2}/[0-9]{2}/[0-9]{4} [0-9]{2}:[0-9]{2}) Transaction: (.*) Term: (.*) Cashback transaction Value date: ([0-9]{2}/[0-9]{2}/[0-9]{4})$" :: String (_, _, _, [cardSeqNo, timestampTxt, transaction, term, valDateTxt]) <- t =~~ regex :: C.Parser (T.Text, T.Text, T.Text, [T.Text]) - timestamp <- timestampCP "%d/%m/%Y %H:%M" amsTz timestampTxt + timestamp <- parseTimestampM "%d/%m/%Y %H:%M" amsTz timestampTxt valDate <- valueDateCP valDateTxt return $ PaymentTerminalCashbackData @@ -212,8 +212,8 @@ notificationsCP amsTz (PartTx _ PaymentTerminal Credit) t = do notificationsCP amsTz (PartTx _ OnlineBanking Credit) t = do let regex = "^Name: (.*) Description: (.*) IBAN: ([A-Z0-9]+) Date/time: ([0-9]{2}-[0-9]{2}-[0-9]{4} [0-9]{2}:[0-9]{2}:[0-9]{2}) Value date: ([0-9]{2}/[0-9]{2}/[0-9]{4})$" :: String (_, _, _, [name, desc, ibanTxt, timestampTxt, valDateTxt]) <- t =~~ regex :: C.Parser (T.Text, T.Text, T.Text, [T.Text]) - iban <- ibanCP ibanTxt - timestamp <- timestampCP "%d-%m-%Y %H:%M:%S" amsTz timestampTxt + iban <- parseIbanM ibanTxt + timestamp <- parseTimestampM "%d-%m-%Y %H:%M:%S" amsTz timestampTxt valDate <- valueDateCP valDateTxt return $ OnlineBankingCredit @@ -226,11 +226,11 @@ notificationsCP amsTz (PartTx _ OnlineBanking Credit) t = do notificationsCP amsTz (PartTx _ OnlineBanking Debit) t = do let regex = "^Name: (.*) Description: (.*) IBAN: ([A-Z0-9]+) (Date/time: ([0-9]{2}-[0-9]{2}-[0-9]{4} [0-9]{2}:[0-9]{2}:[0-9]{2}) )?Value date: ([0-9]{2}/[0-9]{2}/[0-9]{4})$" :: String (_, _, _, [name, desc, ibanTxt, _, timestampTxt, valDateTxt]) <- t =~~ regex :: C.Parser (T.Text, T.Text, T.Text, [T.Text]) - iban <- ibanCP ibanTxt + iban <- parseIbanM ibanTxt timestamp <- if T.null timestampTxt then pure Nothing - else Just <$> timestampCP "%d-%m-%Y %H:%M:%S" amsTz timestampTxt + else Just <$> parseTimestampM "%d-%m-%Y %H:%M:%S" amsTz timestampTxt valDate <- valueDateCP valDateTxt return $ OnlineBankingDebit @@ -245,7 +245,7 @@ notificationsCP _ (PartTx date DirectDebit Debit) t = normalRecurrentDirectDebit normalRecurrentDirectDebit = do let regex = "^Name: (.*) Description: (.*) IBAN: ([A-Z0-9]+) Reference: (.*) Mandate ID: (.*) Creditor ID: (.*) Recurrent SEPA direct debit (Other party: (.*) )?Value date: ([0-9]{2}/[0-9]{2}/[0-9]{4})$" :: String (_, _, _, [name, desc, ibanTxt, ref, mandateId, creditorId, _, otherParty, valDateTxt]) <- t =~~ regex :: C.Parser (T.Text, T.Text, T.Text, [T.Text]) - iban <- ibanCP ibanTxt + iban <- parseIbanM ibanTxt valDate <- valueDateCP valDateTxt return $ RecurrentDirectDebitData @@ -261,7 +261,7 @@ notificationsCP _ (PartTx date DirectDebit Debit) t = normalRecurrentDirectDebit ingInsurancePayment = do let regex = "^Name: (.* ING Verzekeren) Description: (.*) IBAN: ([A-Z0-9]+) Reference: (.*) Mandate ID: (.*) Creditor ID: (.*) Recurrent SEPA direct debit$" :: String (_, _, _, [name, desc, ibanTxt, ref, mandateId, creditorId]) <- t =~~ regex :: C.Parser (T.Text, T.Text, T.Text, [T.Text]) - iban <- ibanCP ibanTxt + iban <- parseIbanM ibanTxt return $ RecurrentDirectDebitData { rddName = name, @@ -276,8 +276,8 @@ notificationsCP _ (PartTx date DirectDebit Debit) t = normalRecurrentDirectDebit notificationsCP amsTz (PartTx _ Ideal Debit) t = do let regex = "^Name: (.*) Description: (.*) IBAN: ([A-Z0-9]+) Reference: ([0-9]{2}-[0-9]{2}-[0-9]{4} [0-9]{2}:[0-9]{2}) ([0-9]+) Value date: ([0-9]{2}/[0-9]{2}/[0-9]{4})$" :: String (_, _, _, [name, desc, ibanTxt, timestampTxt, ref, valDateTxt]) <- t =~~ regex :: C.Parser (T.Text, T.Text, T.Text, [T.Text]) - iban <- ibanCP ibanTxt - timestamp <- timestampCP "%d-%m-%Y %H:%M" amsTz timestampTxt + iban <- parseIbanM ibanTxt + timestamp <- parseTimestampM "%d-%m-%Y %H:%M" amsTz timestampTxt valDate <- valueDateCP valDateTxt return $ IdealDebitData @@ -291,7 +291,7 @@ notificationsCP amsTz (PartTx _ Ideal Debit) t = do notificationsCP _ (PartTx _ BatchPayment Credit) t = do let regex = "^Name: (.*) Description: (.*) IBAN: ([A-Z0-9]+) Reference: (.*) Value date: ([0-9]{2}/[0-9]{2}/[0-9]{4})$" :: String (_, _, _, [name, desc, ibanTxt, ref, valDateTxt]) <- t =~~ regex :: C.Parser (T.Text, T.Text, T.Text, [T.Text]) - iban <- ibanCP ibanTxt + iban <- parseIbanM ibanTxt valDate <- valueDateCP valDateTxt return $ BatchPaymentData @@ -310,7 +310,7 @@ debitCreditCP t = fail ("Unknown debit/credit value '" ++ T.unpack t ++ "'") parseNamedRecord :: TZ -> C.NamedRecord -> C.Parser PrimTx parseNamedRecord amsTz m = do - date <- m .: "Date" >>= dateCP "%0Y%m%d" + date <- m .: "Date" >>= parseDateM "%0Y%m%d" debitCredit <- m .: "Debit/credit" >>= debitCreditCP codeText <- m .: "Code" tyText <- m .: "Transaction type" @@ -322,11 +322,11 @@ parseNamedRecord amsTz m = do else PrimTx date <$> (m .: "Name / Description" <&> maybeNotProvided) - <*> (m .: "Account" >>= ibanCP) - <*> (m .: "Counterparty" >>= maybeCP ibanCP) + <*> (m .: "Account" >>= parseIbanM) + <*> (m .: "Counterparty" >>= maybeCP parseIbanM) <*> pure debitCredit - <*> (m .: "Amount (EUR)" >>= decimalCP) - <*> (m .: "Resulting balance" >>= decimalCP) + <*> (m .: "Amount (EUR)" >>= parseDecimalM) + <*> (m .: "Resulting balance" >>= parseDecimalM) <*> m .: "Tag" <*> (m .: "Notifications" >>= notificationsCP amsTz (PartTx date ty debitCredit)) -- cgit v1.2.3