bookkeeping (empty) → 0.1.0.1
raw patch · 7 files changed
+360/−0 lines, 7 filesdep +Globdep +basedep +bookkeepingsetup-changed
Dependencies added: Glob, base, bookkeeping, dlist, doctest, mtl, text, time
Files
- LICENSE +21/−0
- README.md +13/−0
- Setup.hs +2/−0
- bookkeeping.cabal +54/−0
- src/Business/Bookkeeping.hs +249/−0
- test/Doctest.hs +19/−0
- test/Spec.hs +2/−0
+ LICENSE view
@@ -0,0 +1,21 @@+MIT License++Copyright (c) 2017 Kadzuya OKAMOTO, http://www.arow.info++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in all+copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+SOFTWARE.
+ README.md view
@@ -0,0 +1,13 @@+[](https://travis-ci.org/arowM/heterocephalus)++# Haskell-bookkeeping++A module for bookkeeping by double entry. This module provides a way to do bookkeeping programmatically.++## Example++TODO++## Export as CSV++TODO
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ bookkeeping.cabal view
@@ -0,0 +1,54 @@+name: bookkeeping+version: 0.1.0.1+synopsis: A module for bookkeeping by double entry.+description:+ A module for bookkeeping by double entry. This module provides a way to do bookkeeping programmatically.+homepage: https://github.com/arowM/haskell-bookkeeping#readme+license: MIT+license-file: LICENSE+author: Kadzuya Okamoto+maintainer: arow.okamoto+github@gmail.com+copyright: 2017 Kadzuya Okamoto+category: Business+build-type: Simple+extra-source-files: README.md+cabal-version: >=1.10++library+ hs-source-dirs: src+ exposed-modules: Business.Bookkeeping+ build-depends: base >= 4.9 && < 4.10+ , dlist >= 0.8.0.2 && < 0.9+ , mtl >= 2.2.1 && < 2.3+ , text >= 1.2.2.1 && < 1.3+ , time >= 1.6.0.1 && < 1.7+ default-language: Haskell2010+ default-extensions: OverloadedStrings+ , RecordWildCards+ , Strict+ , StrictData+ other-extensions: GeneralizedNewtypeDeriving++test-suite bookkeeping-test+ type: exitcode-stdio-1.0+ hs-source-dirs: test+ main-is: Spec.hs+ build-depends: base+ , bookkeeping+ ghc-options: -threaded -rtsopts -with-rtsopts=-N+ default-language: Haskell2010++test-suite doctest+ type: exitcode-stdio-1.0+ hs-source-dirs: test+ main-is: Doctest.hs+ build-depends: base+ , Glob+ , doctest >= 0.10+ , bookkeeping+ ghc-options: -threaded -rtsopts -with-rtsopts=-N+ default-language: Haskell2010++source-repository head+ type: git+ location: https://github.com/arowM/haskell-bookkeeping
+ src/Business/Bookkeeping.hs view
@@ -0,0 +1,249 @@+{-# LANGUAGE GeneralizedNewtypeDeriving #-}++{- |+Module : Business.Bookkeeping++Copyright : Kadzuya Okamoto 2017+License : MIT++Stability : experimental+Portability : unknown++This module exports core functions and types for bookkeeping.+-}+module Business.Bookkeeping+ (+ -- * Usage examples+ -- $setup++ -- * Pritty printers+ ppr++ -- * Constructors+ , year+ , month+ , activity+ , dateTrans++ -- * Converters+ , runTransactions++ -- * Types+ , Transactions+ , YearTransactions+ , MonthTransactions+ , DateTransactions+ , Transaction(..)+ , Year(..)+ , Month(..)+ , Date(..)+ , Description(..)+ , Amount(..)+ , Category(..)+ , CategoryName(..)+ , CategoryType(..)+ , DebitCategory(..)+ , CreditCategory(..)+ ) where++import Control.Monad.State (State, execState, modify)+import qualified Data.DList as DList+import Data.DList (DList)+import Data.Monoid ((<>))+import Data.String (IsString(..))+import Data.Text (Text)+import qualified Data.Text as T+import qualified Data.Text.IO as T+import Data.Time.Calendar (Day, fromGregorian)++{- $setup+>>> :{+let+ advance :: CategoryName -> Description -> Amount -> DateTransactions+ advance name = dateTrans+ (DebitCategory $ Category name Expenses)+ (CreditCategory $ Category "Deposit" Assets)+ sample =+ year 2015 $ do+ month 1 $ do+ activity 1 "Constant expenses --" $+ advance "Communication" "Mobile phone" 3000+ activity 3 "Mail a contract --" $ do+ advance "Communication" "Stamp" 50+ advance "Office supplies" "Envelope" 100+ month 2 $+ activity 1 "Constant expenses --" $+ advance "Communication" "Mobile phone" 3000+:}+-}+{-| Convert from 'YearTransactions' to 'Transactions'.+-}+year :: Year -> YearTransactions -> Transactions+year y =+ modify . flip mappend . fmap ($ y) . toDList++{-| Convert from 'MonthTransactions' to 'YearTransactions'.+-}+month :: Month -> MonthTransactions -> YearTransactions+month m =+ modify . flip mappend . fmap ($ m) . toDList++{-| Convert from 'DateTransactions' to 'MonthTransactions'.+-}+activity :: Date -> Description -> DateTransactions -> MonthTransactions+activity d desc =+ modify . flip mappend . fmap (($ desc) . ($ d)) . toDList++dateTrans :: DebitCategory+ -> CreditCategory+ -> Description+ -> Amount+ -> DateTransactions+dateTrans debit credit desc amount =+ modify . flip mappend . DList.singleton $ \d desc' m y ->+ Transaction+ { tDay = fromGregorian (unYear y) (unMonth m) (unDate d)+ , tDescription = desc' <> " " <> desc+ , tDebit = debit+ , tCredit = credit+ , tAmount = amount+ }++{-| Take list of `Transaction` out from 'Transactions'.+-}+runTransactions :: Transactions -> [Transaction]+runTransactions = DList.toList . toDList++toDList :: Trans a -> DList a+toDList ts = execState ts mempty++{-| A pretty printer for `Transactions`.++>>> ppr sample+tDay: 2015-01-01+tDescription: Constant expenses -- Mobile phone+tDebit: Communication (Expenses)+tCredit: Deposit (Assets)+tAmount: 3000+<BLANKLINE>+tDay: 2015-01-03+tDescription: Mail a contract -- Stamp+tDebit: Communication (Expenses)+tCredit: Deposit (Assets)+tAmount: 50+<BLANKLINE>+tDay: 2015-01-03+tDescription: Mail a contract -- Envelope+tDebit: Office supplies (Expenses)+tCredit: Deposit (Assets)+tAmount: 100+<BLANKLINE>+tDay: 2015-02-01+tDescription: Constant expenses -- Mobile phone+tDebit: Communication (Expenses)+tCredit: Deposit (Assets)+tAmount: 3000+<BLANKLINE>+-}+ppr :: Transactions -> IO ()+ppr = T.putStr . T.unlines . map format . runTransactions+ where+ format :: Transaction -> T.Text+ format Transaction {..} =+ T.unlines+ [ "tDay: " <> (T.pack . show) tDay+ , "tDescription: " <> unDescription tDescription+ , "tDebit: " <> (unCategoryName . cName . unDebitCategory) tDebit <>+ " (" <>+ (T.pack . show . cType . unDebitCategory) tDebit <>+ ")"+ , "tCredit: " <> (unCategoryName . cName . unCreditCategory) tCredit <>+ " (" <>+ (T.pack . show . cType . unCreditCategory) tCredit <>+ ")"+ , "tAmount: " <> (T.pack . show . unAmount) tAmount+ ]+++{- ==============+ - Types+ - ============== -}++type Trans a = State (DList a) ()++{-| A type for handling `Transaction` values.+ -}+type Transactions = Trans Transaction++type YearTransactions = Trans (Year -> Transaction)++type MonthTransactions = Trans (Month -> Year -> Transaction)++type DateTransactions = Trans (Date -> Description -> Month -> Year -> Transaction)++{-| A type representing a transaction.+ -}+data Transaction = Transaction+ { tDay :: Day+ , tDescription :: Description+ , tDebit :: DebitCategory+ , tCredit :: CreditCategory+ , tAmount :: Amount+ } deriving (Show, Read, Ord, Eq)++newtype Year = Year+ { unYear :: Integer+ } deriving (Show, Read, Ord, Eq, Num)++newtype Month = Month+ { unMonth :: Int+ } deriving (Show, Read, Ord, Eq, Num)++newtype Date = Date+ { unDate :: Int+ } deriving (Show, Read, Ord, Eq, Num)++newtype Description = Description+ { unDescription :: Text+ } deriving (Show, Read, Ord, Eq)++instance IsString Description where+ fromString = Description . fromString++instance Monoid Description where+ mempty = Description mempty+ mappend (Description a) (Description b) = Description $ mappend a b++newtype Amount = Amount+ { unAmount :: Int+ } deriving (Show, Read, Ord, Eq, Num)++newtype DebitCategory = DebitCategory+ { unDebitCategory :: Category+ } deriving (Show, Read, Ord, Eq)++newtype CreditCategory = CreditCategory+ { unCreditCategory :: Category+ } deriving (Show, Read, Ord, Eq)++{-| A type representing an accounts title.+ -}+data Category = Category+ { cName :: CategoryName+ , cType :: CategoryType+ } deriving (Show, Read, Ord, Eq)++newtype CategoryName = CategoryName+ { unCategoryName :: Text+ } deriving (Show, Read, Ord, Eq)++instance IsString CategoryName where+ fromString = CategoryName . fromString++data CategoryType+ = Assets+ | Liabilities+ | Stock+ | Revenue+ | Expenses+ deriving (Show, Read, Ord, Eq, Enum)
+ test/Doctest.hs view
@@ -0,0 +1,19 @@+module Main where++import Data.Monoid ((<>))+import System.FilePath.Glob (glob)+import Test.DocTest (doctest)++main :: IO ()+main = glob "src/**/*.hs" >>= doDocTest++doDocTest :: [String] -> IO ()+doDocTest options = doctest $ options <> ghcExtensions++ghcExtensions :: [String]+ghcExtensions =+ [ "-XOverloadedStrings"+ , "-XRecordWildCards"+ , "-XStrict"+ , "-XStrictData"+ ]
+ test/Spec.hs view
@@ -0,0 +1,2 @@+main :: IO ()+main = putStrLn "Test suite not yet implemented"