{-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE RecordWildCards #-} module Laskutin where import Control.Concurrent (threadDelay) import Control.Monad (forM_, forM) import Data.Csv (encodeByName) import Data.List.NonEmpty (nonEmpty) import Data.MIME (Address, renderAddresses) import Data.Maybe (catMaybes, mapMaybe) import Data.Text.Encoding (decodeUtf8) import System.Exit (exitFailure) import System.IO (stderr, hPutStrLn) import qualified Data.ByteString.Lazy as LBS import qualified Data.Text.IO as T import Laskutin.CSV import Laskutin.Email import Laskutin.Options import Laskutin.Types main :: IO () main = do Options {csv, command} <- parseOptions case command of Send sendOptions -> sendInvoicesMain csv sendOptions UpdateTable bankCsv -> updateTableMain csv bankCsv sendInvoicesMain :: FilePath -> SendOptions -> IO () sendInvoicesMain csvPath options@SendOptions {email, sendmail} = do invoices <- readInvoices csvPath options forM_ invoices $ \invoice@(address, _) -> do sendEmail sendmail $ uncurry (renderEmail [email]) invoice putStr "Lähetetty osoitteeseen: " T.putStrLn $ decodeUtf8 $ renderAddresses address threadDelay (3 * 1000 * 1000) updateTableMain :: FilePath -> FilePath -> IO () updateTableMain invoiceCsv transactionCsv = do (headers, csvInvoices) <- parseCsvFile invoiceCsv (_, csvTransactions) <- parseCsvFile transactionCsv let newInvoices = fmap (updateInvoices csvTransactions) csvInvoices LBS.writeFile invoiceCsv $ encodeByName headers newInvoices updateInvoices :: [CsvTransaction] -> CsvInvoice -> CsvInvoice updateInvoices transactions invoice@CsvInvoice {isPaid, reference} | isPaid = invoice | otherwise = invoice {isPaid = reference `elem` transactionReferences} where transactionReferences = catMaybes $ transactionReference <$> transactions transactionReference CsvTransaction {referenceOrMessage = Message _} = Nothing transactionReference CsvTransaction {referenceOrMessage = Reference ref} = Just ref readInvoices :: FilePath -> SendOptions -> IO [([Address], Invoice)] readInvoices csv SendOptions {account, recipient, subject, message, due} = do (_, csvInvoices) <- parseCsvFile csv forM csvInvoices $ \CsvInvoice {..} -> do invoiceRows <- maybe (hPutStrLn stderr ("No invoice rows in invoice") >> exitFailure) pure $ nonEmpty $ mapMaybe invoiceRowFromCsv rows pure ([invoiceRecipient], Invoice { rows = invoiceRows, ..})