laskutin/src/Laskutin.hs

63 lines
2.5 KiB
Haskell

{-# 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, ..})