diff options
author | Rutger Broekhoff | 2025-03-18 15:29:27 +0100 |
---|---|---|
committer | Rutger Broekhoff | 2025-03-18 15:31:11 +0100 |
commit | 86c8896ee69b068368b4ef9a4c3923285907c328 (patch) | |
tree | dc6e4f58a511c58e2910e9f7ea900165da7d47c6 /app/Import/Ing/Shared.hs | |
download | rdcapsis-86c8896ee69b068368b4ef9a4c3923285907c328.tar.gz rdcapsis-86c8896ee69b068368b4ef9a4c3923285907c328.zip |
Parsing ING statements (POC)
Diffstat (limited to 'app/Import/Ing/Shared.hs')
-rw-r--r-- | app/Import/Ing/Shared.hs | 47 |
1 files changed, 47 insertions, 0 deletions
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 @@ | |||
1 | module Import.Ing.Shared where | ||
2 | |||
3 | import Data.Attoparsec.Text qualified as AP | ||
4 | import Data.Char (digitToInt, ord) | ||
5 | import Data.Csv qualified as C | ||
6 | import Data.Decimal (Decimal, DecimalRaw (Decimal), normalizeDecimal) | ||
7 | import Data.Iban (Iban, mkIban) | ||
8 | import Data.Text qualified as T | ||
9 | import Data.Time.Calendar (Day) | ||
10 | import Data.Time.Clock (UTCTime) | ||
11 | import Data.Time.Format (defaultTimeLocale, parseTimeM) | ||
12 | import Data.Time.Zones (TZ, localTimeToUTCTZ) | ||
13 | |||
14 | data DebitCredit = Debit | Credit deriving (Show) | ||
15 | |||
16 | readDecimal :: T.Text -> Either String Decimal | ||
17 | readDecimal = AP.parseOnly $ do | ||
18 | decPart <- AP.decimal | ||
19 | _ <- AP.char ',' | ||
20 | f1 <- AP.digit | ||
21 | f2 <- AP.digit | ||
22 | AP.endOfInput | ||
23 | let fracPart = fromIntegral $ digitToInt f1 * 10 + digitToInt f2 | ||
24 | return $ normalizeDecimal (Decimal 2 (decPart * 100 + fracPart)) | ||
25 | |||
26 | scsvOptions :: C.DecodeOptions | ||
27 | scsvOptions = C.defaultDecodeOptions {C.decDelimiter = fromIntegral (ord ';')} | ||
28 | |||
29 | eitherToCP :: Either String a -> C.Parser a | ||
30 | eitherToCP = either fail return | ||
31 | |||
32 | decimalCP :: T.Text -> C.Parser Decimal | ||
33 | decimalCP = eitherToCP . readDecimal | ||
34 | |||
35 | dateCP :: String -> T.Text -> C.Parser Day | ||
36 | dateCP fmt = parseTimeM False defaultTimeLocale fmt . T.unpack | ||
37 | |||
38 | maybeCP :: (T.Text -> C.Parser a) -> T.Text -> C.Parser (Maybe a) | ||
39 | maybeCP p t = if T.null t then return Nothing else Just <$> p t | ||
40 | |||
41 | ibanCP :: T.Text -> C.Parser Iban | ||
42 | ibanCP = eitherToCP . mkIban | ||
43 | |||
44 | timestampCP :: String -> TZ -> T.Text -> C.Parser UTCTime | ||
45 | timestampCP fmt amsTz t = do | ||
46 | localTime <- parseTimeM False defaultTimeLocale fmt (T.unpack t) | ||
47 | return $ localTimeToUTCTZ amsTz localTime | ||