1 {-| 2 Hledger.Cli re-exports the options, utilities and commands provided by the 3 hledger command-line program. 4 -} 5 6 module Hledger.Cli ( 7 module Hledger.Cli.Add, 8 module Hledger.Cli.Balance, 9 module Hledger.Cli.Convert, 10 module Hledger.Cli.Histogram, 11 module Hledger.Cli.Print, 12 module Hledger.Cli.Register, 13 module Hledger.Cli.Stats, 14 module Hledger.Cli.Options, 15 module Hledger.Cli.Utils, 16 module Hledger.Cli.Version, 17 tests_Hledger_Cli 18 ) 19 where 20 import Control.Monad 21 import qualified Data.Map as Map 22 import Data.Time.Calendar 23 import System.Time (ClockTime(TOD)) 24 import Test.HUnit 25 26 import Hledger 27 import Hledger.Cli.Add 28 import Hledger.Cli.Balance 29 import Hledger.Cli.Convert 30 import Hledger.Cli.Histogram 31 import Hledger.Cli.Print 32 import Hledger.Cli.Register 33 import Hledger.Cli.Stats 34 import Hledger.Cli.Options 35 import Hledger.Cli.Utils 36 import Hledger.Cli.Version 37 38 -- | hledger and hledger-lib's unit tests aggregated from all modules 39 -- plus some more which are easier to define here for now. 40 tests_Hledger_Cli :: Test 41 tests_Hledger_Cli = TestList 42 [ 43 tests_Hledger_Data 44 ,tests_Hledger_Read 45 -- ,tests_Hledger_Cli_Add 46 -- ,tests_Hledger_Cli_Balance 47 ,tests_Hledger_Cli_Convert 48 -- ,tests_Hledger_Cli_Histogram 49 ,tests_Hledger_Cli_Options 50 -- ,tests_Hledger_Cli_Print 51 ,tests_Hledger_Cli_Register 52 -- ,tests_Hledger_Cli_Stats 53 54 55 ,"account directive" ~: 56 let sameParse str1 str2 = do j1 <- readJournal Nothing str1 >>= either error' return 57 j2 <- readJournal Nothing str2 >>= either error' return 58 j1 `is` j2{filereadtime=filereadtime j1, files=files j1, jContext=jContext j1} 59 in TestList 60 [ 61 "account directive 1" ~: sameParse 62 "2008/12/07 One\n test:from $-1\n test:to $1\n" 63 "!account test\n2008/12/07 One\n from $-1\n to $1\n" 64 65 ,"account directive 2" ~: sameParse 66 "2008/12/07 One\n test:foo:from $-1\n test:foo:to $1\n" 67 "!account test\n!account foo\n2008/12/07 One\n from $-1\n to $1\n" 68 69 ,"account directive 3" ~: sameParse 70 "2008/12/07 One\n test:from $-1\n test:to $1\n" 71 "!account test\n!account foo\n!end\n2008/12/07 One\n from $-1\n to $1\n" 72 73 ,"account directive 4" ~: sameParse 74 ("2008/12/07 One\n alpha $-1\n beta $1\n" ++ 75 "!account outer\n2008/12/07 Two\n aigh $-2\n bee $2\n" ++ 76 "!account inner\n2008/12/07 Three\n gamma $-3\n delta $3\n" ++ 77 "!end\n2008/12/07 Four\n why $-4\n zed $4\n" ++ 78 "!end\n2008/12/07 Five\n foo $-5\n bar $5\n" 79 ) 80 ("2008/12/07 One\n alpha $-1\n beta $1\n" ++ 81 "2008/12/07 Two\n outer:aigh $-2\n outer:bee $2\n" ++ 82 "2008/12/07 Three\n outer:inner:gamma $-3\n outer:inner:delta $3\n" ++ 83 "2008/12/07 Four\n outer:why $-4\n outer:zed $4\n" ++ 84 "2008/12/07 Five\n foo $-5\n bar $5\n" 85 ) 86 87 ,"account directive should preserve \"virtual\" posting type" ~: do 88 j <- readJournal Nothing "!account test\n2008/12/07 One\n (from) $-1\n (to) $1\n" >>= either error' return 89 let p = head $ tpostings $ head $ jtxns j 90 assertBool "" $ (paccount p) == "test:from" 91 assertBool "" $ (ptype p) == VirtualPosting 92 93 ] 94 95 ,"account aliases" ~: do 96 Right j <- readJournal Nothing "!alias expenses = equity:draw:personal\n1/1\n (expenses:food) 1\n" 97 let p = head $ tpostings $ head $ jtxns j 98 assertBool "" $ paccount p == "equity:draw:personal:food" 99 100 ,"ledgerAccountNames" ~: 101 ledgerAccountNames ledger7 `is` 102 ["assets","assets:cash","assets:checking","assets:saving","equity","equity:opening balances", 103 "expenses","expenses:food","expenses:food:dining","expenses:phone","expenses:vacation", 104 "liabilities","liabilities:credit cards","liabilities:credit cards:discover"] 105 106 ,"balance report tests" ~: 107 let opts `gives` es = do 108 j <- samplejournal 109 d <- getCurrentDay 110 accountsReportAsText opts (accountsReport opts (optsToFilterSpec opts d) j) `is` es 111 in TestList 112 [ 113 "balance report with no args" ~: 114 defreportopts `gives` 115 [" $-1 assets" 116 ," $1 bank:saving" 117 ," $-2 cash" 118 ," $2 expenses" 119 ," $1 food" 120 ," $1 supplies" 121 ," $-2 income" 122 ," $-1 gifts" 123 ," $-1 salary" 124 ," $1 liabilities:debts" 125 ,"--------------------" 126 ," 0" 127 ] 128 129 ,"balance report can be limited with --depth" ~: 130 defreportopts{depth_=Just 1} `gives` 131 [" $-1 assets" 132 ," $2 expenses" 133 ," $-2 income" 134 ," $1 liabilities" 135 ,"--------------------" 136 ," 0" 137 ] 138 139 ,"balance report with account pattern o" ~: 140 defreportopts{patterns_=["o"]} `gives` 141 [" $1 expenses:food" 142 ," $-2 income" 143 ," $-1 gifts" 144 ," $-1 salary" 145 ,"--------------------" 146 ," $-1" 147 ] 148 149 ,"balance report with account pattern o and --depth 1" ~: 150 defreportopts{patterns_=["o"],depth_=Just 1} `gives` 151 [" $1 expenses" 152 ," $-2 income" 153 ,"--------------------" 154 ," $-1" 155 ] 156 157 ,"balance report with account pattern a" ~: 158 defreportopts{patterns_=["a"]} `gives` 159 [" $-1 assets" 160 ," $1 bank:saving" 161 ," $-2 cash" 162 ," $-1 income:salary" 163 ," $1 liabilities:debts" 164 ,"--------------------" 165 ," $-1" 166 ] 167 168 ,"balance report with account pattern e" ~: 169 defreportopts{patterns_=["e"]} `gives` 170 [" $-1 assets" 171 ," $1 bank:saving" 172 ," $-2 cash" 173 ," $2 expenses" 174 ," $1 food" 175 ," $1 supplies" 176 ," $-2 income" 177 ," $-1 gifts" 178 ," $-1 salary" 179 ," $1 liabilities:debts" 180 ,"--------------------" 181 ," 0" 182 ] 183 184 ,"balance report with unmatched parent of two matched subaccounts" ~: 185 defreportopts{patterns_=["cash","saving"]} `gives` 186 [" $-1 assets" 187 ," $1 bank:saving" 188 ," $-2 cash" 189 ,"--------------------" 190 ," $-1" 191 ] 192 193 ,"balance report with multi-part account name" ~: 194 defreportopts{patterns_=["expenses:food"]} `gives` 195 [" $1 expenses:food" 196 ,"--------------------" 197 ," $1" 198 ] 199 200 ,"balance report with negative account pattern" ~: 201 defreportopts{patterns_=["not:assets"]} `gives` 202 [" $2 expenses" 203 ," $1 food" 204 ," $1 supplies" 205 ," $-2 income" 206 ," $-1 gifts" 207 ," $-1 salary" 208 ," $1 liabilities:debts" 209 ,"--------------------" 210 ," $1" 211 ] 212 213 ,"balance report negative account pattern always matches full name" ~: 214 defreportopts{patterns_=["not:e"]} `gives` 215 ["--------------------" 216 ," 0" 217 ] 218 219 ,"balance report negative patterns affect totals" ~: 220 defreportopts{patterns_=["expenses","not:food"]} `gives` 221 [" $1 expenses:supplies" 222 ,"--------------------" 223 ," $1" 224 ] 225 226 ,"balance report with -E shows zero-balance accounts" ~: 227 defreportopts{patterns_=["assets"],empty_=True} `gives` 228 [" $-1 assets" 229 ," $1 bank" 230 ," 0 checking" 231 ," $1 saving" 232 ," $-2 cash" 233 ,"--------------------" 234 ," $-1" 235 ] 236 237 ,"balance report with cost basis" ~: do 238 j <- (readJournal Nothing $ unlines 239 ["" 240 ,"2008/1/1 test " 241 ," a:b 10h @ $50" 242 ," c:d " 243 ]) >>= either error' return 244 let j' = journalCanonicaliseAmounts $ journalConvertAmountsToCost j -- enable cost basis adjustment 245 accountsReportAsText defreportopts (accountsReport defreportopts nullfilterspec j') `is` 246 [" $500 a:b" 247 ," $-500 c:d" 248 ,"--------------------" 249 ," 0" 250 ] 251 252 ,"balance report elides zero-balance root account(s)" ~: do 253 j <- readJournal' 254 (unlines 255 ["2008/1/1 one" 256 ," test:a 1" 257 ," test:b" 258 ]) 259 accountsReportAsText defreportopts (accountsReport defreportopts nullfilterspec j) `is` 260 [" 1 test:a" 261 ," -1 test:b" 262 ,"--------------------" 263 ," 0" 264 ] 265 266 ] 267 268 ,"journalCanonicaliseAmounts" ~: 269 "use the greatest precision" ~: 270 (map precision $ journalAmountAndPriceCommodities $ journalCanonicaliseAmounts $ journalWithAmounts ["1","2.00"]) `is` [2,2] 271 272 ,"commodities" ~: 273 Map.elems (commodities ledger7) `is` [Commodity {symbol="$", side=L, spaced=False, decimalpoint='.', precision=2, separator=',', separatorpositions=[]}] 274 275 -- don't know what this should do 276 -- ,"elideAccountName" ~: do 277 -- (elideAccountName 50 "aaaaaaaaaaaaaaaaaaaa:aaaaaaaaaaaaaaaaaaaa:aaaaaaaaaaaaaaaaaaaa" 278 -- `is` "aa:aaaaaaaaaaaaaaaaaaaa:aaaaaaaaaaaaaaaaaaaa") 279 -- (elideAccountName 20 "aaaaaaaaaaaaaaaaaaaa:aaaaaaaaaaaaaaaaaaaa:aaaaaaaaaaaaaaaaaaaa" 280 -- `is` "aa:aa:aaaaaaaaaaaaaa") 281 282 ,"default year" ~: do 283 j <- readJournal Nothing defaultyear_journal_str >>= either error' return 284 tdate (head $ jtxns j) `is` fromGregorian 2009 1 1 285 return () 286 287 ,"print report tests" ~: TestList 288 [ 289 290 "print expenses" ~: 291 do 292 let opts = defreportopts{patterns_=["expenses"]} 293 j <- samplejournal 294 d <- getCurrentDay 295 showTransactions opts (optsToFilterSpec opts d) j `is` unlines 296 ["2008/06/03 * eat & shop" 297 ," expenses:food $1" 298 ," expenses:supplies $1" 299 ," assets:cash $-2" 300 ,"" 301 ] 302 303 , "print report with depth arg" ~: 304 do 305 let opts = defreportopts{depth_=Just 2} 306 j <- samplejournal 307 d <- getCurrentDay 308 showTransactions opts (optsToFilterSpec opts d) j `is` unlines 309 ["2008/01/01 income" 310 ," income:salary $-1" 311 ,"" 312 ,"2008/06/01 gift" 313 ," income:gifts $-1" 314 ,"" 315 ,"2008/06/03 * eat & shop" 316 ," expenses:food $1" 317 ," expenses:supplies $1" 318 ," assets:cash $-2" 319 ,"" 320 ,"2008/12/31 * pay off" 321 ," liabilities:debts $1" 322 ,"" 323 ] 324 325 ] 326 327 ,"register report tests" ~: 328 let registerdates = filter (not . null) . map (strip . take 10) . lines 329 in 330 TestList 331 [ 332 333 "register report with no args" ~: 334 do 335 j <- samplejournal 336 let opts = defreportopts 337 (postingsReportAsText opts $ postingsReport opts (optsToFilterSpec opts date1) j) `is` unlines 338 ["2008/01/01 income assets:bank:checking $1 $1" 339 ," income:salary $-1 0" 340 ,"2008/06/01 gift assets:bank:checking $1 $1" 341 ," income:gifts $-1 0" 342 ,"2008/06/02 save assets:bank:saving $1 $1" 343 ," assets:bank:checking $-1 0" 344 ,"2008/06/03 eat & shop expenses:food $1 $1" 345 ," expenses:supplies $1 $2" 346 ," assets:cash $-2 0" 347 ,"2008/12/31 pay off liabilities:debts $1 $1" 348 ," assets:bank:checking $-1 0" 349 ] 350 351 ,"register report with cleared option" ~: 352 do 353 let opts = defreportopts{cleared_=True} 354 j <- readJournal' sample_journal_str 355 (postingsReportAsText opts $ postingsReport opts (optsToFilterSpec opts date1) j) `is` unlines 356 ["2008/06/03 eat & shop expenses:food $1 $1" 357 ," expenses:supplies $1 $2" 358 ," assets:cash $-2 0" 359 ,"2008/12/31 pay off liabilities:debts $1 $1" 360 ," assets:bank:checking $-1 0" 361 ] 362 363 ,"register report with uncleared option" ~: 364 do 365 let opts = defreportopts{uncleared_=True} 366 j <- readJournal' sample_journal_str 367 (postingsReportAsText opts $ postingsReport opts (optsToFilterSpec opts date1) j) `is` unlines 368 ["2008/01/01 income assets:bank:checking $1 $1" 369 ," income:salary $-1 0" 370 ,"2008/06/01 gift assets:bank:checking $1 $1" 371 ," income:gifts $-1 0" 372 ,"2008/06/02 save assets:bank:saving $1 $1" 373 ," assets:bank:checking $-1 0" 374 ] 375 376 ,"register report sorts by date" ~: 377 do 378 j <- readJournal' $ unlines 379 ["2008/02/02 a" 380 ," b 1" 381 ," c" 382 ,"" 383 ,"2008/01/01 d" 384 ," e 1" 385 ," f" 386 ] 387 let opts = defreportopts 388 registerdates (postingsReportAsText opts $ postingsReport opts (optsToFilterSpec opts date1) j) `is` ["2008/01/01","2008/02/02"] 389 390 ,"register report with account pattern" ~: 391 do 392 j <- samplejournal 393 let opts = defreportopts{patterns_=["cash"]} 394 (postingsReportAsText opts $ postingsReport opts (optsToFilterSpec opts date1) j) `is` unlines 395 ["2008/06/03 eat & shop assets:cash $-2 $-2" 396 ] 397 398 ,"register report with account pattern, case insensitive" ~: 399 do 400 j <- samplejournal 401 let opts = defreportopts{patterns_=["cAsH"]} 402 (postingsReportAsText opts $ postingsReport opts (optsToFilterSpec opts date1) j) `is` unlines 403 ["2008/06/03 eat & shop assets:cash $-2 $-2" 404 ] 405 406 ,"register report with display expression" ~: 407 do 408 j <- samplejournal 409 let gives displayexpr = 410 (registerdates (postingsReportAsText opts $ postingsReport opts (optsToFilterSpec opts date1) j) `is`) 411 where opts = defreportopts{display_=Just displayexpr} 412 "d<[2008/6/2]" `gives` ["2008/01/01","2008/06/01"] 413 "d<=[2008/6/2]" `gives` ["2008/01/01","2008/06/01","2008/06/02"] 414 "d=[2008/6/2]" `gives` ["2008/06/02"] 415 "d>=[2008/6/2]" `gives` ["2008/06/02","2008/06/03","2008/12/31"] 416 "d>[2008/6/2]" `gives` ["2008/06/03","2008/12/31"] 417 418 ,"register report with period expression" ~: 419 do 420 j <- samplejournal 421 let periodexpr `gives` dates = do 422 j' <- samplejournal 423 registerdates (postingsReportAsText opts $ postingsReport opts (optsToFilterSpec opts date1) j') `is` dates 424 where opts = defreportopts{period_=maybePeriod date1 periodexpr} 425 "" `gives` ["2008/01/01","2008/06/01","2008/06/02","2008/06/03","2008/12/31"] 426 "2008" `gives` ["2008/01/01","2008/06/01","2008/06/02","2008/06/03","2008/12/31"] 427 "2007" `gives` [] 428 "june" `gives` ["2008/06/01","2008/06/02","2008/06/03"] 429 "monthly" `gives` ["2008/01/01","2008/06/01","2008/12/01"] 430 "quarterly" `gives` ["2008/01/01","2008/04/01","2008/10/01"] 431 let opts = defreportopts{period_=maybePeriod date1 "yearly"} 432 (postingsReportAsText opts $ postingsReport opts (optsToFilterSpec opts date1) j) `is` unlines 433 ["2008/01/01 - 2008/12/31 assets:bank:saving $1 $1" 434 ," assets:cash $-2 $-1" 435 ," expenses:food $1 0" 436 ," expenses:supplies $1 $1" 437 ," income:gifts $-1 0" 438 ," income:salary $-1 $-1" 439 ," liabilities:debts $1 0" 440 ] 441 let opts = defreportopts{period_=maybePeriod date1 "quarterly"} 442 registerdates (postingsReportAsText opts $ postingsReport opts (optsToFilterSpec opts date1) j) `is` ["2008/01/01","2008/04/01","2008/10/01"] 443 let opts = defreportopts{period_=maybePeriod date1 "quarterly",empty_=True} 444 registerdates (postingsReportAsText opts $ postingsReport opts (optsToFilterSpec opts date1) j) `is` ["2008/01/01","2008/04/01","2008/07/01","2008/10/01"] 445 446 ] 447 448 , "register report with depth arg" ~: 449 do 450 j <- samplejournal 451 let opts = defreportopts{depth_=Just 2} 452 (postingsReportAsText opts $ postingsReport opts (optsToFilterSpec opts date1) j) `is` unlines 453 ["2008/01/01 income assets:bank $1 $1" 454 ," income:salary $-1 0" 455 ,"2008/06/01 gift assets:bank $1 $1" 456 ," income:gifts $-1 0" 457 ,"2008/06/02 save assets:bank $1 $1" 458 ," assets:bank $-1 0" 459 ,"2008/06/03 eat & shop expenses:food $1 $1" 460 ," expenses:supplies $1 $2" 461 ," assets:cash $-2 0" 462 ,"2008/12/31 pay off liabilities:debts $1 $1" 463 ," assets:bank $-1 0" 464 ] 465 466 ,"show dollars" ~: show (dollars 1) ~?= "$1.00" 467 468 ,"show hours" ~: show (hours 1) ~?= "1.0h" 469 470 ,"unicode in balance layout" ~: do 471 j <- readJournal' 472 "2009/01/01 * медвежья шкура\n расходы:покупки 100\n актив:наличные\n" 473 let opts = defreportopts 474 accountsReportAsText opts (accountsReport opts (optsToFilterSpec opts date1) j) `is` 475 [" -100 актив:наличные" 476 ," 100 расходы:покупки" 477 ,"--------------------" 478 ," 0" 479 ] 480 481 ,"unicode in register layout" ~: do 482 j <- readJournal' 483 "2009/01/01 * медвежья шкура\n расходы:покупки 100\n актив:наличные\n" 484 let opts = defreportopts 485 (postingsReportAsText opts $ postingsReport opts (optsToFilterSpec opts date1) j) `is` unlines 486 ["2009/01/01 медвежья шкура расходы:покупки 100 100" 487 ," актив:наличные -100 0"] 488 489 ,"subAccounts" ~: do 490 l <- liftM (journalToLedger nullfilterspec) samplejournal 491 let a = ledgerAccount l "assets" 492 map aname (ledgerSubAccounts l a) `is` ["assets:bank","assets:cash"] 493 494 ] 495 496 497 -- fixtures/test data 498 499 date1 = parsedate "2008/11/26" 500 -- t1 = LocalTime date1 midday 501 502 samplejournal = readJournal' sample_journal_str 503 504 sample_journal_str = unlines 505 ["; A sample journal file." 506 ,";" 507 ,"; Sets up this account tree:" 508 ,"; assets" 509 ,"; bank" 510 ,"; checking" 511 ,"; saving" 512 ,"; cash" 513 ,"; expenses" 514 ,"; food" 515 ,"; supplies" 516 ,"; income" 517 ,"; gifts" 518 ,"; salary" 519 ,"; liabilities" 520 ,"; debts" 521 ,"" 522 ,"2008/01/01 income" 523 ," assets:bank:checking $1" 524 ," income:salary" 525 ,"" 526 ,"2008/06/01 gift" 527 ," assets:bank:checking $1" 528 ," income:gifts" 529 ,"" 530 ,"2008/06/02 save" 531 ," assets:bank:saving $1" 532 ," assets:bank:checking" 533 ,"" 534 ,"2008/06/03 * eat & shop" 535 ," expenses:food $1" 536 ," expenses:supplies $1" 537 ," assets:cash" 538 ,"" 539 ,"2008/12/31 * pay off" 540 ," liabilities:debts $1" 541 ," assets:bank:checking" 542 ,"" 543 ,"" 544 ,";final comment" 545 ] 546 547 defaultyear_journal_str = unlines 548 ["Y2009" 549 ,"" 550 ,"01/01 A" 551 ," a $1" 552 ," b" 553 ] 554 555 -- write_sample_journal = writeFile "sample.journal" sample_journal_str 556 557 -- entry2_str = unlines 558 -- ["2007/01/27 * joes diner" 559 -- ," expenses:food:dining $10.00" 560 -- ," expenses:gifts $10.00" 561 -- ," assets:checking $-20.00" 562 -- ,"" 563 -- ] 564 565 -- entry3_str = unlines 566 -- ["2007/01/01 * opening balance" 567 -- ," assets:cash $4.82" 568 -- ," equity:opening balances" 569 -- ,"" 570 -- ,"2007/01/01 * opening balance" 571 -- ," assets:cash $4.82" 572 -- ," equity:opening balances" 573 -- ,"" 574 -- ,"2007/01/28 coopportunity" 575 -- ," expenses:food:groceries $47.18" 576 -- ," assets:checking" 577 -- ,"" 578 -- ] 579 580 -- periodic_entry1_str = unlines 581 -- ["~ monthly from 2007/2/2" 582 -- ," assets:saving $200.00" 583 -- ," assets:checking" 584 -- ,"" 585 -- ] 586 587 -- periodic_entry2_str = unlines 588 -- ["~ monthly from 2007/2/2" 589 -- ," assets:saving $200.00 ;auto savings" 590 -- ," assets:checking" 591 -- ,"" 592 -- ] 593 594 -- periodic_entry3_str = unlines 595 -- ["~ monthly from 2007/01/01" 596 -- ," assets:cash $4.82" 597 -- ," equity:opening balances" 598 -- ,"" 599 -- ,"~ monthly from 2007/01/01" 600 -- ," assets:cash $4.82" 601 -- ," equity:opening balances" 602 -- ,"" 603 -- ] 604 605 -- journal1_str = unlines 606 -- ["" 607 -- ,"2007/01/27 * joes diner" 608 -- ," expenses:food:dining $10.00" 609 -- ," expenses:gifts $10.00" 610 -- ," assets:checking $-20.00" 611 -- ,"" 612 -- ,"" 613 -- ,"2007/01/28 coopportunity" 614 -- ," expenses:food:groceries $47.18" 615 -- ," assets:checking $-47.18" 616 -- ,"" 617 -- ,"" 618 -- ] 619 620 -- journal2_str = unlines 621 -- [";comment" 622 -- ,"2007/01/27 * joes diner" 623 -- ," expenses:food:dining $10.00" 624 -- ," assets:checking $-47.18" 625 -- ,"" 626 -- ] 627 628 -- journal3_str = unlines 629 -- ["2007/01/27 * joes diner" 630 -- ," expenses:food:dining $10.00" 631 -- ,";intra-entry comment" 632 -- ," assets:checking $-47.18" 633 -- ,"" 634 -- ] 635 636 -- journal4_str = unlines 637 -- ["!include \"somefile\"" 638 -- ,"2007/01/27 * joes diner" 639 -- ," expenses:food:dining $10.00" 640 -- ," assets:checking $-47.18" 641 -- ,"" 642 -- ] 643 644 -- journal5_str = "" 645 646 -- journal6_str = unlines 647 -- ["~ monthly from 2007/1/21" 648 -- ," expenses:entertainment $16.23 ;netflix" 649 -- ," assets:checking" 650 -- ,"" 651 -- ,"; 2007/01/01 * opening balance" 652 -- ,"; assets:saving $200.04" 653 -- ,"; equity:opening balances " 654 -- ,"" 655 -- ] 656 657 -- journal7_str = unlines 658 -- ["2007/01/01 * opening balance" 659 -- ," assets:cash $4.82" 660 -- ," equity:opening balances " 661 -- ,"" 662 -- ,"2007/01/01 * opening balance" 663 -- ," income:interest $-4.82" 664 -- ," equity:opening balances " 665 -- ,"" 666 -- ,"2007/01/02 * ayres suites" 667 -- ," expenses:vacation $179.92" 668 -- ," assets:checking " 669 -- ,"" 670 -- ,"2007/01/02 * auto transfer to savings" 671 -- ," assets:saving $200.00" 672 -- ," assets:checking " 673 -- ,"" 674 -- ,"2007/01/03 * poquito mas" 675 -- ," expenses:food:dining $4.82" 676 -- ," assets:cash " 677 -- ,"" 678 -- ,"2007/01/03 * verizon" 679 -- ," expenses:phone $95.11" 680 -- ," assets:checking " 681 -- ,"" 682 -- ,"2007/01/03 * discover" 683 -- ," liabilities:credit cards:discover $80.00" 684 -- ," assets:checking " 685 -- ,"" 686 -- ,"2007/01/04 * blue cross" 687 -- ," expenses:health:insurance $90.00" 688 -- ," assets:checking " 689 -- ,"" 690 -- ,"2007/01/05 * village market liquor" 691 -- ," expenses:food:dining $6.48" 692 -- ," assets:checking " 693 -- ,"" 694 -- ] 695 696 journal7 = Journal 697 [] 698 [] 699 [ 700 txnTieKnot $ Transaction { 701 tdate=parsedate "2007/01/01", 702 teffectivedate=Nothing, 703 tstatus=False, 704 tcode="*", 705 tdescription="opening balance", 706 tcomment="", 707 tmetadata=[], 708 tpostings=[ 709 Posting { 710 pstatus=False, 711 paccount="assets:cash", 712 pamount=(Mixed [dollars 4.82]), 713 pcomment="", 714 ptype=RegularPosting, 715 pmetadata=[], 716 ptransaction=Nothing 717 }, 718 Posting { 719 pstatus=False, 720 paccount="equity:opening balances", 721 pamount=(Mixed [dollars (-4.82)]), 722 pcomment="", 723 ptype=RegularPosting, 724 pmetadata=[], 725 ptransaction=Nothing 726 } 727 ], 728 tpreceding_comment_lines="" 729 } 730 , 731 txnTieKnot $ Transaction { 732 tdate=parsedate "2007/02/01", 733 teffectivedate=Nothing, 734 tstatus=False, 735 tcode="*", 736 tdescription="ayres suites", 737 tcomment="", 738 tmetadata=[], 739 tpostings=[ 740 Posting { 741 pstatus=False, 742 paccount="expenses:vacation", 743 pamount=(Mixed [dollars 179.92]), 744 pcomment="", 745 ptype=RegularPosting, 746 pmetadata=[], 747 ptransaction=Nothing 748 }, 749 Posting { 750 pstatus=False, 751 paccount="assets:checking", 752 pamount=(Mixed [dollars (-179.92)]), 753 pcomment="", 754 ptype=RegularPosting, 755 pmetadata=[], 756 ptransaction=Nothing 757 } 758 ], 759 tpreceding_comment_lines="" 760 } 761 , 762 txnTieKnot $ Transaction { 763 tdate=parsedate "2007/01/02", 764 teffectivedate=Nothing, 765 tstatus=False, 766 tcode="*", 767 tdescription="auto transfer to savings", 768 tcomment="", 769 tmetadata=[], 770 tpostings=[ 771 Posting { 772 pstatus=False, 773 paccount="assets:saving", 774 pamount=(Mixed [dollars 200]), 775 pcomment="", 776 ptype=RegularPosting, 777 pmetadata=[], 778 ptransaction=Nothing 779 }, 780 Posting { 781 pstatus=False, 782 paccount="assets:checking", 783 pamount=(Mixed [dollars (-200)]), 784 pcomment="", 785 ptype=RegularPosting, 786 pmetadata=[], 787 ptransaction=Nothing 788 } 789 ], 790 tpreceding_comment_lines="" 791 } 792 , 793 txnTieKnot $ Transaction { 794 tdate=parsedate "2007/01/03", 795 teffectivedate=Nothing, 796 tstatus=False, 797 tcode="*", 798 tdescription="poquito mas", 799 tcomment="", 800 tmetadata=[], 801 tpostings=[ 802 Posting { 803 pstatus=False, 804 paccount="expenses:food:dining", 805 pamount=(Mixed [dollars 4.82]), 806 pcomment="", 807 ptype=RegularPosting, 808 pmetadata=[], 809 ptransaction=Nothing 810 }, 811 Posting { 812 pstatus=False, 813 paccount="assets:cash", 814 pamount=(Mixed [dollars (-4.82)]), 815 pcomment="", 816 ptype=RegularPosting, 817 pmetadata=[], 818 ptransaction=Nothing 819 } 820 ], 821 tpreceding_comment_lines="" 822 } 823 , 824 txnTieKnot $ Transaction { 825 tdate=parsedate "2007/01/03", 826 teffectivedate=Nothing, 827 tstatus=False, 828 tcode="*", 829 tdescription="verizon", 830 tcomment="", 831 tmetadata=[], 832 tpostings=[ 833 Posting { 834 pstatus=False, 835 paccount="expenses:phone", 836 pamount=(Mixed [dollars 95.11]), 837 pcomment="", 838 ptype=RegularPosting, 839 pmetadata=[], 840 ptransaction=Nothing 841 }, 842 Posting { 843 pstatus=False, 844 paccount="assets:checking", 845 pamount=(Mixed [dollars (-95.11)]), 846 pcomment="", 847 ptype=RegularPosting, 848 pmetadata=[], 849 ptransaction=Nothing 850 } 851 ], 852 tpreceding_comment_lines="" 853 } 854 , 855 txnTieKnot $ Transaction { 856 tdate=parsedate "2007/01/03", 857 teffectivedate=Nothing, 858 tstatus=False, 859 tcode="*", 860 tdescription="discover", 861 tcomment="", 862 tmetadata=[], 863 tpostings=[ 864 Posting { 865 pstatus=False, 866 paccount="liabilities:credit cards:discover", 867 pamount=(Mixed [dollars 80]), 868 pcomment="", 869 ptype=RegularPosting, 870 pmetadata=[], 871 ptransaction=Nothing 872 }, 873 Posting { 874 pstatus=False, 875 paccount="assets:checking", 876 pamount=(Mixed [dollars (-80)]), 877 pcomment="", 878 ptype=RegularPosting, 879 pmetadata=[], 880 ptransaction=Nothing 881 } 882 ], 883 tpreceding_comment_lines="" 884 } 885 ] 886 [] 887 [] 888 "" 889 nullctx 890 [] 891 (TOD 0 0) 892 893 ledger7 = journalToLedger nullfilterspec journal7 894 895 -- journal8_str = unlines 896 -- ["2008/1/1 test " 897 -- ," a:b 10h @ $40" 898 -- ," c:d " 899 -- ,"" 900 -- ] 901 902 -- timelogentry1_str = "i 2007/03/11 16:19:00 hledger\n" 903 -- timelogentry1 = TimeLogEntry In (parsedatetime "2007/03/11 16:19:00") "hledger" 904 905 -- timelogentry2_str = "o 2007/03/11 16:30:00\n" 906 -- timelogentry2 = TimeLogEntry Out (parsedatetime "2007/03/11 16:30:00") "" 907 908 -- a1 = Mixed [(hours 1){price=Just $ Mixed [Amount (comm "$") 10 Nothing]}] 909 -- a2 = Mixed [(hours 2){price=Just $ Mixed [Amount (comm "EUR") 10 Nothing]}] 910 -- a3 = Mixed $ amounts a1 ++ amounts a2 911 912 journalWithAmounts :: [String] -> Journal 913 journalWithAmounts as = 914 Journal 915 [] 916 [] 917 [t | a <- as, let t = nulltransaction{tdescription=a,tpostings=[nullposting{pamount=parse a,ptransaction=Just t}]}] 918 [] 919 [] 920 "" 921 nullctx 922 [] 923 (TOD 0 0) 924 where parse = fromparse . parseWithCtx nullctx someamount