From 86c8896ee69b068368b4ef9a4c3923285907c328 Mon Sep 17 00:00:00 2001 From: Rutger Broekhoff Date: Tue, 18 Mar 2025 15:29:27 +0100 Subject: Parsing ING statements (POC) --- app/Import/Ing/Shared.hs | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 app/Import/Ing/Shared.hs (limited to 'app/Import/Ing/Shared.hs') diff --git a/app/Import/Ing/Shared.hs b/app/Import/Ing/Shared.hs new file mode 100644 index 0000000..c70f225 --- /dev/null +++ b/app/Import/Ing/Shared.hs @@ -0,0 +1,47 @@ +module Import.Ing.Shared where + +import Data.Attoparsec.Text qualified as AP +import Data.Char (digitToInt, ord) +import Data.Csv qualified as C +import Data.Decimal (Decimal, DecimalRaw (Decimal), normalizeDecimal) +import Data.Iban (Iban, mkIban) +import Data.Text qualified as T +import Data.Time.Calendar (Day) +import Data.Time.Clock (UTCTime) +import Data.Time.Format (defaultTimeLocale, parseTimeM) +import Data.Time.Zones (TZ, localTimeToUTCTZ) + +data DebitCredit = Debit | Credit deriving (Show) + +readDecimal :: T.Text -> Either String Decimal +readDecimal = AP.parseOnly $ do + decPart <- AP.decimal + _ <- AP.char ',' + f1 <- AP.digit + f2 <- AP.digit + AP.endOfInput + let fracPart = fromIntegral $ digitToInt f1 * 10 + digitToInt f2 + return $ normalizeDecimal (Decimal 2 (decPart * 100 + fracPart)) + +scsvOptions :: C.DecodeOptions +scsvOptions = C.defaultDecodeOptions {C.decDelimiter = fromIntegral (ord ';')} + +eitherToCP :: Either String a -> C.Parser a +eitherToCP = either fail return + +decimalCP :: T.Text -> C.Parser Decimal +decimalCP = eitherToCP . readDecimal + +dateCP :: String -> T.Text -> C.Parser Day +dateCP fmt = parseTimeM False defaultTimeLocale fmt . T.unpack + +maybeCP :: (T.Text -> C.Parser a) -> T.Text -> C.Parser (Maybe a) +maybeCP p t = if T.null t then return Nothing else Just <$> p t + +ibanCP :: T.Text -> C.Parser Iban +ibanCP = eitherToCP . mkIban + +timestampCP :: String -> TZ -> T.Text -> C.Parser UTCTime +timestampCP fmt amsTz t = do + localTime <- parseTimeM False defaultTimeLocale fmt (T.unpack t) + return $ localTimeToUTCTZ amsTz localTime -- cgit v1.2.3