spacepaste

  1.  
  2. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  3. ;; balsheet-pnl.scm: multi-column report. includes
  4. ;; balance-sheet and p&l reports.
  5. ;;
  6. ;; By Christopher Lam, 2018
  7. ;;
  8. ;; Improved from balance-sheet.scm
  9. ;;
  10. ;; This program is free software; you can redistribute it and/or
  11. ;; modify it under the terms of the GNU General Public License as
  12. ;; published by the Free Software Foundation; either version 2 of
  13. ;; the License, or (at your option) any later version.
  14. ;;
  15. ;; This program is distributed in the hope that it will be useful,
  16. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. ;; GNU General Public License for more details.
  19. ;;
  20. ;; You should have received a copy of the GNU General Public License
  21. ;; along with this program; if not, contact:
  22. ;;
  23. ;; Free Software Foundation Voice: +1-617-542-5942
  24. ;; 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
  25. ;; Boston, MA 02110-1301, USA gnu@gnu.org
  26. ;;
  27. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  28. (define-module (gnucash report standard-reports balsheet-pnl))
  29. (use-modules (gnucash utilities))
  30. (use-modules (gnucash gnc-module))
  31. (use-modules (gnucash gettext))
  32. (use-modules (srfi srfi-1))
  33. (gnc:module-load "gnucash/report/report-system" 0)
  34. (define FOOTER-TEXT
  35. "WARNING: Please be aware these figures are not guaranteed to be correct.
  36. Foreign currency conversions are not confirmed correct. Bug reports
  37. are very welcome at https://bugs.gnucash.org/ or please email the team
  38. at gnucash-devel@gnucash.org. No calculations for capital gains, or
  39. unrealized gains are made. Use the amounts at your own risk.")
  40. ;; define all option's names and help text so that they are properly
  41. (define optname-company-name (N_ "Company name"))
  42. (define opthelp-company-name (N_ "Name of company/individual."))
  43. (define optname-startdate (N_ "Start Date"))
  44. (define optname-enddate (N_ "End Date"))
  45. (define optname-period (N_ "Period duration"))
  46. (define opthelp-period (N_ "Duration between time periods"))
  47. (define optname-dual-columns (N_ "Enable dual columns"))
  48. (define opthelp-dual-columns (N_ "Selecting this option will enable double-column \
  49. reporting."))
  50. (define optname-disable-amount-indent (N_ "Disable amount indenting"))
  51. (define opthelp-disable-amount-indent (N_ "Selecting this option will disable amount indenting, and condense amounts into a single column."))
  52. (define optname-options-summary (N_ "Add options summary"))
  53. (define opthelp-options-summary (N_ "Add summary of options."))
  54. (define optname-account-full-name (N_ "Account full name instead of indenting"))
  55. (define opthelp-account-full-name (N_ "Selecting this option enables full account name instead, and disables indenting account names."))
  56. (define optname-accounts (N_ "Accounts"))
  57. (define opthelp-accounts (N_ "Report on these accounts, if display depth allows."))
  58. (define optname-depth-limit (N_ "Levels of Subaccounts"))
  59. (define opthelp-depth-limit (N_ "Maximum number of levels in the account tree displayed."))
  60. (define optname-parent-balance-mode (N_ "Parent account amounts include children"))
  61. (define opthelp-parent-balance-mode (N_ "If this option is enabled, subtotals are \
  62. displayed within parent amounts, and if parent has own amount, it is displayed on \
  63. the next row as a child account. If this option is disabled, subtotals are displayed \
  64. below parent and children groups."))
  65. (define optname-show-zb-accts (N_ "Include accounts with zero total balances"))
  66. (define opthelp-show-zb-accts (N_ "Include accounts with zero total (recursive) balances in this report."))
  67. (define optname-omit-zb-bals (N_ "Omit zero balance figures"))
  68. (define opthelp-omit-zb-bals (N_ "Show blank space in place of any zero balances which would be shown."))
  69. (define optname-account-links (N_ "Display accounts as hyperlinks"))
  70. (define opthelp-account-links (N_ "Shows each account in the table as a hyperlink to its register window."))
  71. (define optname-amount-links (N_ "Display amounts as hyperlinks"))
  72. (define opthelp-amount-links (N_ "Shows each amounts in the table as a hyperlink to a register or report."))
  73. ;; closing entries filter - for P&L report
  74. (define pagename-entries "Entries")
  75. (define optname-closing-pattern (N_ "Closing Entries pattern"))
  76. (define opthelp-closing-pattern (N_ "Any text in the Description column which identifies closing entries."))
  77. (define optname-closing-casing (N_ "Closing Entries pattern is case-sensitive"))
  78. (define opthelp-closing-casing (N_ "Causes the Closing Entries Pattern match to be case-sensitive."))
  79. (define optname-closing-regexp (N_ "Closing Entries Pattern is regular expression"))
  80. (define opthelp-closing-regexp (N_ "Causes the Closing Entries Pattern to be treated as a regular expression."))
  81. ;; section labels
  82. (define optname-label-sections (N_ "Label sections"))
  83. (define opthelp-label-sections (N_ "Whether or not to include a label for sections."))
  84. (define optname-total-sections (N_ "Include totals"))
  85. (define opthelp-total-sections (N_ "Whether or not to include a line indicating total amounts."))
  86. ;; commodities
  87. (define pagename-commodities (N_ "Commodities"))
  88. (define optname-include-chart (N_ "Enable chart"))
  89. (define opthelp-include-chart (N_ "Enable link to barchart report"))
  90. (define optname-common-currency (N_ "Convert to common currency"))
  91. (define opthelp-common-currency (N_ "Convert all amounts to a single currency."))
  92. (define optname-report-commodity (N_ "Report's currency"))
  93. (define optname-price-source (N_ "Price Source"))
  94. (define opthelp-price-source (N_ "How to determine exchange rates."))
  95. (define optname-show-foreign (N_ "Show Foreign Currencies"))
  96. (define opthelp-show-foreign (N_ "Display any foreign currency amount in an account."))
  97. (define optname-include-overall-period (N_ "If more than 1 period column, include overall period?"))
  98. (define opthelp-include-overall-period (N_ "If several profit & loss period columns are shown, \
  99. also show overall period profit & loss."))
  100. (define optname-show-rates (N_ "Show Exchange Rates"))
  101. (define opthelp-show-rates (N_ "Show the exchange rates used."))
  102. (define trep-uuid "2fe3b9833af044abb929a88d5a59620f")
  103. (define networth-barchart-uuid "cbba1696c8c24744848062c7f1cf4a72")
  104. (define pnl-barchart-uuid "80769921e87943adade887b9835a7685")
  105. (define periodlist
  106. (list
  107. (cons #f (list
  108. (cons 'delta #f)
  109. (cons 'text (_ "disabled"))
  110. (cons 'tip (_ "disable multicolumn"))))
  111. (cons 'year (list
  112. (cons 'delta YearDelta)
  113. (cons 'text (_ "year"))
  114. (cons 'tip (_ "every year"))))
  115. (cons 'halfyear (list
  116. (cons 'delta HalfYearDelta)
  117. (cons 'text (_ "half-year"))
  118. (cons 'tip (_ "every half year"))))
  119. (cons 'quarter (list
  120. (cons 'delta QuarterDelta)
  121. (cons 'text (_ "quarter"))
  122. (cons 'tip (_ "every three months"))))
  123. (cons 'month (list
  124. (cons 'delta MonthDelta)
  125. (cons 'text (_ "month"))
  126. (cons 'tip (_ "every month"))))
  127. (cons 'twoweek (list
  128. (cons 'delta TwoWeekDelta)
  129. (cons 'text (_ "two weeks"))
  130. (cons 'tip (_ "every fortnight"))))
  131. (cons 'week (list
  132. (cons 'delta WeekDelta)
  133. (cons 'text (_ "week"))
  134. (cons 'tip (_ "every 7 days"))))))
  135. (define pricesource-list-common
  136. (list
  137. (cons 'pricedb-latest (list
  138. (cons 'text (_ "Most recent"))
  139. (cons 'tip (_ "The most recent recorded price."))))
  140. (cons 'weighted-average (list
  141. (cons 'text (_ "Weighted Average"))
  142. (cons 'tip (_ "The weighted average of all currency transactions of the past."))))
  143. (cons 'average-cost (list
  144. (cons 'text (_ "Average Cost"))
  145. (cons 'tip (_ "The volume-weighted average cost of purchases."))))))
  146. (define pricesource-list-balsheet
  147. (reverse
  148. (cons
  149. (cons 'pricedb-nearest (list
  150. (cons 'text (_ "Nearest in time"))
  151. (cons 'tip (_ "The price recorded nearest in time to the column date."))))
  152. pricesource-list-common)))
  153. (define pricesource-list-pnl
  154. (reverse
  155. (cons*
  156. (cons 'startperiod (list
  157. (cons 'text (_ "Nearest to start of period"))
  158. (cons 'tip (_ "Prices closest to the start of the reporting period \
  159. are used."))))
  160. (cons 'midperiod (list
  161. (cons 'text (_ "Nearest to mid of period"))
  162. (cons 'tip (_ "Prices in the middle of the reporting period \
  163. are used."))))
  164. (cons 'endperiod (list
  165. (cons 'text (_ "Nearest to end of period"))
  166. (cons 'tip (_ "Prices in the end of the reporting period \
  167. are used."))))
  168. pricesource-list-common))
  169. (define (keylist->vectorlist keylist)
  170. (map
  171. (lambda (item)
  172. (vector
  173. (car item)
  174. (keylist-get-info keylist (car item) 'text)
  175. (keylist-get-info keylist (car item) 'tip)))
  176. keylist))
  177. (define (keylist-get-info keylist key info)
  178. (cdr (assq info (cdr (assq key keylist)))))
  179. (define* (gnc:account-get-balances-at-dates account dates-list #:key ignore-closing?)
  180. (define (amount->monetary bal)
  181. (gnc:make-gnc-monetary (xaccAccountGetCommodity account) bal))
  182. (let loop ((splits (xaccAccountGetSplitList account))
  183. (dates-list dates-list)
  184. (currentbal 0)
  185. (lastbal 0)
  186. (balancelist '()))
  187. (cond
  188. ;; end of dates. job done!
  189. ((null? dates-list)
  190. (map amount->monetary (reverse balancelist)))
  191. ;; end of splits, but still has dates. pad with last-bal
  192. ;; until end of dates.
  193. ((null? splits)
  194. (loop '()
  195. (cdr dates-list)
  196. currentbal
  197. lastbal
  198. (cons lastbal balancelist)))
  199. (else
  200. (let* ((this (car splits))
  201. (rest (cdr splits))
  202. (currentbal (if (and ignore-closing?
  203. (xaccTransGetIsClosingTxn (xaccSplitGetParent this)))
  204. currentbal
  205. (+ (xaccSplitGetAmount this) currentbal)))
  206. (next (and (pair? rest) (car rest))))
  207. (cond
  208. ;; the next split is still before date
  209. ((and next (< (xaccTransGetDate (xaccSplitGetParent next)) (car dates-list)))
  210. (loop rest dates-list currentbal lastbal balancelist))
  211. ;; this split after date, add previous bal to balancelist
  212. ((< (car dates-list) (xaccTransGetDate (xaccSplitGetParent this)))
  213. (loop splits
  214. (cdr dates-list)
  215. lastbal
  216. lastbal
  217. (cons lastbal balancelist)))
  218. ;; this split before date, next split after date, or end.
  219. (else
  220. (loop rest
  221. (cdr dates-list)
  222. currentbal
  223. currentbal
  224. (cons currentbal balancelist)))))))))
  225. ;; options generator
  226. (define (multicol-report-options-generator report-type)
  227. (let* ((options (gnc:new-options))
  228. (book (gnc-get-current-book))
  229. (add-option
  230. (lambda (new-option)
  231. (gnc:register-option options new-option))))
  232. (add-option
  233. (gnc:make-string-option
  234. gnc:pagename-general optname-company-name
  235. "b" opthelp-company-name (or (gnc:company-info book gnc:*company-name*) "")))
  236. ;; date at which to report balance
  237. (gnc:options-add-date-interval!
  238. options gnc:pagename-general optname-startdate optname-enddate "c")
  239. (add-option
  240. (gnc:make-multichoice-callback-option
  241. gnc:pagename-general optname-period
  242. "c2" opthelp-period
  243. #f
  244. (keylist->vectorlist periodlist)
  245. #f
  246. (lambda (x)
  247. (gnc-option-db-set-option-selectable-by-name
  248. options
  249. gnc:pagename-general optname-disable-amount-indent
  250. (not x))
  251. (gnc-option-db-set-option-selectable-by-name
  252. options
  253. gnc:pagename-general optname-dual-columns
  254. (not x))
  255. (gnc-option-db-set-option-selectable-by-name
  256. options
  257. gnc:pagename-general
  258. (case report-type
  259. ((balsheet) optname-startdate)
  260. ((pnl) optname-include-overall-period))
  261. x))))
  262. (add-option
  263. (gnc:make-simple-boolean-option
  264. gnc:pagename-general optname-disable-amount-indent
  265. "c3" opthelp-disable-amount-indent #f))
  266. (add-option
  267. (gnc:make-simple-boolean-option
  268. gnc:pagename-general optname-include-chart
  269. "d" opthelp-include-chart #f))
  270. (add-option
  271. (gnc:make-simple-boolean-option
  272. gnc:pagename-general optname-dual-columns
  273. "c4" opthelp-dual-columns #t))
  274. (add-option
  275. (gnc:make-multichoice-option
  276. gnc:pagename-general optname-options-summary
  277. "d" opthelp-options-summary
  278. 'never
  279. (list (vector 'always
  280. (_ "Always")
  281. (_ "Always display summary."))
  282. (vector 'never
  283. (_ "Never")
  284. (_ "Disable report summary.")))))
  285. ;; accounts to work on
  286. (add-option
  287. (gnc:make-account-list-option
  288. gnc:pagename-accounts optname-accounts
  289. "a"
  290. opthelp-accounts
  291. (lambda ()
  292. (gnc:filter-accountlist-type
  293. (list ACCT-TYPE-BANK ACCT-TYPE-CASH ACCT-TYPE-CREDIT
  294. ACCT-TYPE-ASSET ACCT-TYPE-LIABILITY
  295. ACCT-TYPE-STOCK ACCT-TYPE-MUTUAL ACCT-TYPE-CURRENCY
  296. ACCT-TYPE-PAYABLE ACCT-TYPE-RECEIVABLE
  297. ACCT-TYPE-EQUITY ACCT-TYPE-INCOME ACCT-TYPE-EXPENSE
  298. ACCT-TYPE-TRADING)
  299. (gnc-account-get-descendants-sorted (gnc-get-current-root-account))))
  300. #f #t))
  301. (gnc:options-add-account-levels!
  302. options gnc:pagename-accounts optname-depth-limit
  303. "b" opthelp-depth-limit 'all)
  304. ;; all about currencies
  305. (add-option
  306. (gnc:make-complex-boolean-option
  307. pagename-commodities optname-common-currency
  308. "b" opthelp-common-currency #f #f
  309. (lambda (x)
  310. (for-each
  311. (lambda (optname)
  312. (gnc-option-db-set-option-selectable-by-name
  313. options pagename-commodities optname x))
  314. (list optname-report-commodity
  315. optname-show-rates
  316. optname-show-foreign
  317. optname-price-source)))))
  318. (gnc:options-add-currency!
  319. options pagename-commodities
  320. optname-report-commodity "c")
  321. (add-option
  322. (gnc:make-multichoice-option
  323. pagename-commodities optname-price-source
  324. "d" opthelp-price-source
  325. (case report-type
  326. ((pnl) 'midperiod)
  327. ((balsheet) 'pricedb-nearest))
  328. (keylist->vectorlist
  329. (case report-type
  330. ((pnl) pricesource-list-pnl)
  331. ((balsheet) pricesource-list-balsheet)))))
  332. (add-option
  333. (gnc:make-simple-boolean-option
  334. pagename-commodities optname-show-foreign
  335. "e" opthelp-show-foreign #t))
  336. (add-option
  337. (gnc:make-simple-boolean-option
  338. pagename-commodities optname-show-rates
  339. "f" opthelp-show-rates #t))
  340. ;; what to show for zero-balance accounts
  341. (add-option
  342. (gnc:make-simple-boolean-option
  343. gnc:pagename-display optname-show-zb-accts
  344. "a" opthelp-show-zb-accts #t))
  345. (add-option
  346. (gnc:make-simple-boolean-option
  347. gnc:pagename-display optname-omit-zb-bals
  348. "b" opthelp-omit-zb-bals #f))
  349. (add-option
  350. (gnc:make-simple-boolean-option
  351. gnc:pagename-display optname-parent-balance-mode
  352. "c" opthelp-parent-balance-mode #t))
  353. ;; some detailed formatting options
  354. (add-option
  355. (gnc:make-simple-boolean-option
  356. gnc:pagename-display optname-account-links
  357. "e" opthelp-account-links #t))
  358. (add-option
  359. (gnc:make-simple-boolean-option
  360. gnc:pagename-display optname-amount-links
  361. "e5" opthelp-amount-links #t))
  362. (add-option
  363. (gnc:make-simple-boolean-option
  364. gnc:pagename-display optname-account-full-name
  365. "f" opthelp-account-full-name #f))
  366. (add-option
  367. (gnc:make-simple-boolean-option
  368. gnc:pagename-display optname-label-sections "g" opthelp-label-sections #t))
  369. (add-option
  370. (gnc:make-simple-boolean-option
  371. gnc:pagename-display optname-total-sections "h" opthelp-total-sections #t))
  372. (when (eq? report-type 'pnl)
  373. ;; include overall period column?
  374. (add-option
  375. (gnc:make-simple-boolean-option
  376. gnc:pagename-general optname-include-overall-period
  377. "e" opthelp-include-overall-period #f))
  378. ;; closing entry match criteria
  379. (add-option
  380. (gnc:make-string-option
  381. pagename-entries optname-closing-pattern
  382. "a" opthelp-closing-pattern (_ "Closing Entries")))
  383. (add-option
  384. (gnc:make-simple-boolean-option
  385. pagename-entries optname-closing-casing
  386. "b" opthelp-closing-casing #f))
  387. (add-option
  388. (gnc:make-simple-boolean-option
  389. pagename-entries optname-closing-regexp
  390. "c" opthelp-closing-regexp #f)))
  391. ;; Set the accounts page as default option tab
  392. (gnc:options-set-default-section options gnc:pagename-accounts)
  393. options))
  394. (define* (add-multicolumn-acct-table
  395. table title accountlist maxindent get-cell-monetary-fn cols-data #:key
  396. (omit-zb-bals? #f)
  397. (show-zb-accts? #t)
  398. (disable-account-indent? #f)
  399. (disable-amount-indent? #f)
  400. (show-orig-cur? #t)
  401. (show-title? #t)
  402. (show-accounts? #t)
  403. (show-total? #t)
  404. (depth-limit #f)
  405. (negate-amounts? #f)
  406. (recursive-bals? #f)
  407. (account-anchor? #t)
  408. (get-col-header-fn #f)
  409. (convert-curr-fn #f)
  410. (get-cell-anchor-fn #f))
  411. ;; this function will add a 2D grid into the html-table
  412. ;; the data cells are generated from (get-cell-monetary-fn account col-datum)
  413. ;; the data cells may request an alternative (eg. original currency) monetary
  414. ;; horizontal labels are generated from calling (get-col-header-fn col-datum)
  415. ;; vertical labels are the account list. it can have multilevel subtotals.
  416. ;; the following are compulsory arguments:
  417. ;; table - an existing html-table object
  418. ;; title - string as the first row
  419. ;; accountlist - list of accounts
  420. ;; maxindent - maximum account depth
  421. ;; cols-data - list of data to be passed as parameter to the following helper functions
  422. ;; get-cell-monetary-fn - a lambda (account cols-data) which produces a gnc-monetary or #f (eg price conversion impossible)
  423. ;; the following are optional:
  424. ;; omit-zb-bals? - a boolean to omit "$0.00" amounts
  425. ;; show-zb-accts? - a boolean to omit whole account lines where all amounts are $0.00 (eg closed accts)
  426. ;; show-title? - a bool to show/hide individual sections: title row
  427. ;; show-accounts? - a bool to show/hide individual sections: accounts list and data columns
  428. ;; show-total? - a bool to show/hide individual sections: accounts total
  429. ;; disable-account-indent? - a boolean to disable narrow-cell indenting, and render account full-name instead
  430. ;; disable-amount-indent? - a bool to disable amount indenting (only for single data column reports)
  431. ;; negate-amounts? - a boolean to negate amounts. useful for e.g. income-type accounts.
  432. ;; depth-limit - (untested) accounts whose levels exceed this depth limit are not shown
  433. ;; recursive-bals? - a boolean to confirm recursive-balances enabled (parent-accounts show balances) or
  434. ;; disabled (multilevel subtotals after each parent+children)
  435. ;; account-anchor? - a boolean to enable/disable account link to account
  436. ;; amount-anchor? - a boolean to enable/disable amount link to report/register
  437. ;; get-col-header-fn - a lambda (accounts cols-data) to produce html-object - this is optional
  438. ;; convert-curr-fn - a lambda (monetary cols-data) which produces a gnc-monetary or #f - optional
  439. ;; show-orig-cur? - a boolean to enable/disable original currency after convert-curr-fn
  440. ;; get-cell-anchor-fn - a lambda (account cols-data) which produces a url string - optional
  441. (define num-columns (length cols-data))
  442. (define amount-indenting? (and (not disable-amount-indent?) (= num-columns 1)))
  443. (define (make-list-thunk n thunk)
  444. (let loop ((result '()) (n n))
  445. (if (zero? n) result
  446. (loop (cons (thunk) result) (1- n)))))
  447. (define (make-narrow-cell)
  448. (let ((narrow (gnc:make-html-table-cell/markup "text-cell" #f)))
  449. (gnc:html-table-cell-set-style! narrow "text-cell" 'attribute '("style" "width:1px"))
  450. narrow))
  451. (define (add-indented-row indent label label-markup amount-indent rest)
  452. (when (or (not depth-limit) (<= indent depth-limit))
  453. (gnc:html-table-append-row!
  454. table
  455. (append (if disable-account-indent? '() (make-list-thunk indent make-narrow-cell))
  456. (list (if label-markup
  457. (gnc:make-html-table-cell/size/markup 1 (if disable-account-indent? 1 (- maxindent indent)) label-markup label)
  458. (gnc:make-html-table-cell/size 1 (if disable-account-indent? 1 (- maxindent indent)) label)))
  459. (gnc:html-make-empty-cells (if amount-indenting? (1- amount-indent) 0))
  460. rest
  461. (gnc:html-make-empty-cells
  462. (if amount-indenting? (- maxindent amount-indent) 0))))))
  463. (define (monetary+ . monetaries)
  464. ;; usage: (monetary+ monetary...)
  465. ;; inputs: list of gnc-monetary (e.g. USD 10, USD 25, GBP 5, GBP 8)
  466. ;; outputs: list of gnc-monetary (e.g. USD 35, GBP 13), or '()
  467. (let ((coll (gnc:make-commodity-collector)))
  468. (for-each
  469. (lambda (monetary)
  470. (if monetary
  471. (coll 'add
  472. (gnc:gnc-monetary-commodity monetary)
  473. (let ((amount (gnc:gnc-monetary-amount monetary)))
  474. (if negate-amounts? (- amount) amount)))))
  475. monetaries)
  476. (coll 'format gnc:make-gnc-monetary #f)))
  477. (define (list-of-monetary->html-text monetaries col-datum anchor)
  478. ;; inputs:
  479. ;; monetaries: list of gnc-monetary (or #f, or html-text object)
  480. ;; col-datum: col-datum to help convert monetary currency
  481. ;; anchor: url string for monetaries (or #f) (all have same anchor)
  482. ;;
  483. ;; outputs: html-text object
  484. (let ((text (gnc:make-html-text)))
  485. (for-each
  486. (lambda (monetary)
  487. (let ((converted (and show-orig-cur?
  488. convert-curr-fn
  489. (convert-curr-fn monetary col-datum))))
  490. (if (not (and omit-zb-bals?
  491. (gnc:gnc-monetary? monetary)
  492. (zero? (gnc:gnc-monetary-amount monetary))))
  493. (gnc:html-text-append! text
  494. (if converted
  495. (gnc:html-markup-i
  496. (gnc:html-markup "small" monetary " "))
  497. "")
  498. (if anchor
  499. (gnc:html-markup-anchor
  500. anchor (or converted monetary))
  501. (or converted monetary))
  502. (gnc:html-markup-br)))))
  503. monetaries)
  504. text))
  505. (define (render-account account total?)
  506. ;; input: account-name
  507. ;; outputs: string or html-markup-anchor object
  508. (let* ((acct-name ((if disable-account-indent?
  509. gnc-account-get-full-name
  510. xaccAccountGetName) account))
  511. (acct-label (if total?
  512. (string-append (_ "Total For ") acct-name)
  513. acct-name))
  514. (acct-url (and account-anchor?
  515. (not total?)
  516. (not (xaccAccountGetPlaceholder account))
  517. (gnc:account-anchor-text account))))
  518. (gnc:make-html-text
  519. (if acct-url
  520. (gnc:html-markup-anchor acct-url acct-label)
  521. acct-label))))
  522. (define (add-whole-line contents)
  523. (gnc:html-table-append-row!
  524. table (gnc:make-html-table-cell/size
  525. 1 (+ 1 (if disable-account-indent? 0 maxindent) num-columns)
  526. contents)))
  527. (define (account-and-descendants account)
  528. (cons account (filter (lambda (acc) (member acc accountlist))
  529. (gnc-account-get-descendants account))))
  530. (define (sum-accounts-at-col accounts datum convert?)
  531. ;; outputs: list of gnc-monetary
  532. (apply monetary+
  533. (map (lambda (acc)
  534. (let ((monetary (get-cell-monetary-fn acc datum)))
  535. (or (and convert? convert-curr-fn
  536. (convert-curr-fn monetary datum))
  537. monetary)))
  538. accounts)))
  539. (define (is-not-zero? accts)
  540. ;; this function tests whether accounts (with descendants) of all
  541. ;; columns are zero.
  542. (not (every zero? (concatenate
  543. (map
  544. (lambda (col-datum)
  545. (map gnc:gnc-monetary-amount
  546. (sum-accounts-at-col accts col-datum #f)))
  547. cols-data)))))
  548. (define* (add-recursive-subtotal lvl lvl-acct #:key account-style-normal?)
  549. (if (or show-zb-accts?
  550. (is-not-zero? (account-and-descendants lvl-acct)))
  551. (add-indented-row lvl
  552. (render-account lvl-acct (not account-style-normal?))
  553. (if account-style-normal?
  554. "text-cell"
  555. "total-label-cell")
  556. (- maxindent lvl)
  557. (map
  558. (lambda (col-datum)
  559. (gnc:make-html-table-cell/markup
  560. "total-number-cell"
  561. (list-of-monetary->html-text
  562. (sum-accounts-at-col (account-and-descendants lvl-acct)
  563. col-datum
  564. #t)
  565. col-datum
  566. #f)))
  567. cols-data))))
  568. (define* (add-account-row lvl-curr curr #:key
  569. (override-show-zb-accts? #f)
  570. (account-indent 0))
  571. (if (or show-zb-accts?
  572. override-show-zb-accts?
  573. (is-not-zero? (list curr)))
  574. (add-indented-row lvl-curr
  575. (render-account curr #f)
  576. "text-cell"
  577. (- maxindent lvl-curr account-indent)
  578. (map
  579. (lambda (col-datum)
  580. (gnc:make-html-table-cell/markup
  581. "number-cell"
  582. (list-of-monetary->html-text
  583. (sum-accounts-at-col
  584. (list curr)
  585. col-datum
  586. (not show-orig-cur?))
  587. col-datum
  588. (and get-cell-anchor-fn
  589. (get-cell-anchor-fn curr col-datum)))))
  590. cols-data))))
  591. ;; header ASSET/LIABILITY etc
  592. (if show-title?
  593. (add-indented-row 0
  594. title
  595. "total-label-cell"
  596. maxindent
  597. (if get-col-header-fn
  598. (map
  599. (lambda (col-datum)
  600. (get-col-header-fn accountlist col-datum))
  601. cols-data)
  602. (gnc:html-make-empty-cells num-columns))))
  603. (let loop ((accounts (if show-accounts? accountlist '())))
  604. (if (pair? accounts)
  605. (let* ((curr (car accounts))
  606. (rest (cdr accounts))
  607. (next (and (pair? rest) (car rest)))
  608. (lvl-curr (gnc-account-get-current-depth curr))
  609. (lvl-next (if next (gnc-account-get-current-depth next) 0))
  610. (curr-descendants-list (filter
  611. (lambda (acc) (member acc accountlist))
  612. (gnc-account-get-descendants curr)))
  613. (recursive-parent-acct? (and recursive-bals?
  614. (pair? curr-descendants-list)))
  615. (multilevel-parent-acct? (and (not recursive-bals?)
  616. (pair? curr-descendants-list))))
  617. (if recursive-parent-acct?
  618. (begin
  619. (add-recursive-subtotal lvl-curr curr #:account-style-normal? #t)
  620. (if (is-not-zero? (list curr))
  621. (add-account-row (1+ lvl-curr) curr #:override-show-zb-accts? #t)))
  622. (add-account-row lvl-curr curr
  623. #:account-indent (if multilevel-parent-acct? 1 0)
  624. #:override-show-zb-accts? multilevel-parent-acct?))
  625. (if (and (not recursive-bals?)
  626. (> lvl-curr lvl-next))
  627. (let multilevel-loop ((lvl (1- lvl-curr))
  628. (lvl-acct (gnc-account-get-parent curr)))
  629. (unless (or (zero? lvl)
  630. (not (member lvl-acct accountlist))
  631. (< lvl lvl-next))
  632. (add-recursive-subtotal lvl lvl-acct)
  633. (multilevel-loop (1- lvl)
  634. (gnc-account-get-parent lvl-acct)))))
  635. (loop rest))))
  636. (if show-total?
  637. (add-indented-row 0
  638. (string-append (_ "Total For ") title)
  639. "total-label-cell"
  640. maxindent
  641. (map
  642. (lambda (col-datum)
  643. (let ((total-cell (gnc:make-html-table-cell/markup
  644. "total-number-cell"
  645. (list-of-monetary->html-text
  646. (sum-accounts-at-col accountlist
  647. col-datum
  648. #t)
  649. col-datum
  650. #f))))
  651. (gnc:html-table-cell-set-style!
  652. total-cell "total-number-cell"
  653. 'attribute '("style" "border-top-style:solid; border-top-width: 1px; border-bottom-style:double"))
  654. total-cell))
  655. cols-data)))
  656. (add-whole-line #f))
  657. (define (monetary-less . monetaries)
  658. ;; syntax: (monetary-less mon0 mon1 mon2 ...)
  659. ;; equiv: (- mon0 mon1 mon2 ...)
  660. (let ((res (gnc:make-commodity-collector)))
  661. (res 'add (gnc:gnc-monetary-commodity (car monetaries)) (gnc:gnc-monetary-amount (car monetaries)))
  662. (for-each
  663. (lambda (mon)
  664. (res 'add (gnc:gnc-monetary-commodity mon) (- (gnc:gnc-monetary-amount mon))))
  665. (cdr monetaries))
  666. (car (res 'format gnc:make-gnc-monetary #f))))
  667. ;;;;;;;;;;;;;;;;;;;;;;;;;;;
  668. ;; multicol-report-renderer
  669. ;;;;;;;;;;;;;;;;;;;;;;;;;;;
  670. (define (multicol-report-renderer report-obj report-type)
  671. (define (get-option pagename optname)
  672. (gnc:option-value
  673. (gnc:lookup-option
  674. (gnc:report-options report-obj) pagename optname)))
  675. (gnc:report-starting (get-option gnc:pagename-general gnc:optname-reportname))
  676. ;; get all options values
  677. (let* ((report-title (get-option gnc:pagename-general gnc:optname-reportname))
  678. (company-name (get-option gnc:pagename-general optname-company-name))
  679. (startdate (gnc:date-option-absolute-time
  680. (get-option gnc:pagename-general
  681. optname-startdate)))
  682. (enddate (gnc:date-option-absolute-time
  683. (get-option gnc:pagename-general
  684. optname-enddate)))
  685. (disable-account-indent? (get-option gnc:pagename-display
  686. optname-account-full-name))
  687. (incr (let ((period (get-option gnc:pagename-general optname-period)))
  688. (and period
  689. (keylist-get-info periodlist period 'delta))))
  690. (disable-amount-indent? (and (not incr)
  691. (get-option gnc:pagename-general
  692. optname-disable-amount-indent)))
  693. (enable-dual-columns? (and (not incr)
  694. (get-option gnc:pagename-general
  695. optname-dual-columns)))
  696. (accounts (get-option gnc:pagename-accounts
  697. optname-accounts))
  698. (depth-limit (let ((limit (get-option gnc:pagename-accounts
  699. optname-depth-limit)))
  700. (and (not (eq? limit 'all)) limit)))
  701. (show-zb-accts? (get-option gnc:pagename-display
  702. optname-show-zb-accts))
  703. (omit-zb-bals? (get-option gnc:pagename-display
  704. optname-omit-zb-bals))
  705. (recursive-bals? (get-option gnc:pagename-display
  706. optname-parent-balance-mode))
  707. (label-sections? (get-option gnc:pagename-display
  708. optname-label-sections))
  709. (total-sections? (get-option gnc:pagename-display
  710. optname-total-sections))
  711. (use-links? (get-option gnc:pagename-display
  712. optname-account-links))
  713. (use-amount-links? (get-option gnc:pagename-display
  714. optname-amount-links))
  715. (include-chart? (get-option gnc:pagename-general optname-include-chart))
  716. (common-currency (and (get-option pagename-commodities optname-common-currency)
  717. (get-option pagename-commodities optname-report-commodity)))
  718. (has-price? (lambda (commodity)
  719. ;; the following tests whether an amount in commodity can be converted to
  720. ;; common-currency. if conversion successful, it will be a non-zero value.
  721. ;; note if we use API gnc-pricedb-has-prices, we're only querying the pricedb.
  722. ;; if we use gnc-pricedb-convert-balance-latest-price, we can potentially
  723. ;; use an intermediate currency.
  724. (not (zero? (gnc-pricedb-convert-balance-latest-price
  725. (gnc-pricedb-get-db (gnc-get-current-book))
  726. (gnc-commodity-get-fraction commodity)
  727. commodity
  728. common-currency)))))
  729. (price-source (get-option pagename-commodities optname-price-source))
  730. (report-dates (map (if (eq? report-type 'balsheet)
  731. gnc:time64-end-day-time
  732. gnc:time64-start-day-time)
  733. (if incr
  734. (gnc:make-date-list startdate enddate incr)
  735. (if (eq? report-type 'balsheet)
  736. (list enddate)
  737. (list startdate enddate)))))
  738. (accounts-balances (map
  739. (lambda (acc)
  740. (cons acc
  741. (gnc:account-get-balances-at-dates acc report-dates)))
  742. accounts))
  743. (convert-curr-fn (lambda (monetary col-idx)
  744. (and common-currency
  745. (not (gnc-commodity-equal (gnc:gnc-monetary-commodity monetary) common-currency))
  746. (has-price? (gnc:gnc-monetary-commodity monetary))
  747. (let* ((date (case price-source
  748. ((startperiod) startdate)
  749. ((midperiod) (floor (/ (+ startdate enddate) 2)))
  750. ((endperiod weighted-average average-cost) enddate)
  751. ((pricedb-latest) (current-time))
  752. (else
  753. (list-ref report-dates
  754. (case report-type
  755. ((balsheet) col-idx)
  756. ((pnl) (1+ col-idx)))))))
  757. (exchange-fn (gnc:case-exchange-fn
  758. (if (memq price-source '(startperiod midperiod endperiod))
  759. 'pricedb-nearest
  760. price-source)
  761. common-currency date)))
  762. (exchange-fn monetary common-currency)))))
  763. ;; the following function generates an gnc:html-text object
  764. ;; to dump exchange rate for a particular column. From the
  765. ;; accountlist given, obtain commodities, and convert 1 unit
  766. ;; currency into report-currency. If cannot convert due to
  767. ;; missing price, say so.
  768. (get-exchange-rates-fn (lambda (accounts date)
  769. (let ((commodities (delete
  770. common-currency
  771. (delete-duplicates
  772. (map xaccAccountGetCommodity accounts)
  773. gnc-commodity-equal)
  774. gnc-commodity-equal))
  775. (cell (gnc:make-html-text)))
  776. (for-each
  777. (lambda (commodity)
  778. (let ((orig-monetary (gnc:make-gnc-monetary commodity 1)))
  779. (if (has-price? commodity)
  780. (let ((conv-monetary (convert-curr-fn
  781. orig-monetary
  782. (case report-type
  783. ((balsheet) date)
  784. ((pnl) (cons startdate enddate))))))
  785. (gnc:html-text-append!
  786. cell
  787. (format #f "~a ~a"
  788. (gnc:monetary->string orig-monetary)
  789. (gnc:monetary->string conv-monetary))))
  790. (gnc:html-text-append!
  791. cell
  792. (format #f (string-append "~a ~a" (_ "missing"))
  793. (gnc:monetary->string orig-monetary)
  794. (gnc-commodity-get-nice-symbol common-currency)))))
  795. (gnc:html-text-append! cell (gnc:html-markup-br)))
  796. commodities)
  797. (gnc:make-html-table-cell/markup "number-cell" cell))))
  798. ;; decompose the account list
  799. (show-foreign? (get-option pagename-commodities optname-show-foreign))
  800. (show-rates? (get-option pagename-commodities optname-show-rates))
  801. (split-up-accounts (gnc:decompose-accountlist accounts))
  802. (asset-accounts
  803. (assoc-ref split-up-accounts ACCT-TYPE-ASSET))
  804. (liability-accounts
  805. (assoc-ref split-up-accounts ACCT-TYPE-LIABILITY))
  806. (income-accounts
  807. (assoc-ref split-up-accounts ACCT-TYPE-INCOME))
  808. (expense-accounts
  809. (assoc-ref split-up-accounts ACCT-TYPE-EXPENSE))
  810. (equity-accounts
  811. (assoc-ref split-up-accounts ACCT-TYPE-EQUITY))
  812. (trading-accounts
  813. (assoc-ref split-up-accounts ACCT-TYPE-TRADING))
  814. (doc (gnc:make-html-document))
  815. (multicol-table-left (gnc:make-html-table))
  816. (multicol-table-right (if enable-dual-columns?
  817. (gnc:make-html-table)
  818. multicol-table-left))
  819. (maxindent (gnc-account-get-tree-depth (gnc-get-current-root-account))))
  820. (gnc:html-document-set-title!
  821. doc (string-append company-name " " report-title " "
  822. (if (and (eq? report-type 'balsheet) (not incr))
  823. ""
  824. (string-append (qof-print-date startdate) " - "))
  825. (qof-print-date enddate)))
  826. (if (eq? (get-option gnc:pagename-general optname-options-summary) 'always)
  827. (gnc:html-document-add-object!
  828. doc (gnc:html-render-options-changed (gnc:report-options report-obj))))
  829. (if (null? accounts)
  830. (gnc:html-document-add-object!
  831. doc
  832. (gnc:html-make-no-account-warning
  833. report-title (gnc:report-id report-obj)))
  834. (case report-type
  835. ((balsheet)
  836. (let* ((get-cell-monetary-fn (lambda (account col-idx)
  837. (let ((account-balance-list (assoc account accounts-balances)))
  838. (and account-balance-list
  839. (list-ref account-balance-list (1+ col-idx))))))
  840. (get-cell-anchor-fn (lambda (account col-idx)
  841. (let* ((splits (xaccAccountGetSplitList account))
  842. (split-date (lambda (s) (xaccTransGetDate (xaccSplitGetParent s))))
  843. (date (list-ref report-dates col-idx))
  844. (valid-split? (lambda (s) (< (split-date s) date)))
  845. (valid-splits (filter valid-split? splits))
  846. (split (and (pair? valid-splits)
  847. (last valid-splits))))
  848. (and split
  849. (gnc:split-anchor-text split)))))
  850. (chart (and include-chart?
  851. (gnc:make-report-anchor
  852. networth-barchart-uuid report-obj
  853. (list (list "General" "Start Date" (cons 'absolute startdate))
  854. (list "General" "End Date" (cons 'absolute enddate))
  855. (list "General" "Report's currency" (or common-currency (gnc-default-report-currency)))
  856. (list "General" "Price Source" price-source)
  857. (list "Accounts" "Accounts" (append asset-accounts liability-accounts))))))
  858. (get-col-header-fn (lambda (accounts col-idx)
  859. (let* ((date (list-ref report-dates col-idx))
  860. (header (qof-print-date date))
  861. (cell (gnc:make-html-table-cell/markup
  862. "total-label-cell" header)))
  863. (gnc:html-table-cell-set-style!
  864. cell "total-label-cell"
  865. 'attribute '("style" "text-align:right"))
  866. cell)))
  867. (add-to-table (lambda* (table title accounts #:key
  868. (get-col-header-fn #f)
  869. (show-accounts? #t)
  870. (show-total? #t)
  871. (force-total? #f)
  872. (negate-amounts? #f))
  873. (add-multicolumn-acct-table
  874. table title accounts
  875. maxindent get-cell-monetary-fn (iota (length report-dates))
  876. #:omit-zb-bals? omit-zb-bals?
  877. #:show-zb-accts? show-zb-accts?
  878. #:disable-account-indent? disable-account-indent?
  879. #:negate-amounts? negate-amounts?
  880. #:disable-amount-indent? disable-amount-indent?
  881. #:depth-limit (if get-col-header-fn 0 depth-limit)
  882. #:show-orig-cur? show-foreign?
  883. #:show-title? label-sections?
  884. #:show-accounts? show-accounts?
  885. #:show-total? (or (and total-sections? show-total?) force-total?)
  886. #:recursive-bals? recursive-bals?
  887. #:account-anchor? use-links?
  888. #:convert-curr-fn (and common-currency convert-curr-fn)
  889. #:get-col-header-fn get-col-header-fn
  890. #:get-cell-anchor-fn (and use-amount-links? get-cell-anchor-fn)
  891. ))))
  892. (when incr
  893. (add-to-table multicol-table-left (_ "Date") '()
  894. #:get-col-header-fn get-col-header-fn
  895. #:show-accounts? #f
  896. #:show-total? #f)
  897. (if enable-dual-columns?
  898. (add-to-table multicol-table-right (_ "Date") '()
  899. #:get-col-header-fn get-col-header-fn
  900. #:show-accounts? #f
  901. #:show-total? #f)))
  902. (unless (null? asset-accounts)
  903. (add-to-table multicol-table-left (_ "Asset") asset-accounts))
  904. (unless (null? liability-accounts)
  905. (add-to-table multicol-table-right (_ "Liability") liability-accounts
  906. #:negate-amounts? #t))
  907. (unless (null? equity-accounts)
  908. (add-to-table multicol-table-right (_ "Equity")
  909. equity-accounts))
  910. (unless (null? trading-accounts)
  911. (add-to-table multicol-table-right (_ "Trading")
  912. trading-accounts))
  913. (unless (or (null? asset-accounts)
  914. (null? liability-accounts))
  915. (add-to-table multicol-table-right (_ "Net Worth")
  916. (append asset-accounts liability-accounts trading-accounts)
  917. #:show-accounts? #f
  918. #:force-total? #t))
  919. (if (and common-currency show-rates?)
  920. (add-to-table multicol-table-right (_ "Exchange Rates")
  921. (append asset-accounts liability-accounts)
  922. #:get-col-header-fn get-exchange-rates-fn
  923. #:show-accounts? #f
  924. #:show-total? #f))
  925. (if include-chart?
  926. (gnc:html-document-add-object!
  927. doc
  928. (gnc:make-html-text
  929. (gnc:html-markup-anchor chart "Barchart"))))))
  930. ((pnl)
  931. (let* ((closing-str (get-option pagename-entries optname-closing-pattern))
  932. (closing-cased (get-option pagename-entries optname-closing-casing))
  933. (closing-regexp (get-option pagename-entries optname-closing-regexp))
  934. (include-overall-period? (get-option gnc:pagename-general optname-include-overall-period))
  935. (col-idx->datepair (lambda (idx)
  936. (if (eq? idx 'overall-period)
  937. (cons (car report-dates) (last report-dates))
  938. (cons (list-ref report-dates idx)
  939. (list-ref report-dates (1+ idx))))))
  940. (col-idx->monetarypair (lambda (balancelist idx)
  941. (if (eq? idx 'overall-period)
  942. (cons (car balancelist) (last balancelist))
  943. (cons (list-ref balancelist idx)
  944. (list-ref balancelist (1+ idx))))))
  945. (closing-entries (let ((query (qof-query-create-for-splits)))
  946. (qof-query-set-book query (gnc-get-current-book))
  947. (xaccQueryAddAccountMatch query (append income-accounts expense-accounts)
  948. QOF-GUID-MATCH-ANY QOF-QUERY-AND)
  949. (if (and closing-str (not (string-null? closing-str)))
  950. (xaccQueryAddDescriptionMatch query closing-str closing-cased closing-regexp
  951. QOF-COMPARE-CONTAINS QOF-QUERY-AND))
  952. (xaccQueryAddClosingTransMatch query #t QOF-QUERY-OR)
  953. (let ((splits (qof-query-run query)))
  954. (qof-query-destroy query)
  955. splits)))
  956. ;; this function will query the above closing-entries for splits within the date range,
  957. ;; and produce the total amount for these closing entries
  958. (closing-adjustment (lambda (account col-idx)
  959. (define datepair (col-idx->datepair col-idx))
  960. (define (include-split? split)
  961. (and (equal? (xaccSplitGetAccount split) account)
  962. (<= (car datepair)
  963. (xaccTransGetDate (xaccSplitGetParent split))
  964. (cdr datepair))))
  965. (let ((account-closing-splits (filter include-split? closing-entries)))
  966. (gnc:make-gnc-monetary
  967. (xaccAccountGetCommodity account)
  968. (apply + (map xaccSplitGetAmount account-closing-splits))))))
  969. (get-cell-monetary-fn (lambda (account col-idx)
  970. (let ((account-balance-list (assoc account accounts-balances)))
  971. (and account-balance-list
  972. (let ((monetarypair (col-idx->monetarypair (cdr account-balance-list) col-idx)))
  973. (monetary-less
  974. (cdr monetarypair)
  975. (car monetarypair)
  976. (closing-adjustment account col-idx)))))))
  977. (get-cell-anchor-fn (lambda (account col-idx)
  978. (define datepair (col-idx->datepair col-idx))
  979. (gnc:make-report-anchor
  980. trep-uuid report-obj
  981. (list (list "General" "Start Date" (cons 'absolute (car datepair)))
  982. (list "General" "End Date" (cons 'absolute (cdr datepair)))
  983. (list "Accounts" "Accounts" (list account))))))
  984. (chart (and include-chart?
  985. (gnc:make-report-anchor
  986. pnl-barchart-uuid report-obj
  987. (list (list "General" "Start Date" (cons 'absolute startdate))
  988. (list "General" "End Date" (cons 'absolute enddate))
  989. (list "General" "Report's currency" (or common-currency (gnc-default-report-currency)))
  990. (list "General" "Price Source" (case price-source
  991. ((pricedb-latest) 'pricedb-latest)
  992. (else 'pricedb-nearest)))
  993. (list "Accounts" "Accounts" (append income-accounts expense-accounts))))))
  994. (get-col-header-fn (lambda (accounts col-idx)
  995. (let* ((datepair (col-idx->datepair col-idx))
  996. (header (gnc:make-html-text
  997. (qof-print-date (car datepair))
  998. (gnc:html-markup-br)
  999. (_ " to ")
  1000. (qof-print-date (cdr datepair))))
  1001. (cell (gnc:make-html-table-cell/markup "total-label-cell" header)))
  1002. (gnc:html-table-cell-set-style! cell "total-label-cell" 'attribute '("style" "text-align:right"))
  1003. cell)))
  1004. (add-to-table (lambda* (table title accounts #:key
  1005. (get-col-header-fn #f)
  1006. (show-accounts? #t)
  1007. (show-total? #t)
  1008. (force-total? #f)
  1009. (negate-amounts? #f))
  1010. (add-multicolumn-acct-table
  1011. table title accounts
  1012. maxindent get-cell-monetary-fn
  1013. (append
  1014. (iota (1- (length report-dates)))
  1015. (if (and include-overall-period?
  1016. (> (length report-dates) 2))
  1017. '(overall-period)
  1018. '()))
  1019. #:omit-zb-bals? omit-zb-bals?
  1020. #:show-zb-accts? show-zb-accts?
  1021. #:disable-account-indent? disable-account-indent?
  1022. #:negate-amounts? negate-amounts?
  1023. #:disable-amount-indent? disable-amount-indent?
  1024. #:depth-limit (if get-col-header-fn 0 depth-limit)
  1025. #:show-orig-cur? show-foreign?
  1026. #:show-title? label-sections?
  1027. #:show-accounts? show-accounts?
  1028. #:show-total? (or (and total-sections? show-total?) force-total?)
  1029. #:recursive-bals? recursive-bals?
  1030. #:account-anchor? use-links?
  1031. #:convert-curr-fn (and common-currency convert-curr-fn)
  1032. #:get-col-header-fn get-col-header-fn
  1033. #:get-cell-anchor-fn (and use-amount-links? get-cell-anchor-fn)
  1034. ))))
  1035. (when incr
  1036. (add-to-table multicol-table-left (_ "Period") '()
  1037. #:get-col-header-fn get-col-header-fn
  1038. #:show-accounts? #f
  1039. #:show-total? #f)
  1040. (if enable-dual-columns?
  1041. (add-to-table multicol-table-right (_ "Period") '()
  1042. #:get-col-header-fn get-col-header-fn
  1043. #:show-accounts? #f
  1044. #:show-total? #f)))
  1045. (unless (null? income-accounts)
  1046. (add-to-table multicol-table-left (_ "Income") income-accounts
  1047. #:negate-amounts? #t))
  1048. (unless (null? expense-accounts)
  1049. (add-to-table multicol-table-right (_ "Expense") expense-accounts))
  1050. (unless (or (null? income-accounts)
  1051. (null? expense-accounts))
  1052. (add-to-table multicol-table-left (_ "Net Income")
  1053. (append income-accounts expense-accounts)
  1054. #:show-accounts? #f
  1055. #:negate-amounts? #t
  1056. #:force-total? #t))
  1057. (if (and common-currency show-rates?)
  1058. (add-to-table multicol-table-left (_ "Exchange Rates")
  1059. (append income-accounts expense-accounts)
  1060. #:get-col-header-fn get-exchange-rates-fn
  1061. #:show-accounts? #f
  1062. #:show-total? #f))
  1063. (if include-chart?
  1064. (gnc:html-document-add-object!
  1065. doc
  1066. (gnc:make-html-text
  1067. (gnc:html-markup-anchor chart "Barchart"))))))))
  1068. (let ((multicol-table (if enable-dual-columns?
  1069. (gnc:make-html-table)
  1070. multicol-table-left)))
  1071. (when enable-dual-columns?
  1072. (gnc:html-table-append-row! multicol-table
  1073. (list multicol-table-left multicol-table-right)))
  1074. (gnc:html-document-add-object!
  1075. doc multicol-table))
  1076. (gnc:html-document-add-object!
  1077. doc (gnc:make-html-text FOOTER-TEXT))
  1078. (gnc:report-finished)
  1079. ;; (gnc:html-document-set-style-text!
  1080. ;; doc " table, td{ border-width: 1px; border-style:solid; border-color: lightgray; border-collapse: collapse}")
  1081. doc))
  1082. (define balsheet-reportname (_ "Balance Sheet (Multicolumn)"))
  1083. (define pnl-reportname (_ "Income Statement (Multicolumn)"))
  1084. (gnc:define-report
  1085. 'version 1
  1086. 'name balsheet-reportname
  1087. 'report-guid "065d5d5a77ba11e8b31e83ada73c5eea"
  1088. 'menu-path (list gnc:menuname-asset-liability)
  1089. 'options-generator (lambda () (multicol-report-options-generator 'balsheet))
  1090. 'renderer (lambda (rpt) (multicol-report-renderer rpt 'balsheet)))
  1091. (gnc:define-report
  1092. 'version 1
  1093. 'name pnl-reportname
  1094. 'report-guid "0e94fd0277ba11e8825d43e27232c9d4"
  1095. 'menu-path (list gnc:menuname-income-expense)
  1096. 'options-generator (lambda () (multicol-report-options-generator 'pnl))
  1097. 'renderer (lambda (rpt) (multicol-report-renderer rpt 'pnl)))
  1098. ;; END
  1099.