{-# LANGUAGE RecordWildCards #-}
module Web.CoinTracking.Imports
( writeImportDataToFile
, module Web.CoinTracking.Imports.Types
, coinTrackingCsvImport
, headerRow
, csvEncodingOptions
, coinTrackingXlsxImport
, writeXlsxHeader
, writeXlsxRow
) where
import Codec.Xlsx ( CellValue(..)
, DateBase(DateBase1900)
, Worksheet
, atSheet
, cellValueAt
, dateToNumber
, def
, fromXlsx
)
import Control.Lens ( (.~)
, (?~)
)
import Data.Char ( toLower )
import Data.Csv ( EncodeOptions(..)
, defaultEncodeOptions
, encodeWith
)
import Data.Foldable ( foldl' )
import Data.Function ( (&) )
import Data.Scientific ( toRealFloat )
import Data.Time ( zonedTimeToUTC )
import Data.Time.Clock.POSIX ( POSIXTime
, getPOSIXTime
)
import System.FilePath ( takeExtension )
import Web.CoinTracking.Imports.Types
import qualified Data.ByteString.Lazy as LBS
import qualified Data.ByteString.Lazy.Char8 as LBC
import qualified Data.Text as T
writeImportDataToFile :: FilePath -> [CTImportData] -> IO ()
writeImportDataToFile :: FilePath -> [CTImportData] -> IO ()
writeImportDataToFile FilePath
file [CTImportData]
xs = do
POSIXTime
currentTime <- IO POSIXTime
getPOSIXTime
let extension :: FilePath
extension = FilePath -> FilePath
takeExtension FilePath
file
output :: ByteString
output = if (Char -> Char) -> FilePath -> FilePath
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toLower FilePath
extension FilePath -> [FilePath] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [FilePath
".xlsx", FilePath
".xls"]
then POSIXTime -> [CTImportData] -> ByteString
coinTrackingXlsxImport POSIXTime
currentTime [CTImportData]
xs
else [CTImportData] -> ByteString
coinTrackingCsvImport [CTImportData]
xs
FilePath -> ByteString -> IO ()
LBC.writeFile FilePath
file ByteString
output
coinTrackingCsvImport :: [CTImportData] -> LBS.ByteString
coinTrackingCsvImport :: [CTImportData] -> ByteString
coinTrackingCsvImport = (ByteString
headerRow ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<>) (ByteString -> ByteString)
-> ([CTImportData] -> ByteString) -> [CTImportData] -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. EncodeOptions -> [CTImportData] -> ByteString
forall a. ToRecord a => EncodeOptions -> [a] -> ByteString
encodeWith EncodeOptions
csvEncodingOptions
headerRow :: LBS.ByteString
= EncodeOptions -> [[Text]] -> ByteString
forall a. ToRecord a => EncodeOptions -> [a] -> ByteString
encodeWith
EncodeOptions
csvEncodingOptions
[ [ Text
"Type" :: T.Text
, Text
"Buy"
, Text
"Cur."
, Text
"Sell"
, Text
"Cur."
, Text
"Fee"
, Text
"Cur."
, Text
"Exchange"
, Text
"Trade-Group"
, Text
"Comment"
, Text
"Date"
, Text
"Tx-ID"
, Text
"Buy Value in your Account Currency"
, Text
"Sell Value in your Account Currency"
]
]
csvEncodingOptions :: EncodeOptions
csvEncodingOptions :: EncodeOptions
csvEncodingOptions = EncodeOptions
defaultEncodeOptions { encUseCrLf :: Bool
encUseCrLf = Bool
False }
coinTrackingXlsxImport
:: POSIXTime
-> [CTImportData]
-> LBS.ByteString
coinTrackingXlsxImport :: POSIXTime -> [CTImportData] -> ByteString
coinTrackingXlsxImport POSIXTime
createdTime [CTImportData]
rows =
let sheet :: Worksheet
sheet = (Worksheet -> Int -> CTImportData -> Worksheet)
-> Worksheet -> [CTImportData] -> Worksheet
forall b a. (b -> Int -> a -> b) -> b -> [a] -> b
ixFoldl
(\Worksheet
sheet_ Int
rowNum CTImportData
row -> Worksheet -> Int -> CTImportData -> Worksheet
writeXlsxRow Worksheet
sheet_ (Int
rowNum Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
3) CTImportData
row)
(Worksheet -> Worksheet
writeXlsxHeader Worksheet
forall a. Default a => a
def)
[CTImportData]
rows
book :: Xlsx
book = Xlsx
forall a. Default a => a
def Xlsx -> (Xlsx -> Xlsx) -> Xlsx
forall a b. a -> (a -> b) -> b
& Text -> Lens' Xlsx (Maybe Worksheet)
atSheet Text
"Sheet1" ((Maybe Worksheet -> Identity (Maybe Worksheet))
-> Xlsx -> Identity Xlsx)
-> Worksheet -> Xlsx -> Xlsx
forall s t a b. ASetter s t a (Maybe b) -> b -> s -> t
?~ Worksheet
sheet
in POSIXTime -> Xlsx -> ByteString
fromXlsx POSIXTime
createdTime Xlsx
book
where
ixFoldl :: (b -> Int -> a -> b) -> b -> [a] -> b
ixFoldl :: (b -> Int -> a -> b) -> b -> [a] -> b
ixFoldl b -> Int -> a -> b
f b
initial =
(b, Int) -> b
forall a b. (a, b) -> a
fst ((b, Int) -> b) -> ([a] -> (b, Int)) -> [a] -> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((b, Int) -> a -> (b, Int)) -> (b, Int) -> [a] -> (b, Int)
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' (\(b
b, Int
i) a
a -> (b -> Int -> a -> b
f b
b Int
i a
a, Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)) (b
initial, Int
0)
writeXlsxHeader :: Worksheet -> Worksheet
Worksheet
sheet =
Worksheet
sheet
Worksheet -> (Worksheet -> Worksheet) -> Worksheet
forall a b. a -> (a -> b) -> b
& (Int, Int) -> Lens' Worksheet (Maybe CellValue)
cellValueAt (Int
1, Int
1)
((Maybe CellValue -> Identity (Maybe CellValue))
-> Worksheet -> Identity Worksheet)
-> CellValue -> Worksheet -> Worksheet
forall s t a b. ASetter s t a (Maybe b) -> b -> s -> t
?~ Text -> CellValue
CellText
Text
"CoinTracking Excel Import data (see docs: https://cointracking.info/import/import_xls/)"
Worksheet -> (Worksheet -> Worksheet) -> Worksheet
forall a b. a -> (a -> b) -> b
& Int -> Text -> Worksheet -> Worksheet
writeColumn Int
1 Text
"Type"
Worksheet -> (Worksheet -> Worksheet) -> Worksheet
forall a b. a -> (a -> b) -> b
& Int -> Text -> Worksheet -> Worksheet
writeColumn Int
2 Text
"Buy Amount"
Worksheet -> (Worksheet -> Worksheet) -> Worksheet
forall a b. a -> (a -> b) -> b
& Int -> Text -> Worksheet -> Worksheet
writeColumn Int
3 Text
"Buy Cur."
Worksheet -> (Worksheet -> Worksheet) -> Worksheet
forall a b. a -> (a -> b) -> b
& Int -> Text -> Worksheet -> Worksheet
writeColumn Int
4 Text
"Sell Amount"
Worksheet -> (Worksheet -> Worksheet) -> Worksheet
forall a b. a -> (a -> b) -> b
& Int -> Text -> Worksheet -> Worksheet
writeColumn Int
5 Text
"Sell Cur."
Worksheet -> (Worksheet -> Worksheet) -> Worksheet
forall a b. a -> (a -> b) -> b
& Int -> Text -> Worksheet -> Worksheet
writeColumn Int
6 Text
"Feel Amount"
Worksheet -> (Worksheet -> Worksheet) -> Worksheet
forall a b. a -> (a -> b) -> b
& Int -> Text -> Worksheet -> Worksheet
writeColumn Int
7 Text
"Fee Cur."
Worksheet -> (Worksheet -> Worksheet) -> Worksheet
forall a b. a -> (a -> b) -> b
& Int -> Text -> Worksheet -> Worksheet
writeColumn Int
8 Text
"Exchange"
Worksheet -> (Worksheet -> Worksheet) -> Worksheet
forall a b. a -> (a -> b) -> b
& Int -> Text -> Worksheet -> Worksheet
writeColumn Int
9 Text
"Trade Group"
Worksheet -> (Worksheet -> Worksheet) -> Worksheet
forall a b. a -> (a -> b) -> b
& Int -> Text -> Worksheet -> Worksheet
writeColumn Int
10 Text
"Comment"
Worksheet -> (Worksheet -> Worksheet) -> Worksheet
forall a b. a -> (a -> b) -> b
& Int -> Text -> Worksheet -> Worksheet
writeColumn Int
11 Text
"Date"
where
writeColumn :: Int -> T.Text -> Worksheet -> Worksheet
writeColumn :: Int -> Text -> Worksheet -> Worksheet
writeColumn Int
c Text
t Worksheet
s = Worksheet
s Worksheet -> (Worksheet -> Worksheet) -> Worksheet
forall a b. a -> (a -> b) -> b
& (Int, Int) -> Lens' Worksheet (Maybe CellValue)
cellValueAt (Int
2, Int
c) ((Maybe CellValue -> Identity (Maybe CellValue))
-> Worksheet -> Identity Worksheet)
-> CellValue -> Worksheet -> Worksheet
forall s t a b. ASetter s t a (Maybe b) -> b -> s -> t
?~ Text -> CellValue
CellText Text
t
writeXlsxRow :: Worksheet -> Int -> CTImportData -> Worksheet
writeXlsxRow :: Worksheet -> Int -> CTImportData -> Worksheet
writeXlsxRow Worksheet
sheet Int
row CTImportData {Maybe Amount
Text
ZonedTime
CTTransactionType
ctidSellValue :: CTImportData -> Maybe Amount
ctidBuyValue :: CTImportData -> Maybe Amount
ctidTradeId :: CTImportData -> Text
ctidDate :: CTImportData -> ZonedTime
ctidComment :: CTImportData -> Text
ctidGroup :: CTImportData -> Text
ctidExchange :: CTImportData -> Text
ctidFee :: CTImportData -> Maybe Amount
ctidSell :: CTImportData -> Maybe Amount
ctidBuy :: CTImportData -> Maybe Amount
ctidType :: CTImportData -> CTTransactionType
ctidSellValue :: Maybe Amount
ctidBuyValue :: Maybe Amount
ctidTradeId :: Text
ctidDate :: ZonedTime
ctidComment :: Text
ctidGroup :: Text
ctidExchange :: Text
ctidFee :: Maybe Amount
ctidSell :: Maybe Amount
ctidBuy :: Maybe Amount
ctidType :: CTTransactionType
..} =
Worksheet
sheet
Worksheet -> (Worksheet -> Worksheet) -> Worksheet
forall a b. a -> (a -> b) -> b
& ((Int, Int) -> Lens' Worksheet (Maybe CellValue)
cellValueAt (Int
row, Int
1) ((Maybe CellValue -> Identity (Maybe CellValue))
-> Worksheet -> Identity Worksheet)
-> CellValue -> Worksheet -> Worksheet
forall s t a b. ASetter s t a (Maybe b) -> b -> s -> t
?~ Text -> CellValue
CellText (CTTransactionType -> Text
forall a. IsString a => CTTransactionType -> a
renderTransactionType CTTransactionType
ctidType))
Worksheet -> (Worksheet -> Worksheet) -> Worksheet
forall a b. a -> (a -> b) -> b
& ((Int, Int) -> Lens' Worksheet (Maybe CellValue)
cellValueAt (Int
row, Int
2) ((Maybe CellValue -> Identity (Maybe CellValue))
-> Worksheet -> Identity Worksheet)
-> Maybe CellValue -> Worksheet -> Worksheet
forall s t a b. ASetter s t a b -> b -> s -> t
.~ Maybe Amount -> Maybe CellValue
renderAmount Maybe Amount
ctidBuy)
Worksheet -> (Worksheet -> Worksheet) -> Worksheet
forall a b. a -> (a -> b) -> b
& ((Int, Int) -> Lens' Worksheet (Maybe CellValue)
cellValueAt (Int
row, Int
3) ((Maybe CellValue -> Identity (Maybe CellValue))
-> Worksheet -> Identity Worksheet)
-> Maybe CellValue -> Worksheet -> Worksheet
forall s t a b. ASetter s t a b -> b -> s -> t
.~ Maybe Amount -> Maybe CellValue
renderCurrency Maybe Amount
ctidBuy)
Worksheet -> (Worksheet -> Worksheet) -> Worksheet
forall a b. a -> (a -> b) -> b
& ((Int, Int) -> Lens' Worksheet (Maybe CellValue)
cellValueAt (Int
row, Int
4) ((Maybe CellValue -> Identity (Maybe CellValue))
-> Worksheet -> Identity Worksheet)
-> Maybe CellValue -> Worksheet -> Worksheet
forall s t a b. ASetter s t a b -> b -> s -> t
.~ Maybe Amount -> Maybe CellValue
renderAmount Maybe Amount
ctidSell)
Worksheet -> (Worksheet -> Worksheet) -> Worksheet
forall a b. a -> (a -> b) -> b
& ((Int, Int) -> Lens' Worksheet (Maybe CellValue)
cellValueAt (Int
row, Int
5) ((Maybe CellValue -> Identity (Maybe CellValue))
-> Worksheet -> Identity Worksheet)
-> Maybe CellValue -> Worksheet -> Worksheet
forall s t a b. ASetter s t a b -> b -> s -> t
.~ Maybe Amount -> Maybe CellValue
renderCurrency Maybe Amount
ctidSell)
Worksheet -> (Worksheet -> Worksheet) -> Worksheet
forall a b. a -> (a -> b) -> b
& ((Int, Int) -> Lens' Worksheet (Maybe CellValue)
cellValueAt (Int
row, Int
6) ((Maybe CellValue -> Identity (Maybe CellValue))
-> Worksheet -> Identity Worksheet)
-> Maybe CellValue -> Worksheet -> Worksheet
forall s t a b. ASetter s t a b -> b -> s -> t
.~ Maybe Amount -> Maybe CellValue
renderAmount Maybe Amount
ctidFee)
Worksheet -> (Worksheet -> Worksheet) -> Worksheet
forall a b. a -> (a -> b) -> b
& ((Int, Int) -> Lens' Worksheet (Maybe CellValue)
cellValueAt (Int
row, Int
7) ((Maybe CellValue -> Identity (Maybe CellValue))
-> Worksheet -> Identity Worksheet)
-> Maybe CellValue -> Worksheet -> Worksheet
forall s t a b. ASetter s t a b -> b -> s -> t
.~ Maybe Amount -> Maybe CellValue
renderCurrency Maybe Amount
ctidFee)
Worksheet -> (Worksheet -> Worksheet) -> Worksheet
forall a b. a -> (a -> b) -> b
& ((Int, Int) -> Lens' Worksheet (Maybe CellValue)
cellValueAt (Int
row, Int
8) ((Maybe CellValue -> Identity (Maybe CellValue))
-> Worksheet -> Identity Worksheet)
-> CellValue -> Worksheet -> Worksheet
forall s t a b. ASetter s t a (Maybe b) -> b -> s -> t
?~ Text -> CellValue
CellText Text
ctidExchange)
Worksheet -> (Worksheet -> Worksheet) -> Worksheet
forall a b. a -> (a -> b) -> b
& ((Int, Int) -> Lens' Worksheet (Maybe CellValue)
cellValueAt (Int
row, Int
9) ((Maybe CellValue -> Identity (Maybe CellValue))
-> Worksheet -> Identity Worksheet)
-> CellValue -> Worksheet -> Worksheet
forall s t a b. ASetter s t a (Maybe b) -> b -> s -> t
?~ Text -> CellValue
CellText Text
ctidGroup)
Worksheet -> (Worksheet -> Worksheet) -> Worksheet
forall a b. a -> (a -> b) -> b
& ((Int, Int) -> Lens' Worksheet (Maybe CellValue)
cellValueAt (Int
row, Int
10) ((Maybe CellValue -> Identity (Maybe CellValue))
-> Worksheet -> Identity Worksheet)
-> CellValue -> Worksheet -> Worksheet
forall s t a b. ASetter s t a (Maybe b) -> b -> s -> t
?~ Text -> CellValue
CellText Text
ctidComment)
Worksheet -> (Worksheet -> Worksheet) -> Worksheet
forall a b. a -> (a -> b) -> b
& ((Int, Int) -> Lens' Worksheet (Maybe CellValue)
cellValueAt (Int
row, Int
11) ((Maybe CellValue -> Identity (Maybe CellValue))
-> Worksheet -> Identity Worksheet)
-> CellValue -> Worksheet -> Worksheet
forall s t a b. ASetter s t a (Maybe b) -> b -> s -> t
?~ CellValue
renderedDate)
where
renderAmount :: Maybe Amount -> Maybe CellValue
renderAmount :: Maybe Amount -> Maybe CellValue
renderAmount = (Amount -> CellValue) -> Maybe Amount -> Maybe CellValue
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Double -> CellValue
CellDouble (Double -> CellValue) -> (Amount -> Double) -> Amount -> CellValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Scientific -> Double
forall a. RealFloat a => Scientific -> a
toRealFloat (Scientific -> Double)
-> (Amount -> Scientific) -> Amount -> Double
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Amount -> Scientific
aAmount)
renderCurrency :: Maybe Amount -> Maybe CellValue
renderCurrency :: Maybe Amount -> Maybe CellValue
renderCurrency = (Amount -> CellValue) -> Maybe Amount -> Maybe CellValue
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Text -> CellValue
CellText (Text -> CellValue) -> (Amount -> Text) -> Amount -> CellValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Currency -> Text
cTicker (Currency -> Text) -> (Amount -> Currency) -> Amount -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Amount -> Currency
aCurrency)
renderedDate :: CellValue
renderedDate :: CellValue
renderedDate =
Double -> CellValue
CellDouble (Double -> CellValue) -> Double -> CellValue
forall a b. (a -> b) -> a -> b
$ DateBase -> UTCTime -> Double
forall a. Fractional a => DateBase -> UTCTime -> a
dateToNumber DateBase
DateBase1900 (UTCTime -> Double) -> UTCTime -> Double
forall a b. (a -> b) -> a -> b
$ ZonedTime -> UTCTime
zonedTimeToUTC ZonedTime
ctidDate