631 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			Haskell
		
	
	
	
	
	
			
		
		
	
	
			631 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			Haskell
		
	
	
	
	
	
| {-|
 | |
| hledger's built-in commands, and helpers for printing the commands list.
 | |
| -}
 | |
| 
 | |
| {-# LANGUAGE OverloadedStrings #-}
 | |
| {-# LANGUAGE QuasiQuotes #-}
 | |
| {-# LANGUAGE CPP #-}
 | |
| 
 | |
| module Hledger.Cli.Commands (
 | |
|    findCommand
 | |
|   ,testcmd
 | |
|   ,builtinCommands
 | |
|   ,builtinCommandNames
 | |
|   ,printCommandsList
 | |
|   ,tests_Commands
 | |
|   ,module Hledger.Cli.Commands.Accounts
 | |
|   ,module Hledger.Cli.Commands.Activity
 | |
|   ,module Hledger.Cli.Commands.Add
 | |
|   ,module Hledger.Cli.Commands.Balance
 | |
|   ,module Hledger.Cli.Commands.Balancesheet
 | |
|   ,module Hledger.Cli.Commands.Balancesheetequity
 | |
|   ,module Hledger.Cli.Commands.Cashflow
 | |
|   ,module Hledger.Cli.Commands.Checkdates
 | |
|   ,module Hledger.Cli.Commands.Checkdupes
 | |
|   ,module Hledger.Cli.Commands.Close
 | |
|   ,module Hledger.Cli.Commands.Help
 | |
|   ,module Hledger.Cli.Commands.Import
 | |
|   ,module Hledger.Cli.Commands.Incomestatement
 | |
|   ,module Hledger.Cli.Commands.Prices
 | |
|   ,module Hledger.Cli.Commands.Print
 | |
|   ,module Hledger.Cli.Commands.Printunique
 | |
|   ,module Hledger.Cli.Commands.Register
 | |
|   ,module Hledger.Cli.Commands.Registermatch
 | |
|   ,module Hledger.Cli.Commands.Rewrite
 | |
|   ,module Hledger.Cli.Commands.Stats
 | |
|   ,module Hledger.Cli.Commands.Tags
 | |
| ) 
 | |
| where
 | |
| 
 | |
| import Data.Default
 | |
| import Data.List
 | |
| import Data.List.Split (splitOn)
 | |
| #if !(MIN_VERSION_base(4,11,0))
 | |
| import Data.Monoid ((<>))
 | |
| #endif
 | |
| import Data.String.Here
 | |
| import Data.Text (Text)
 | |
| import qualified Data.Text as T
 | |
| import Data.Time.Calendar
 | |
| import qualified EasyTest
 | |
| import System.Console.CmdArgs.Explicit as C
 | |
| import System.Exit
 | |
| 
 | |
| import Hledger 
 | |
| import Hledger.Cli.CliOptions
 | |
| import Hledger.Cli.Version
 | |
| import Hledger.Cli.Commands.Accounts
 | |
| import Hledger.Cli.Commands.Activity
 | |
| import Hledger.Cli.Commands.Add
 | |
| import Hledger.Cli.Commands.Balance
 | |
| import Hledger.Cli.Commands.Balancesheet
 | |
| import Hledger.Cli.Commands.Balancesheetequity
 | |
| import Hledger.Cli.Commands.Cashflow
 | |
| import Hledger.Cli.Commands.Checkdates
 | |
| import Hledger.Cli.Commands.Checkdupes
 | |
| import Hledger.Cli.Commands.Close
 | |
| import Hledger.Cli.Commands.Files
 | |
| import Hledger.Cli.Commands.Help
 | |
| import Hledger.Cli.Commands.Import
 | |
| import Hledger.Cli.Commands.Incomestatement
 | |
| import Hledger.Cli.Commands.Prices
 | |
| import Hledger.Cli.Commands.Print
 | |
| import Hledger.Cli.Commands.Printunique
 | |
| import Hledger.Cli.Commands.Register
 | |
| import Hledger.Cli.Commands.Registermatch
 | |
| import Hledger.Cli.Commands.Rewrite
 | |
| import Hledger.Cli.Commands.Roi
 | |
| import Hledger.Cli.Commands.Stats
 | |
| import Hledger.Cli.Commands.Tags
 | |
| 
 | |
| 
 | |
| -- | The cmdargs subcommand mode and IO action for each builtin command.
 | |
| -- Command actions take parsed CLI options and a (lazy) finalised journal.
 | |
| builtinCommands :: [(Mode RawOpts, CliOpts -> Journal -> IO ())]
 | |
| builtinCommands = [
 | |
|    (accountsmode           , accounts)
 | |
|   ,(activitymode           , activity)
 | |
|   ,(addmode                , add)
 | |
|   ,(balancemode            , balance)
 | |
|   ,(balancesheetmode       , balancesheet)
 | |
|   ,(balancesheetequitymode , balancesheetequity)
 | |
|   ,(cashflowmode           , cashflow)
 | |
|   ,(checkdatesmode         , checkdates)
 | |
|   ,(checkdupesmode         , checkdupes)
 | |
|   ,(closemode              , close)
 | |
|   ,(helpmode               , help')
 | |
|   ,(importmode             , importcmd)
 | |
|   ,(filesmode              , files)
 | |
|   ,(incomestatementmode    , incomestatement)
 | |
|   ,(pricesmode             , prices)
 | |
|   ,(printmode              , print')
 | |
|   ,(printuniquemode        , printunique)
 | |
|   ,(registermode           , register)
 | |
|   ,(registermatchmode      , registermatch)
 | |
|   ,(rewritemode            , rewrite)
 | |
|   ,(roimode                , roi)
 | |
|   ,(statsmode              , stats)
 | |
|   ,(tagsmode               , tags)
 | |
|   ,(testmode               , testcmd)
 | |
|   ]
 | |
| 
 | |
| -- | All names and aliases of builtin commands.
 | |
| builtinCommandNames :: [String]
 | |
| builtinCommandNames = concatMap (modeNames . fst) builtinCommands
 | |
| 
 | |
| -- | Look up a builtin command's mode and action by exact command name or alias. 
 | |
| findCommand :: String -> Maybe (Mode RawOpts, CliOpts -> Journal -> IO ()) 
 | |
| findCommand cmdname = find (elem cmdname . modeNames . fst) builtinCommands 
 | |
| 
 | |
| -- | A template for the commands list, containing entries (indented lines)
 | |
| -- for all known and some hypothetical builtin and addon commands.
 | |
| -- These will be filtered based on the commands found at runtime,  
 | |
| -- except those beginning with "hledger", which are not filtered. 
 | |
| -- PROGVERSION is replaced with the program name and version.
 | |
| -- OTHER is replaced with an entry for each unknown addon command found. 
 | |
| --  
 | |
| -- The command descriptions here should be kept synced with 
 | |
| -- each command's builtin help and with hledger manual's command list.
 | |
| --
 | |
| commandsList :: String
 | |
| commandsList = [here|
 | |
| -------------------------------------------------------------------------------
 | |
| PROGVERSION, commands available:
 | |
| 
 | |
| Data entry:
 | |
|  add                      add transactions using console ui
 | |
|  iadd                     add transactions using curses ui
 | |
|  import                   add new transactions from one or more import files
 | |
|  edit                     open a text editor on some part of the journal
 | |
| 
 | |
| Statements:
 | |
|  balancesheet (bs)        show a simple balance sheet with net worth
 | |
|  balancesheetequity (bse) show a detailed balance sheet with equity
 | |
|  cashflow (cf)            show a cashflow statement
 | |
|  incomestatement (is)     show an income statement
 | |
| 
 | |
| Basic reports:
 | |
|  accounts (a)             show account names
 | |
|  activity                 show a chart of posting counts per interval
 | |
|  aregister (ar, areg)     show transactions in a single account
 | |
|  balance (b, bal)         show account balance changes or ending balances
 | |
|  prices                   show market price records
 | |
|  print (p, txns)          show transactions/journal entries
 | |
|  register (r, reg)        show postings to one or more accounts
 | |
|  stats                    show journal statistics
 | |
|  tags                     show tag names
 | |
| 
 | |
| UIs:
 | |
|  ui                       start curses ui
 | |
|  web                      start web ui
 | |
| 
 | |
| Generating data:
 | |
|  close                    generate balance-resetting transactions
 | |
|  interest                 generate interest transactions
 | |
|  rewrite                  generate automated postings on matched transactions
 | |
| 
 | |
| Other/experimental:
 | |
|  api                      start web api server
 | |
|  autosync                 download/deduplicate/convert OFX data
 | |
|  budget                   add automated postings/txns/bucket accts
 | |
|  chart                    generate simple balance pie charts
 | |
|  check                    check more powerful balance assertions
 | |
|  check-dates              check transactions are ordered by date
 | |
|  check-dupes              check for accounts with the same leaf name
 | |
|  diff                     compare account transactions in two journal files
 | |
|  irr                      calculate internal rate of return of an investment
 | |
|  print-unique             show only transactions with unique descriptions
 | |
|  register-match           show best matching transaction for a description
 | |
|  test                     run self tests
 | |
| OTHER
 | |
| Help:
 | |
|  help                     show any of the hledger manuals in various formats
 | |
|  hledger CMD -h           show command usage
 | |
|  hledger -h               show general usage
 | |
| -------------------------------------------------------------------------------
 | |
| |]
 | |
| 
 | |
| -- | Print the commands list, modifying the template above based on
 | |
| -- the currently available addons. Missing addons will be removed, and
 | |
| -- extra addons will be added under Misc.
 | |
| printCommandsList :: [String] -> IO ()
 | |
| printCommandsList addonsFound =
 | |
|   putStr $
 | |
|   regexReplace "PROGVERSION" (prognameandversion) $
 | |
|   regexReplace "OTHER" (unlines $ map (' ':) unknownCommandsFound) $
 | |
|   -- regexReplace "COUNT" (show cmdcount) $
 | |
|   unlines $ concatMap adjustline $ lines $
 | |
|   cmdlist
 | |
|   where
 | |
|     cmdlist = commandsList
 | |
|     -- cmdcount = length $ commandsFromCommandsList cmdlist
 | |
|     commandsFound = builtinCommandNames ++ addonsFound
 | |
|     unknownCommandsFound = addonsFound \\ knownCommands
 | |
| 
 | |
|     adjustline l | " hledger " `isPrefixOf` l = [l]
 | |
|     adjustline (' ':l) | not $ w `elem` commandsFound = []
 | |
|       where w = takeWhile (not . (`elem` ['|',' '])) l
 | |
|     adjustline l = [l]
 | |
| 
 | |
| knownCommands :: [String]
 | |
| knownCommands = sort $ commandsFromCommandsList commandsList
 | |
| 
 | |
| -- | Extract the command names from a commands list like the above:
 | |
| -- the first word (or words separated by |) of lines beginning with a space.
 | |
| commandsFromCommandsList :: String -> [String]
 | |
| commandsFromCommandsList s =
 | |
|   concatMap (splitOn "|") [w | ' ':l <- lines s, let w:_ = words l]
 | |
| 
 | |
| 
 | |
| -- The test command, defined here for easy access to other modules' tests.
 | |
| 
 | |
| testmode = hledgerCommandMode
 | |
|   [here| test
 | |
| Run the unit tests built in to hledger-lib and hledger, 
 | |
| printing results on stdout and exiting with success or failure.
 | |
| 
 | |
| If a scope argument is provided, only tests in that (exact, case-sensitive) 
 | |
| scope are run.
 | |
| 
 | |
| If a numeric second argument is provided, it will set the randomness seed,
 | |
| for any tests which use randomness.
 | |
| 
 | |
| FLAGS
 | |
|   |]
 | |
|   []
 | |
|   [generalflagsgroup3]
 | |
|   []
 | |
|   ([], Just $ argsFlag "[TESTPATTERN] [SEED]")
 | |
| 
 | |
| -- | See testmode.
 | |
| --
 | |
| -- Unlike other hledger commands, this one does not operate on the user's Journal.
 | |
| -- For ease of implementation the Journal parameter remains in the type signature. 
 | |
| testcmd :: CliOpts -> Journal -> IO ()
 | |
| testcmd opts _undefined = do 
 | |
|   let args = words' $ query_ $ reportopts_ opts
 | |
|   -- workaround for https://github.com/joelburget/easytest/issues/11 
 | |
| --  import System.IO (hSetEncoding, stdout, stderr, utf8)
 | |
| --  hSetEncoding stdout utf8
 | |
| --  hSetEncoding stderr utf8
 | |
|   e <- runEasytests args $ EasyTest.tests [tests_Hledger, tests_Commands]
 | |
|   if e then exitFailure else exitSuccess
 | |
| 
 | |
| -- unit tests of hledger command-line executable
 | |
| 
 | |
| tests_Commands = tests "Commands" [
 | |
|    tests_Balance
 | |
|   ,tests_Register
 | |
| 
 | |
|   -- some more tests easiest to define here:
 | |
|   
 | |
|   ,test "apply account directive" $ do 
 | |
|     let ignoresourcepos j = j{jtxns=map (\t -> t{tsourcepos=nullsourcepos}) (jtxns j)}
 | |
|     let sameParse str1 str2 = do j1 <- io $ readJournal def Nothing str1 >>= either error' (return . ignoresourcepos)
 | |
|                                  j2 <- io $ readJournal def Nothing str2 >>= either error' (return . ignoresourcepos)
 | |
|                                  j1 `is` j2{jlastreadtime=jlastreadtime j1, jfiles=jfiles j1} --, jparsestate=jparsestate j1}
 | |
|     sameParse
 | |
|      ("2008/12/07 One\n  alpha  $-1\n  beta  $1\n" <>
 | |
|       "apply account outer\n2008/12/07 Two\n  aigh  $-2\n  bee  $2\n" <>
 | |
|       "apply account inner\n2008/12/07 Three\n  gamma  $-3\n  delta  $3\n" <>
 | |
|       "end apply account\n2008/12/07 Four\n  why  $-4\n  zed  $4\n" <>
 | |
|       "end apply account\n2008/12/07 Five\n  foo  $-5\n  bar  $5\n"
 | |
|      )
 | |
|      ("2008/12/07 One\n  alpha  $-1\n  beta  $1\n" <>
 | |
|       "2008/12/07 Two\n  outer:aigh  $-2\n  outer:bee  $2\n" <>
 | |
|       "2008/12/07 Three\n  outer:inner:gamma  $-3\n  outer:inner:delta  $3\n" <>
 | |
|       "2008/12/07 Four\n  outer:why  $-4\n  outer:zed  $4\n" <>
 | |
|       "2008/12/07 Five\n  foo  $-5\n  bar  $5\n"
 | |
|      )
 | |
| 
 | |
|   ,test "apply account directive should preserve \"virtual\" posting type" $ do
 | |
|     j <- io $ readJournal def Nothing "apply account test\n2008/12/07 One\n  (from)  $-1\n  (to)  $1\n" >>= either error' return
 | |
|     let p = head $ tpostings $ head $ jtxns j
 | |
|     paccount p `is` "test:from"
 | |
|     ptype p `is` VirtualPosting
 | |
|   
 | |
|   ,test "account aliases" $ do
 | |
|     j <- io $ readJournal def Nothing "!alias expenses = equity:draw:personal\n1/1\n (expenses:food)  1\n" >>= either error' return
 | |
|     let p = head $ tpostings $ head $ jtxns j
 | |
|     paccount p `is` "equity:draw:personal:food"
 | |
| 
 | |
|   ,test "ledgerAccountNames" $
 | |
|     ledgerAccountNames ledger7 `is`
 | |
|      ["assets","assets:cash","assets:checking","assets:saving","equity","equity:opening balances",
 | |
|       "expenses","expenses:food","expenses:food:dining","expenses:phone","expenses:vacation",
 | |
|       "liabilities","liabilities:credit cards","liabilities:credit cards:discover"]
 | |
| 
 | |
|   -- ,test "journalCanonicaliseAmounts" ~:
 | |
|   --  "use the greatest precision" ~:
 | |
|   --   (map asprecision $ journalAmountAndPriceCommodities $ journalCanonicaliseAmounts $ journalWithAmounts ["1","2.00"]) `is` [2,2]
 | |
| 
 | |
|   -- don't know what this should do
 | |
|   -- ,test "elideAccountName" ~: do
 | |
|   --    (elideAccountName 50 "aaaaaaaaaaaaaaaaaaaa:aaaaaaaaaaaaaaaaaaaa:aaaaaaaaaaaaaaaaaaaa"
 | |
|   --     `is` "aa:aaaaaaaaaaaaaaaaaaaa:aaaaaaaaaaaaaaaaaaaa")
 | |
|   --    (elideAccountName 20 "aaaaaaaaaaaaaaaaaaaa:aaaaaaaaaaaaaaaaaaaa:aaaaaaaaaaaaaaaaaaaa"
 | |
|   --     `is` "aa:aa:aaaaaaaaaaaaaa")
 | |
| 
 | |
|   ,test "default year" $ do
 | |
|     j <- io $ readJournal def Nothing defaultyear_journal_txt >>= either error' return
 | |
|     tdate (head $ jtxns j) `is` fromGregorian 2009 1 1
 | |
| 
 | |
|   ,test "show dollars" $ showAmount (usd 1) `is` "$1.00"
 | |
| 
 | |
|   ,test "show hours" $ showAmount (hrs 1) `is` "1.00h"
 | |
| 
 | |
|  ]
 | |
| 
 | |
| 
 | |
| -- test data
 | |
| 
 | |
| -- date1 = parsedate "2008/11/26"
 | |
| -- t1 = LocalTime date1 midday
 | |
| 
 | |
| {-
 | |
| samplejournal = readJournal' sample_journal_str
 | |
| 
 | |
| sample_journal_str = unlines
 | |
|  ["; A sample journal file."
 | |
|  ,";"
 | |
|  ,"; Sets up this account tree:"
 | |
|  ,"; assets"
 | |
|  ,";   bank"
 | |
|  ,";     checking"
 | |
|  ,";     saving"
 | |
|  ,";   cash"
 | |
|  ,"; expenses"
 | |
|  ,";   food"
 | |
|  ,";   supplies"
 | |
|  ,"; income"
 | |
|  ,";   gifts"
 | |
|  ,";   salary"
 | |
|  ,"; liabilities"
 | |
|  ,";   debts"
 | |
|  ,""
 | |
|  ,"2008/01/01 income"
 | |
|  ,"    assets:bank:checking  $1"
 | |
|  ,"    income:salary"
 | |
|  ,""
 | |
|  ,"2008/06/01 gift"
 | |
|  ,"    assets:bank:checking  $1"
 | |
|  ,"    income:gifts"
 | |
|  ,""
 | |
|  ,"2008/06/02 save"
 | |
|  ,"    assets:bank:saving  $1"
 | |
|  ,"    assets:bank:checking"
 | |
|  ,""
 | |
|  ,"2008/06/03 * eat & shop"
 | |
|  ,"    expenses:food      $1"
 | |
|  ,"    expenses:supplies  $1"
 | |
|  ,"    assets:cash"
 | |
|  ,""
 | |
|  ,"2008/12/31 * pay off"
 | |
|  ,"    liabilities:debts  $1"
 | |
|  ,"    assets:bank:checking"
 | |
|  ,""
 | |
|  ,""
 | |
|  ,";final comment"
 | |
|  ]
 | |
| -}
 | |
| 
 | |
| defaultyear_journal_txt :: Text
 | |
| defaultyear_journal_txt = T.unlines
 | |
|  ["Y2009"
 | |
|  ,""
 | |
|  ,"01/01 A"
 | |
|  ,"    a  $1"
 | |
|  ,"    b"
 | |
|  ]
 | |
| 
 | |
| -- write_sample_journal = writeFile "sample.journal" sample_journal_str
 | |
| 
 | |
| -- entry2_str = unlines
 | |
| --  ["2007/01/27 * joes diner"
 | |
| --  ,"    expenses:food:dining                      $10.00"
 | |
| --  ,"    expenses:gifts                            $10.00"
 | |
| --  ,"    assets:checking                          $-20.00"
 | |
| --  ,""
 | |
| --  ]
 | |
| 
 | |
| -- entry3_str = unlines
 | |
| --  ["2007/01/01 * opening balance"
 | |
| --  ,"    assets:cash                                $4.82"
 | |
| --  ,"    equity:opening balances"
 | |
| --  ,""
 | |
| --  ,"2007/01/01 * opening balance"
 | |
| --  ,"    assets:cash                                $4.82"
 | |
| --  ,"    equity:opening balances"
 | |
| --  ,""
 | |
| --  ,"2007/01/28 coopportunity"
 | |
| --  ,"  expenses:food:groceries                 $47.18"
 | |
| --  ,"  assets:checking"
 | |
| --  ,""
 | |
| --  ]
 | |
| 
 | |
| -- periodic_entry1_str = unlines
 | |
| --  ["~ monthly from 2007/2/2"
 | |
| --  ,"  assets:saving            $200.00"
 | |
| --  ,"  assets:checking"
 | |
| --  ,""
 | |
| --  ]
 | |
| 
 | |
| -- periodic_entry2_str = unlines
 | |
| --  ["~ monthly from 2007/2/2"
 | |
| --  ,"  assets:saving            $200.00         ;auto savings"
 | |
| --  ,"  assets:checking"
 | |
| --  ,""
 | |
| --  ]
 | |
| 
 | |
| -- periodic_entry3_str = unlines
 | |
| --  ["~ monthly from 2007/01/01"
 | |
| --  ,"    assets:cash                                $4.82"
 | |
| --  ,"    equity:opening balances"
 | |
| --  ,""
 | |
| --  ,"~ monthly from 2007/01/01"
 | |
| --  ,"    assets:cash                                $4.82"
 | |
| --  ,"    equity:opening balances"
 | |
| --  ,""
 | |
| --  ]
 | |
| 
 | |
| -- journal1_str = unlines
 | |
| --  [""
 | |
| --  ,"2007/01/27 * joes diner"
 | |
| --  ,"  expenses:food:dining                    $10.00"
 | |
| --  ,"  expenses:gifts                          $10.00"
 | |
| --  ,"  assets:checking                        $-20.00"
 | |
| --  ,""
 | |
| --  ,""
 | |
| --  ,"2007/01/28 coopportunity"
 | |
| --  ,"  expenses:food:groceries                 $47.18"
 | |
| --  ,"  assets:checking                        $-47.18"
 | |
| --  ,""
 | |
| --  ,""
 | |
| --  ]
 | |
| 
 | |
| -- journal2_str = unlines
 | |
| --  [";comment"
 | |
| --  ,"2007/01/27 * joes diner"
 | |
| --  ,"  expenses:food:dining                    $10.00"
 | |
| --  ,"  assets:checking                        $-47.18"
 | |
| --  ,""
 | |
| --  ]
 | |
| 
 | |
| -- journal3_str = unlines
 | |
| --  ["2007/01/27 * joes diner"
 | |
| --  ,"  expenses:food:dining                    $10.00"
 | |
| --  ,";intra-entry comment"
 | |
| --  ,"  assets:checking                        $-47.18"
 | |
| --  ,""
 | |
| --  ]
 | |
| 
 | |
| -- journal4_str = unlines
 | |
| --  ["!include \"somefile\""
 | |
| --  ,"2007/01/27 * joes diner"
 | |
| --  ,"  expenses:food:dining                    $10.00"
 | |
| --  ,"  assets:checking                        $-47.18"
 | |
| --  ,""
 | |
| --  ]
 | |
| 
 | |
| -- journal5_str = ""
 | |
| 
 | |
| -- journal6_str = unlines
 | |
| --  ["~ monthly from 2007/1/21"
 | |
| --  ,"    expenses:entertainment  $16.23        ;netflix"
 | |
| --  ,"    assets:checking"
 | |
| --  ,""
 | |
| --  ,"; 2007/01/01 * opening balance"
 | |
| --  ,";     assets:saving                            $200.04"
 | |
| --  ,";     equity:opening balances                         "
 | |
| --  ,""
 | |
| --  ]
 | |
| 
 | |
| -- journal7_str = unlines
 | |
| --  ["2007/01/01 * opening balance"
 | |
| --  ,"    assets:cash                                $4.82"
 | |
| --  ,"    equity:opening balances                         "
 | |
| --  ,""
 | |
| --  ,"2007/01/01 * opening balance"
 | |
| --  ,"    income:interest                                $-4.82"
 | |
| --  ,"    equity:opening balances                         "
 | |
| --  ,""
 | |
| --  ,"2007/01/02 * ayres suites"
 | |
| --  ,"    expenses:vacation                        $179.92"
 | |
| --  ,"    assets:checking                                 "
 | |
| --  ,""
 | |
| --  ,"2007/01/02 * auto transfer to savings"
 | |
| --  ,"    assets:saving                            $200.00"
 | |
| --  ,"    assets:checking                                 "
 | |
| --  ,""
 | |
| --  ,"2007/01/03 * poquito mas"
 | |
| --  ,"    expenses:food:dining                       $4.82"
 | |
| --  ,"    assets:cash                                     "
 | |
| --  ,""
 | |
| --  ,"2007/01/03 * verizon"
 | |
| --  ,"    expenses:phone                            $95.11"
 | |
| --  ,"    assets:checking                                 "
 | |
| --  ,""
 | |
| --  ,"2007/01/03 * discover"
 | |
| --  ,"    liabilities:credit cards:discover         $80.00"
 | |
| --  ,"    assets:checking                                 "
 | |
| --  ,""
 | |
| --  ,"2007/01/04 * blue cross"
 | |
| --  ,"    expenses:health:insurance                 $90.00"
 | |
| --  ,"    assets:checking                                 "
 | |
| --  ,""
 | |
| --  ,"2007/01/05 * village market liquor"
 | |
| --  ,"    expenses:food:dining                       $6.48"
 | |
| --  ,"    assets:checking                                 "
 | |
| --  ,""
 | |
| --  ]
 | |
| 
 | |
| journal7 :: Journal
 | |
| journal7 = nulljournal {jtxns =
 | |
|           [
 | |
|            txnTieKnot Transaction {
 | |
|              tindex=0,
 | |
|              tsourcepos=nullsourcepos,
 | |
|              tdate=parsedate "2007/01/01",
 | |
|              tdate2=Nothing,
 | |
|              tstatus=Unmarked,
 | |
|              tcode="*",
 | |
|              tdescription="opening balance",
 | |
|              tcomment="",
 | |
|              ttags=[],
 | |
|              tpostings=
 | |
|                  ["assets:cash" `post` usd 4.82
 | |
|                  ,"equity:opening balances" `post` usd (-4.82)
 | |
|                  ],
 | |
|              tpreceding_comment_lines=""
 | |
|            }
 | |
|           ,
 | |
|            txnTieKnot Transaction {
 | |
|              tindex=0,
 | |
|              tsourcepos=nullsourcepos,
 | |
|              tdate=parsedate "2007/02/01",
 | |
|              tdate2=Nothing,
 | |
|              tstatus=Unmarked,
 | |
|              tcode="*",
 | |
|              tdescription="ayres suites",
 | |
|              tcomment="",
 | |
|              ttags=[],
 | |
|              tpostings=
 | |
|                  ["expenses:vacation" `post` usd 179.92
 | |
|                  ,"assets:checking" `post` usd (-179.92)
 | |
|                  ],
 | |
|              tpreceding_comment_lines=""
 | |
|            }
 | |
|           ,
 | |
|            txnTieKnot Transaction {
 | |
|              tindex=0,
 | |
|              tsourcepos=nullsourcepos,
 | |
|              tdate=parsedate "2007/01/02",
 | |
|              tdate2=Nothing,
 | |
|              tstatus=Unmarked,
 | |
|              tcode="*",
 | |
|              tdescription="auto transfer to savings",
 | |
|              tcomment="",
 | |
|              ttags=[],
 | |
|              tpostings=
 | |
|                  ["assets:saving" `post` usd 200
 | |
|                  ,"assets:checking" `post` usd (-200)
 | |
|                  ],
 | |
|              tpreceding_comment_lines=""
 | |
|            }
 | |
|           ,
 | |
|            txnTieKnot Transaction {
 | |
|              tindex=0,
 | |
|              tsourcepos=nullsourcepos,
 | |
|              tdate=parsedate "2007/01/03",
 | |
|              tdate2=Nothing,
 | |
|              tstatus=Unmarked,
 | |
|              tcode="*",
 | |
|              tdescription="poquito mas",
 | |
|              tcomment="",
 | |
|              ttags=[],
 | |
|              tpostings=
 | |
|                  ["expenses:food:dining" `post` usd 4.82
 | |
|                  ,"assets:cash" `post` usd (-4.82)
 | |
|                  ],
 | |
|              tpreceding_comment_lines=""
 | |
|            }
 | |
|           ,
 | |
|            txnTieKnot Transaction {
 | |
|              tindex=0,
 | |
|              tsourcepos=nullsourcepos,
 | |
|              tdate=parsedate "2007/01/03",
 | |
|              tdate2=Nothing,
 | |
|              tstatus=Unmarked,
 | |
|              tcode="*",
 | |
|              tdescription="verizon",
 | |
|              tcomment="",
 | |
|              ttags=[],
 | |
|              tpostings=
 | |
|                  ["expenses:phone" `post` usd 95.11
 | |
|                  ,"assets:checking" `post` usd (-95.11)
 | |
|                  ],
 | |
|              tpreceding_comment_lines=""
 | |
|            }
 | |
|           ,
 | |
|            txnTieKnot Transaction {
 | |
|              tindex=0,
 | |
|              tsourcepos=nullsourcepos,
 | |
|              tdate=parsedate "2007/01/03",
 | |
|              tdate2=Nothing,
 | |
|              tstatus=Unmarked,
 | |
|              tcode="*",
 | |
|              tdescription="discover",
 | |
|              tcomment="",
 | |
|              ttags=[],
 | |
|              tpostings=
 | |
|                  ["liabilities:credit cards:discover" `post` usd 80
 | |
|                  ,"assets:checking" `post` usd (-80)
 | |
|                  ],
 | |
|              tpreceding_comment_lines=""
 | |
|            }
 | |
|           ]
 | |
|          }
 | |
| 
 | |
| ledger7 :: Ledger
 | |
| ledger7 = ledgerFromJournal Any journal7
 |