Difference between revisions of "Custom Reports"

From GnuCash
Jump to: navigation, search
(Moved technique for reloading a report under Development Environment section.)
(Minimum definition example now includes gettext module so that it will compile. Highlighted where reader needs to paste in generated unique report ids more clearly.)
Line 317: Line 317:
 
* the <code>gnc:define-report</code> statement (make the report available in ''GnuCash'')
 
* the <code>gnc:define-report</code> statement (make the report available in ''GnuCash'')
  
This is the minimum defintion needed for a new ''GnuCash'' report:
+
This is the minimum definition needed for a new ''GnuCash'' report:
 
 
<pre>
 
;; -*-scheme-*-
 
 
 
;; This is a minimum report definition in GnuCash.
 
;; It illustrates the the minimum definitions needed to create
 
;; a new GnuCash report.
 
;; It will create an empty page with heading 'Prototype'.
 
;; To be used as template.
 
 
 
;; ------------------------------------------------------------------
 
;; Top-level definitions
 
;; ------------------------------------------------------------------
 
 
 
(define-module (gnucash report prototype))
 
(use-modules (gnucash gnc-module))
 
(gnc:module-load "gnucash/report/report-system" 0)
 
 
 
;; ------------------------------------------------------------------
 
;; Define the Options for this report
 
;; ------------------------------------------------------------------
 
 
 
(define (options-generator)   
 
  (let* ((options (gnc:new-options)))       
 
    options))
 
 
 
;; ------------------------------------------------------------------
 
;; Render the HTML document
 
;; ------------------------------------------------------------------
 
 
 
(define (document-renderer report-obj)
 
  (let ((document (gnc:make-html-document)))
 
      document))
 
 
 
;; ------------------------------------------------------------------
 
;; Define the actual report
 
;; ------------------------------------------------------------------
 
 
 
(gnc:define-report
 
'version 1
 
'name (N_ "Prototype")
 
'report-guid "<copy-here-new-created-report-ID>"
 
'menu-tip (N_ "Unstable. Used for Testing.")
 
'menu-path (list gnc:menuname-utility)
 
'options-generator options-generator
 
'renderer document-renderer)
 
</pre>
 
  
 +
;; -*-scheme-*-
 +
 +
;; This is a minimum report definition in GnuCash.
 +
;; It illustrates the the minimum definitions needed to create
 +
;; a new GnuCash report.
 +
;; It will create an empty page with heading 'Prototype'.
 +
;; To be used as template.
 +
 +
;; ------------------------------------------------------------------
 +
;; Top-level definitions
 +
;; ------------------------------------------------------------------
 +
 +
(define-module (gnucash report prototype))
 +
(use-modules (gnucash gnc-module))
 +
(use-modules (gnucash gettext))
 +
(gnc:module-load "gnucash/report/report-system" 0)
 +
 +
;; ------------------------------------------------------------------
 +
;; Define the Options for this report
 +
;; ------------------------------------------------------------------
 +
 +
(define (options-generator)   
 +
  (let* ((options (gnc:new-options)))       
 +
    options))
 +
 +
;; ------------------------------------------------------------------
 +
;; Render the HTML document
 +
;; ------------------------------------------------------------------
 +
 +
(define (document-renderer report-obj)
 +
  (let ((document (gnc:make-html-document)))
 +
      document))
 +
 +
;; ------------------------------------------------------------------
 +
;; Define the actual report
 +
;; ------------------------------------------------------------------
 +
 +
(gnc:define-report
 +
  'version 1
 +
  'name (N_ "Prototype")
 +
  'report-guid "<span style="color:red">paste generated unique report id here</span>"
 +
  'menu-tip (N_ "Unstable. Used for Testing.")
 +
  'menu-path (list gnc:menuname-utility)
 +
  'options-generator options-generator
 +
  'renderer document-renderer)
  
 
=== The Options-Generator ===
 
=== The Options-Generator ===
Line 672: Line 670:
 
The minimum definition is of a bar chart report is shown in the example below:
 
The minimum definition is of a bar chart report is shown in the example below:
  
<pre>
+
;; -*-scheme-*-
;; -*-scheme-*-
+
 
+
;; This is a minimum barchart report definition in GnuCash.
;; This is a minimum barchart report definition in GnuCash.
+
;; It illustrates the the minimum definitions needed to create
;; It illustrates the the minimum definitions needed to create
+
;; a new GnuCash barchart report.
;; a new GnuCash barchart report.
+
;; It will create a page with heading 'Prototype'.
;; It will create a page with heading 'Prototype'.
+
;; To be used as template.
;; To be used as template.
+
 
+
;; ------------------------------------------------------------------
;; ------------------------------------------------------------------
+
;; Top-level definitions
;; Top-level definitions
+
;; ------------------------------------------------------------------
;; ------------------------------------------------------------------
+
 
+
(define-module (gnucash report prototype))
(define-module (gnucash report prototype))
+
(use-modules (gnucash gnc-module))
(use-modules (gnucash gnc-module))
+
(gnc:module-load "gnucash/report/report-system" 0)
(gnc:module-load "gnucash/report/report-system" 0)
+
 
+
;; ------------------------------------------------------------------
;; ------------------------------------------------------------------
+
;; Define the Options for this report
;; Define the Options for this report
+
;; ------------------------------------------------------------------
;; ------------------------------------------------------------------
+
 
+
(define (options-generator)     
(define (options-generator)     
+
  (let* ((options (gnc:new-options)))         
  (let* ((options (gnc:new-options)))         
+
    options))
    options))
+
 
+
;; ------------------------------------------------------------------
;; ------------------------------------------------------------------
+
;; Render the HTML document
;; Render the HTML document
+
;; ------------------------------------------------------------------
;; ------------------------------------------------------------------
+
 
+
(define (document-renderer report-obj)
(define (document-renderer report-obj)
+
  (let (
  (let (
+
          (document (gnc:make-html-document))
        (document (gnc:make-html-document))
+
          (chart (gnc:make-html-barchart))
        (chart (gnc:make-html-barchart))
+
        )
      )
+
 
+
        (gnc:html-barchart-set-title! chart "Barchart Title") ;; optional
      (gnc:html-barchart-set-title! chart "Barchart Title") ;; optional
+
        (gnc:html-barchart-set-subtitle! chart "Barchart Sub-Title") ;; optional
      (gnc:html-barchart-set-subtitle! chart "Barchart Sub-Title") ;; optional
+
        (gnc:html-barchart-set-width! chart 400)
      (gnc:html-barchart-set-width! chart 400)
+
        (gnc:html-barchart-set-height! chart 400)
      (gnc:html-barchart-set-height! chart 400)
+
        (gnc:html-barchart-set-row-labels! chart '("row1" "row2"))
      (gnc:html-barchart-set-row-labels! chart '("row1" "row2"))
+
        (gnc:html-barchart-set-y-axis-label! chart "y-Axis-Label") ;; optional
      (gnc:html-barchart-set-y-axis-label! chart "y-Axis-Label") ;; optional
+
        (gnc:html-barchart-set-x-axis-label! chart "x-Axis-Label") ;; optional
      (gnc:html-barchart-set-x-axis-label! chart "x-Axis-Label") ;; optional
+
        (gnc:html-barchart-append-column! chart '(100 200))
      (gnc:html-barchart-append-column! chart '(100 200))
+
        (gnc:html-barchart-append-column! chart '(110 210))
      (gnc:html-barchart-append-column! chart '(110 210))
+
 
+
        (gnc:html-barchart-set-col-labels! chart '("col1" "col2"))
      (gnc:html-barchart-set-col-labels! chart '("col1" "col2"))
+
        (gnc:html-barchart-set-col-colors! chart '("green" "blue"))
      (gnc:html-barchart-set-col-colors! chart '("green" "blue"))
+
       
     
+
        (gnc:html-document-add-object! document chart)
      (gnc:html-document-add-object! document chart)
+
 
+
        document ;; RETURN value
      document ;; RETURN value
+
  )
  )
+
)
)
+
 
+
;; ------------------------------------------------------------------
;; ------------------------------------------------------------------
+
;; Define the actual report
;; Define the actual report
+
;; ------------------------------------------------------------------
;; ------------------------------------------------------------------
+
 
+
(gnc:define-report
(gnc:define-report
+
  'version 1
'version 1
+
  'name (N_ "Prototype")
'name (N_ "Prototype")
+
  'report-guid "<span style="color:red">paste generated unique report id here</span>"
'report-guid "<put_in_a_valid_ID_here>"
+
  'menu-tip (N_ "Unstable. Used for Testing.")
'menu-tip (N_ "Unstable. Used for Testing.")
+
  'menu-path (list gnc:menuname-utility)
'menu-path (list gnc:menuname-utility)
+
  'options-generator options-generator
'options-generator options-generator
+
  'renderer document-renderer)
'renderer document-renderer)
 
</pre>
 
  
 
and it will create the following line in the report:
 
and it will create the following line in the report:

Revision as of 22:43, 22 July 2017

Custom Reports in GnuCash

The term Custom Reports has several contexts in GnuCash:

If you are not up into coding, you should check the

  • report options
  • stylesheets and
  • stylesheet options and
  • file properties.

Possibly there are ways to get what you desired.

If you are ready for coding (and even already firm in Scheme and Guile) then this is the place to contribute.

Introduction

Unfortunately, at the present time writing a custom report for GnuCash requires a little bit of hacking. This wiki page should contain some information to help you get started, since there is no official documentation.

In the GnuCash project the reports are coded in Scheme, not in C. This is one of the pre-requisites to make the behaviour ready for customization. It leads to the drawback that one must learn yet another programming language (if not already familiar with it) but saves the effort to get into the issue how to build GnuCash from source.

Guile is used as interface to get the Scheme code executed during runtime. Again, if not already familiar with it, this is the second piece of work that one has to swallow.

Last but not least the API for that sort of thing is not formally specified.

Still reading? Not yet discouraged? Good on you! Because there is lots of help available.

First of all there is good educational stuff available on the web to get you into the topic of Scheme and Guile. Secondly there is a nice hello-world.scm example report specifically written to show you the base layout of a GnuCash report. And finally, this Wiki page might give you some guidence when doing the first steps.

Getting Started

Get to know Scheme

If you are new to Scheme it is not necessary to read and understand each bit of it right now. But you should at least have gone through the Getting Started section.

Get to know Guile

This comes with a marvellous Tutorial. You don't need this for writing the reports themselves, but it gives a clue of how reports are working in GnuCash and by that hopefully a good motivation to go and take the learning curve for Scheme.

Get to know Gettext

That is the tool which makes the strings translatable. (_ "Some Text"), (N_ "Some Text") and similar mark the text for translation. See Translation#How to make strings in code translatable for details.

Where to find existing reports

The location varies with different operating systems:

Operating System Existing Reports Location (2.4.x) Existing Reports Location (2.6.x)
BSD /usr/local/share/gnucash/guile-modules/gnucash/report /usr/local/share/gnucash/scm/gnucash/report
Debian

incl. derivatives such as Ubuntu

/usr/share/gnucash/guile-modules/gnucash/report /usr/share/gnucash/scm/gnucash/report
Gentoo and

Foresight

/usr/share/gnucash/guile-modules/gnucash/report /usr/share/gnucash/scm/gnucash/report
OpenSuse

10.x and newer

/usr/share/gnucash/guile-modules/gnucash/report /usr/share/gnucash/scm/gnucash/report
OpenSuse

up to 10.x

/opt/gnome/share/gnucash/guile-modules/gnucash/report
OSX bundle

(Gnucash.app)

Gnucash.app/Contents/Resources/share/gnucash/guile-modules/gnucash/report Gnucash.app/Contents/Resources/share/gnucash/scm/gnucash/report
Windows C:\Program Files\gnucash\share\gnucash\guile-modules\gnucash\report C:\Program Files\gnucash\share\gnucash\scm\gnucash\report

Read the hello-world.scm report

hello-world.scm is specially written to demonstrate the basic structure of a report. However, don't get too confused by the huge number of options which are shown in that report - those were just added to show off the variety of options which are available inside gnucash.

By looking at the result of this report at the same time, you will easily get clues. You find this report in GnuCash under

  • Reports
    • Sample & Custom
      • Sample Report with Examples

account-piechart

As another example, here's how the file src/reports/standard-reports/account-piechart.scm works (line numbers for SVN r20800 version): There are two long Scheme functions: The first one is "option-generator" starting in line 84 which defines, well, the options for this report. The second one is "piechart-renderer" (line 191ff) and contains the code that does the actual calculation: The list of values that should be shown is calculated by the function call in line 377, using the selected accounts in the variable "topl-accounts". That function "traverse-accounts" is defined in line 336 and it is a recursive function that calls itself in line 349 to traverse through all children accounts of the account tree. For a single account, in line 346 it calls "profit-fn" which gets the balance amount of one single account. You can see that in "profit-fn"'s definition in line 253, which obtains the account balance either in one interval or at a given date. The function there "gnc:account-get-comm-balance-at-date" is defined in the file src/reports/report-system/html-utilities.scm, where it finally will call the functions from the C API about QofQuery. It will create a query for the account balance at the given date.

Well, long story short, this calculation is rather involved. Sorry.

Setup a prototype report

Even if you haven't ever written a report before, and you can't come up with a shiny track record of great Scheme experience, setting up a prototype at this moment will have the benefits getting productive after some time of pure theory.

The beginners amongst us might not have a final picture of what report to write. No worries, take the hello-world.scm report source file, store it in your preferred working directory, and rename it to a unique name, say my-world.scm. As, for sure, you already have read through this report, you know that this report is very wordy, giving a lot of text printouts. These can be used to easily see your own first changes on the screen once this prototype is loaded into GnuCash, and even better, it will let you differentiate between the my-world.scm that you have loaded and the hello-world.scm that is available in GnuCash by default (see previous section). So feel free to implement some fancy printout changes.

Prerequisites

There are two edits that you have to do in your report source file before loading the report into GnuCash:

  1. To avoid symbol definition conflicts with other reports, make sure your report code begins with a define-module statement:
    (define-module (gnucash report unique-report-name))
    like for example
    (define-module (gnucash report my-world-report))
  2. To enable GnuCash to register your report into the Report menu, go to the end of the code and update the gnc:define-report statement:
    1. Set the name that will be shown in the menu:
      'name (N_ "My World")
    2. Further down below comment out the menu-name line:
      ;;'menu-name (N_ "Sample Report with Examples")
    3. Update the tool tip:
      'menu-tip (N_ "Unstable. Used for Testing.")
  • Make sure your report has
  • GnuCash 2.2.x and before: a unique name or
  • GnuCash 2.3.x and later: a unique id. GnuCash will fail to start if multiple reports have the same unique id. For this reason, if you wish to create a backup of a report while you work on it, place the backup outside the GnuCash directories. If you need some newly generated unique id, run the program
    gnucash-make-guids
    which is being installed by gnucash as well. You may alternatively run the command:
    uuidgen | sed -e s/-//g
    Copy the newly generated ID into
    'report-guid "copy-here-the-new-generated-unique-ID"

There are two ways to load a report at startup of GnuCash:

  • from a user account or
  • from the installation tree.

You will likely want to use the user account approach - a least until your work is finished.

Load the report from a user account

This method is used if you edit your report source file in a working directory.

In your settings directory:

Operating System Settings Directory
Linux/Unix .gnucash in your home directory
Windows Vista, Win7, and newer C:\Users\YourName\.gnucash
Windows XP C:\Documents and Settings\YourName\.gnucash
OSX Bundle (Gnucash.app) Library/Applications Defaults/Gnucash or Library/Applications Support/Gnucash (Lion) in your home folder

... edit config.user to add a line of the form:

(load (gnc-build-dotgnucash-path "my-report.scm"))

Note: (gnc-build-dotgnucash-path ...) will complement your report name with the full path of your settings directory as shown in above table.

  • If the config.user file is not yet found in your settings directory, simply create it.

Move, copy, or link* your report file (my-report.scm) from your working directory to the above settings directory. The report should be visible in the Reports menu after the next restart.

* On Unix-like OSs you can use the ln command; on Windows (7 and higher) you can use the mklink command.

Caution: For older versions of GnuCash (before 2.1.x ?) load-from-path was suggested to load reports instead of load, but this is not compatible with the module definition that is now found in all reports. Using load-from-path on a report with module defninition will cause a crash

To reload your report, you must restart GnuCash. You will have to do this every time you change a report.

Thanks to DeanCording for clarifying the define-module/load bits


Load the report from the installed report directory

While not recommended you can also copy the report to the installed report directory. Make sure you have included a module definition as shown above. All *.scm files from the directory guile-modules/gnucash/report/standard-reports/ will be loaded automatically. This applies only to the standard-reports/ sub-directory, not to any of the other directories with reports. Hence, the easiest way to have your report available to gnucash is to copy your *.scm file into that directory.

Then restart GnuCash. You will have to do this every time you change the report definition file.

Debugging your report

There is not really a debugger available for guile, but you can have your code write debug messages to help you trace your code.

  • Start GnuCash like
    gnucash --debug --log gnc.scm=debug
    to enable debugging messages.
  • Add debugging messages with the (gnc:debug) variable, e.g. (gnc:debug "here I am").
  • There are also (gnc:msg), (gnc:warn) and (gnc:error) functions; see src/scm/main.scm for more details.
  • Messages will be logged to $TEMP/gnucash.something.trace by default (on Windows %TEMP%/gnucash.something.trace), you can change this with --logto (try 'stderr' or 'stdout').

Development Environment

Programming tools

Any reasonable source/text editor, including emacs and vi, should provide basic syntax support for source-code editing. One of the most basic and important for editings scheme/lisp sources is parenthesis matching. Other scheme environments (such as drScheme) might also be useful for editing the sources, but note that they might allow constructs that are not valid in guile.

Simple Proposal for Linux

This is a simple proposal for a development environment in Linux. Assume

  • there is a working directory ~/GnuCash/CustomReports in your home directory.
  • the new report is stored in the test00.scm file

Here is the proposal how to setup up your environment

cd ~/GnuCash/CustomReports
ln -s test00.scm prototype.scm
cat > config.user << "EOF"
(load "<fullPathTo>/GnuCash/CustomReports/prototype.scm")
EOF
cd ~/.gnucash
ln -s ~/GnuCash/CustomReports/config.user
uuidgen | sed -e s/-//g

Prepare test00.scm to include

  • the define-module statement
(define-module (gnucash report prototype-report))
  • following updates in the gnc:define-report statement
'name (N_ "Prototype")
;;'menu-name (N_ "Sample Report with Examples")
'menu-tip (N_ "Unstable. Used for Testing.")
'report-guid "the-new-generated-unique-ID"

See also the minimum report defintion in the #Designing new Reports chapter.

By this you can

  • use test00.scm as a template test report and use the lines as described above without further changes
  • collect all our test reports as e.g. testXX.scm files in this directory
  • switch between them by making the prototype.scm point to the desired report
  • restart GnuCash
  • always find the report under Reports->Sample & Custom Report->Prototype

Finally, you should also extract a GnuCash source tar ball in ~/GnuCash/CustomReport/ to have access to the Scheme files referenced in this page.

Technique to reload reports without restarting GnuCash

Reports can be modified to allow the majority of the report to be reloaded without requiring GnuCash to be restarted for each change which is very convenient when developing reports. This requires splitting the report into two files:

  1. a minimal loader which which forces the reload of the meat of your report each time options are generated or report is rendered.
  2. the meat of your report. This contains actual report code for the options generator and renderer.

Both files must parse and execute correctly before the reload will function.

Minimal Example

The following is a skeleton outline of what is required for a report to be reloaded on the fly. Tested with GnuCash 2.6.17.

Minimal Loader

custom_import.scm:

(define-module (custom_import))
(use-modules (gnucash gnc-module))
(use-modules (gnucash gettext))
(gnc:module-load "gnucash/report/report-system" 0)
; load the renderer module once at the top level to get the symbols
(use-modules (custom_import_renderer))

; get and reload the module
(define (reload-report-module)
  (reload-module (resolve-module '(custom_import_renderer))))

; every time options are generated, reload the meat of the report
(define (options_loader)
  (reload-report-module)
  (custom_import_options))

; every time report is rendered, reload the meat of the report
(define (renderer_loader report-obj)
  (reload-report-module)
  (custom_import_renderer report-obj))

(gnc:define-report
 'version 1
 'name (N_ "report name")
 'report-guid "report unique id"
 'menu-tip (N_"report menu tip")
 'menu-path (list gnc:menuname-utility)
 'options-generator options_loader
 'renderer renderer_loader)

Edit red text as appropriate for your report.

The Meat of Your Report

custom_import_renderer.scm:

(define-module (custom_import_renderer))
 
; options for the report (called by loader after it reloads this module)
(define (custom_import_options)    
  (let* ((options (gnc:new-options)))  
    ; add your options here       
    options))

; report renderer (called by loader after it reloads this module)
(define (custom_import_renderer report-obj) 
  (let ((document (gnc:make-html-document)))
      ; add your renderer here
      document))

(export custom_import_options)
(export custom_import_renderer)
Configuration

You'll also need to edit config.user so that GnuCash can find the files above.

config.user:

(add-to-load-path "type the full path to above report files here")
(use-modules (custom_import))

Designing new Reports

In general, reports are divided into three sections

  • the Options-Generator (define the options for the report)
  • the Report-Renderer (create the HTML report)
  • the gnc:define-report statement (make the report available in GnuCash)

This is the minimum definition needed for a new GnuCash report:

;; -*-scheme-*-

;; This is a minimum report definition in GnuCash.
;; It illustrates the the minimum definitions needed to create
;; a new GnuCash report.
;; It will create an empty page with heading 'Prototype'.
;; To be used as template.

;; ------------------------------------------------------------------
;; Top-level definitions
;; ------------------------------------------------------------------

(define-module (gnucash report prototype))
(use-modules (gnucash gnc-module))
(use-modules (gnucash gettext))
(gnc:module-load "gnucash/report/report-system" 0)

;; ------------------------------------------------------------------
;; Define the Options for this report
;; ------------------------------------------------------------------

(define (options-generator)    
  (let* ((options (gnc:new-options)))         
    options))

;; ------------------------------------------------------------------
;; Render the HTML document
;; ------------------------------------------------------------------

(define (document-renderer report-obj)
  (let ((document (gnc:make-html-document)))
      document))

;; ------------------------------------------------------------------
;; Define the actual report
;; ------------------------------------------------------------------

(gnc:define-report
 'version 1
 'name (N_ "Prototype")
 'report-guid "paste generated unique report id here"
 'menu-tip (N_ "Unstable. Used for Testing.")
 'menu-path (list gnc:menuname-utility)
 'options-generator options-generator
 'renderer document-renderer)

The Options-Generator

Each report takes responsibility to build up an own database that holds the options for the report.

Usually it is a good habit to copy the relavant code from the hello-world.scm. In there you will find the database initializing

  • call to gnc:new-options

which will

  • create the container called options

which will later on be filled by

  • calling the help function add-option

which is a nice wrapper to eventually

  • call gnc:register-option

The gnc:...-procedures to create this database and to fill it with values are contained in gnucash/src/app-utils/options.scm.

gnucash/src/report/utility-reports/hello-world.scm presents a nice selection of example option definitions of following types:

gnc:make-simple-boolean-option
gnc:make-multichoice-option
gnc:make-string-option
gnc:make-date-option
gnc:make-number-range-option
gnc:make-color-option
gnc:make-account-list-option
gnc:make-list-option

On top of these, you find

gnc:make-text-option
gnc:make-font-option
gnc:make-currency-option
gnc:make-budget-option
gnc:make-commodity-option
gnc:make-complex-boolean-option
gnc:make-pixmap-option 
gnc:make-account-list-limited-option
gnc:make-account-sel-option
gnc:make-account-sel-limited-option
gnc:make-multichoice-callback-option
gnc:make-radiobutton-option
gnc:make-radiobutton-callback-option
gnc:make-internal-option
gnc:make-query-option
gnc:make-dateformat-option

in gnucash/src/app-utils/options.scm.

Also, gnucash/src/business/business-utils/business-options.scm provides some options

gnc:make-invoice-option
gnc:make-customer-option
gnc:make-vendor-option
gnc:make-employee-option
gnc:make-owner-option
gnc:make-taxtable-option
gnc:make-counter-option
gnc:make-counter-format-option

In general, the syntax for creating an option is

(define (gnc:make-<__type__>-option
         section                      ;; the tab-string in the option dialog
         name                         ;; the text for this option in the option dialog
         sort-tag                     ;; used to define the order in which the options are listed
         documentation-string         ;; help string shown when the mouse moved over the option
         default-value
         <__optioinal type specific parameters__>)

Note that section is free to be any text string. If section-string has not been used before, a new tab with this name will be created automatically. Nevertheless, note that gnucash/src/report/report-system/report.scm provides three default names. Re-use these before creating new names:

(define gnc:pagename-general (N_ "General"))
(define gnc:pagename-accounts (N_ "Accounts"))
(define gnc:pagename-display (N_ "Display"))

For a start, simply read through the define (options-generator) statement in hello-world.scm and copy what you need.

Nice to know:

  • The General option group does not need to be defined, it is part of the report definition per default. If you run the above minimum report definition, the General option group will automatically include a text field for the Report Name, a selection box for the Stylesheet, and a button to Reset defaults.
  • To find the option creation procedures in the source file tree you can use grep gnc:make-.*-option `find . -name "*.scm"` | grep define
  • The source file tree is found in
    • Debian and Ubuntu Linux: /usr/share/gnucash/scm

The Report-Renderer

Define how to apply the options (the actual report contents).

The overall goal of the Report-Renderer is to create an HTML-document and fill it in with the reports results to display it out to the user.

Similar as with the Options-Generator, hello-world.scm gives you a great introduction how this works in general.

The gnc:...-procedures are found in the src/report/report-system/html-*.scm source files.

After runnning the report you can press the Export button to save the generated HTML-Code into a file for viewing. Doing this for the above minimum prototype report gives the following result:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<style type="text/css">
h3 { font-family: Ubuntu; font-size: 15pt; font-weight: bold;  }
a { font-family: Ubuntu; font-size: 10pt; font-style: italic;  }
body, p, table, tr, td { text-align: left; font-family: Ubuntu; font-size: 10pt;  }
tr.alternate-row { background: #ffffff }
th.column-heading-left { text-align: left; font-family: Ubuntu; font-size: 10pt;  }
th.column-heading-center { text-align: center; font-family: Ubuntu; font-size: 10pt;  }
th.column-heading-right { text-align: right; font-family: Ubuntu; font-size: 10pt;  }
td.neg { color: red;  }
td.number-cell, td.total-number-cell { text-align: right; white-space: nowrap; }
td.date-cell { white-space: nowrap; }
td.anchor-cell { white-space: nowrap; font-family: Ubuntu; font-size: 10pt;  }
td.number-cell { font-family: Ubuntu; font-size: 10pt;  }
td.number-header { text-align: right; font-family: Ubuntu; font-size: 10pt;  }
td.text-cell { font-family: Ubuntu; font-size: 10pt;  }
td.total-number-cell { font-family: Ubuntu; font-size: 12pt; font-weight: bold;  }
td.total-label-cell { font-family: Ubuntu; font-size: 12pt; font-weight: bold;  }
td.centered-label-cell { text-align: center; font-family: Ubuntu; font-size: 12pt; font-weight: bold;  }
</style>
<title></title>
</head>

<body bgcolor="#ffffff">
<h3></h3>
</body>
</html>

It can be seen that the style section is added automatically without specific definitions inside the prototoype source. Also note that the register name in GnuCash is not part of the HTML document.

The procedures to fill this HTML-document with life and further formating are given in source tree below

  • Linux Ubuntu: /usr/share/gnucash/scm

in the following files:

html-acct-table.scm
html-barchart.scm
html-document.scm
html-fonts.scm
html-linechart.scm
html-piechart.scm
html-scatter.scm
html-style-info.scm
html-style-sheet.scm
html-table.scm
html-text.scm
html-utilities.scm

Start making the prototype report a little nicer, adding the following line to the document-renderer from html-document.scm

(gnc:html-document-set-title! document (_ "GnuCash Report Prototype"))

will result in an update of the title and h3 lines:

[...]
<title>GnuCash Report Prototype</title>
[...]
<h3>GnuCash Report Prototype</h3>
[...]

Next it is possible to add attributes to the body line.

Note: You should read the following section just with informational intention. Since style sheets are now the preferred way to specify a document's presentation, the presentational attributes of BODY have been deprecated. (quoted from W3.org) (Currently in GnuCash the bgcolor-tag is default part of the body-tag.)

The body-tag can be enhanced with attributes via the gnc:html-document-set-style! funtion. The general sytax:

(gnc:html-document-set-style!
         document                               ;; the reference to the current html-document
	 "body"                                 ;; specify the tag to add attributes to
         'attribute (list "blabla" "balabala")  ;; first additional attribute
         'attribute (list "nonstop" "nonsens")  ;; second additional attribute
         'attribute (list "bgcolor" "#f6ffdb")  ;; third additional attribute
         [...]                                  ;; further attributes
)

The example above lists some imaginary attributes to indicate that the attribute definition will be added to the body-tag without further validity check. Invalid attributes will appear in the HTML-code but will have no visible effect on the document representation.

The rest of the body is filled with HTML-text by defintion of text objects, which gives the following structure

<body bgcolor="#ffffff">
<h3>[title]</h3>

  [text object 1]
  [text object 2]
    .     .    .
    .     .    .
    .     .    .
  [text object n]

</body>

whereas it does not matter if you define one or more text objects, you can put everything into one object or split it over several objects.

In Scheme these objects are defined like

(gnc:html-document-add-object!
         document               ;; the overall HTML document defined above
         (gnc:make-html-text    ;; a text object
	   [text 1]             ;; part 1 of the text
           [text 2]             ;; part 2 of the text
             .   .
             .   .
             .   .
           [text m]             ;; part m of the text
	 )
)

Note the above structure is the definition of 1 text object, which consists of m (sub-)text elements.

The text elements can be simple strings, or markup-formatted. Markup-commands are found in

  • Linux Ubuntu: /usr/share/gnucash/scm/html-text.scm:
gnc:html-markup-p        ;; markup for "paragraph"
gnc:html-markup-tt       ;; markup for fixed font (type writer style)
gnc:html-markup-em       ;; markup for "emphasis"
gnc:html-markup-b        ;; markup for "bold"
gnc:html-markup-i        ;; markup for "italic"
gnc:html-markup-h1       ;; markup for headers on level 1
gnc:html-markup-h2       ;; markup for headers on level 2
gnc:html-markup-h3       ;; markup for headers on level 3
gnc:html-markup-br       ;; markup for line "break" (no text)
gnc:html-markup-hr       ;; markup for "horizontal line" (no text)
gnc:html-markup-ul       ;; markup for "unsorted list" (bullet list)
gnc:html-markup-anchor   ;; markup for hyperlinks
gnc:html-markup-img      ;; markup for images

To give you a basic idea: Following example of simple text objects

(gnc:html-document-add-object!
         document
         (gnc:make-html-text 
	   "some text" 
	   "some other text" 
	   (gnc:html-markup-br)
	   (gnc:html-markup-tt "tt text")
	   (gnc:html-markup-h1 "header1 text")
	   (gnc:html-markup "bla" "tirili flöt")
	   (gnc:html-markup "i" "italic text")
	 )
)

will result in following HTML-code

<body bgcolor="#f6ffdb">
<h3>GnuCash Report Prototype</h3>
some text some other text
<br />
<tt>tt text</tt>

<h1>header1 text</h1>

<bla>tirili flöt</bla>

<i>italic text</i>

</body>

Note that it is possible to define new tags (here: "bla") if needed by using gnc:html-markup.

Again: Take a good look at hello-world.scm and explore many more expamples how to format HTML-text.

Also, be aware to examine

html-scatter.scm
html-acct-table.scm
html-piechart.scm
html-table.scm
html-linechart.scm

to find out more about

gnc:make-html-scatter
gnc:make-html-acct-table
gnc:make-html-barchart
gnc:make-html-table
gnc:make-html-linechart

The gnc:define-report Statement

If you want to follow the #Simple Proposal for Linux to setup a simple development environment then you need updates to this section only

  • once that you set up the development environment
  • once that your report is ready, fully tested, and shall become part of your standard reports

And again, hello-world.scm already proposes how you should proceed in the latter case

[...] 
to contribute your brand new, totally cool report, consult the mailing list "mailto:gnucash-devel@gnucash.org"
[...]

Barcharts

The minimum definition is of a bar chart report is shown in the example below:

;; -*-scheme-*-

;; This is a minimum barchart report definition in GnuCash.
;; It illustrates the the minimum definitions needed to create
;; a new GnuCash barchart report.
;; It will create a page with heading 'Prototype'.
;; To be used as template.

;; ------------------------------------------------------------------
;; Top-level definitions
;; ------------------------------------------------------------------

(define-module (gnucash report prototype))
(use-modules (gnucash gnc-module))
(gnc:module-load "gnucash/report/report-system" 0)

;; ------------------------------------------------------------------
;; Define the Options for this report
;; ------------------------------------------------------------------

(define (options-generator)    
  (let* ((options (gnc:new-options)))         
    options))

;; ------------------------------------------------------------------
;; Render the HTML document
;; ------------------------------------------------------------------

(define (document-renderer report-obj)
  (let (
         (document (gnc:make-html-document))
         (chart (gnc:make-html-barchart))
       )

       (gnc:html-barchart-set-title! chart "Barchart Title")		;; optional
       (gnc:html-barchart-set-subtitle! chart "Barchart Sub-Title")	;; optional
       (gnc:html-barchart-set-width! chart 400)
       (gnc:html-barchart-set-height! chart 400)
       (gnc:html-barchart-set-row-labels! chart '("row1" "row2"))
       (gnc:html-barchart-set-y-axis-label! chart "y-Axis-Label")	;; optional
       (gnc:html-barchart-set-x-axis-label! chart "x-Axis-Label")	;; optional
       (gnc:html-barchart-append-column! chart '(100 200))
       (gnc:html-barchart-append-column! chart '(110 210))

       (gnc:html-barchart-set-col-labels! chart '("col1" "col2"))
       (gnc:html-barchart-set-col-colors! chart '("green" "blue"))
       
       (gnc:html-document-add-object! document chart)

       document ;; RETURN value
  )
)

;; ------------------------------------------------------------------
;; Define the actual report
;; ------------------------------------------------------------------

(gnc:define-report
 'version 1
 'name (N_ "Prototype")
 'report-guid "paste generated unique report id here"
 'menu-tip (N_ "Unstable. Used for Testing.")
 'menu-path (list gnc:menuname-utility)
 'options-generator options-generator
 'renderer document-renderer)

and it will create the following line in the report:

<img src="data:image/png;base64,<very_long_ASCII_coded_string>" alt="Cannot display barchart"/>  

meaning, the graph is coded inline as ASCII-string within the <img> statement.

The GnuCash API

The GnuCash application programming interface (master branch) is quite intimidating, unfortunately. Luckily, for the reports, most of the stuff needed can be found in the scheme sources. Here some random examples of handy procedures (paths shown refer to the location in a source tarball; might be copied into the location as above in your installation):

  • create a monetary object: gnc:make-gnc-monetary src/engine/gnc-numeric.scm
  • get the amount of a monetary object: gnc:gnc-monetary-amount src/engine/gnc-numeric.scm
  • get an account name: gnc-account-get-name src/engine/swig-engine.c
  • create a commodity collector: gnc:make-commodity-collector src/report/report-system/report-utilities.scm

Watch out for the gnucash version in use: In 2.0.x, the Scheme wrappers were created by G-WRAP, started with gnc: (with a colon) and were written into scheme files of the name gw-something.scm. In 2.1.x and later, the Scheme wrappers are created by SWIG, start with gnc- (a dash, not a colon) and were written into C files of the name swig-something.c. Please keep that in mind if the old documentation points you towards functions like these: Get an account name: gnc:account-get-name src/engine/gw-engine-spec.scm - such a function would now be called gnc-account-get-name and would be found in src/engine/engine.i or the generated file src/engine/swig-engine.c.

The mightiness of the API is huge. Doing a grep on swig-engine.c for

  • scm_c_define_gsubr will return 866 results (i.e. in theory 866 routines that can be called via guile)
  • scm_c_define_gsubr\.*gnc-\.* will return 337 results

(Status: GnuCash 2.4.10)

It is by far too much to be documented in this Wiki-page.

However, having a table at hand which includes the most common function calls is convenient especially at the start of digging into it.

That is why following table is included in this chapter. The table does not purport to be exhaustive, nor even aim to be, but Scheme-Report developers are invited to add to this table whenever they come across additions of general interest.

Name Source Example Comments
gnc:account-get-balance-at-date report-utilities.scm Returns the account balance as a gnc-numeric record. To get the float value it is possible to use gnc:gnc-numeric-num and gnc:gnc-numeric-denom (see below). Example:
(let* (
        (bal 
            (gnc:account-get-balance-at-date
               acct 
               date
               #f ;; include children?
            )
        )
        (num (gnc:gnc-numeric-num bal))
        (denom (gnc:gnc-numeric-denom bal))
      )
      (/ num denom 1.0)
)
gnc:html-table-append-row! html-table.scm - Appends a row to a HTML table.
Note that row can be a list. If so then each list element represents a column entry.
Example:
(gnc:html-table-append-row! table (list e1 e2 e3))
will result in
<tr>
<td>e1<td>
<td>e2<td>
<td>e3<td>
</tr>
Note that only simple lists are supported for this. If you use nested lists as input, then the whole list contents of the nested lists will be displayed.
gnc:gnc-numeric-denom gnc-numeric.scm Returns the denominator part of a gnc-numeric record.
gnc:gnc-numeric-num gnc-numeric.scm Returns the numerator part of a gnc-numeric record.
gnc-account-get-full-name swig-engine.c hello-world.scm Returns the account name in the format
ParentLevel1:ParentLevel2:...:AccountName
To only get the AccountName use xaccAccountGetName
gnc-transaction-get-date-posted swig-engine.c - Returns the posting date of a transaction. Transactions are return e.g. by xaccSplitGetParent, see below. Note that this function will return the date as numerical value. If you need to have it human readable, you need to convert this numerical value into a date string. You can do this according to following example:
(gnc-print-date (gnc-transaction-get-date-posted (xaccSplitGetParent split)))
gnc-window-show-progress swig-gnome-utils.c report-utilities.scm Used to forward processing progress information to the user. In report-utilities.scm this is wrapped in the routines
gnc:report-starting
gnc:report-render-starting
gnc:report-percent-done
gnc:report-finished

The standard report cash-flow.scm is making use of this.
xaccAccountGetDescription swig-engine.c - Returns the account description. To be used with the account as input parameter
(xaccAccountGetDescription acct)
xaccAccountGetName swig-engine.c hello-world.scm Returns the account name in the format
AccountName
To get the full AccountName including parent names use gnc-account-get-full-name
xaccAccountGetNotes swig-engine.c - Returns the account notes, which is the text field that is found in the edit dialog of the accounts. To be used with the account as input parameter
(xaccAccountGetNotes acct)
xaccAccountGetSplitList swig-engine.c report-utilities.scm Returns the the list of transactions in a given account. Note that in GnuCash each transaction is a split even if it is not a split transaction. A non-split transaction is a transaction consisting of a single split.
To get the numerical value for the amount of splits in a list of accounts use gnc:accounts-count-splits defined in report-utilities.scm
The standard report cash-flow.scm is making use of this.
xaccAccountGetType swig-engine.c - Returns the account type, which is the text field that is found in the edit dialog of the accounts. To be used with the account as input parameter (xaccAccountGetNotes acct)


Following types are available:

ACCT-TYPE-BANK
ACCT-TYPE-CASH
ACCT-TYPE-CREDIT
ACCT-TYPE-ASSET
ACCT-TYPE-LIABILITY
ACCT-TYPE-STOCK
ACCT-TYPE-MUTUAL
ACCT-TYPE-CURRENCY
ACCT-TYPE-INCOME
ACCT-TYPE-EXPENSE
ACCT-TYPE-EQUITY
ACCT-TYPE-CHECKING
ACCT-TYPE-SAVINGS
ACCT-TYPE-MONEYMRKT
ACCT-TYPE-RECEIVABLE
ACCT-TYPE-PAYABLE
ACCT-TYPE-CREDITLINE
ACCT-TYPE-TRADING
xaccSplitGetAccount swig-engine.c - Returns the account that the split belongs to. Note that this is not a name string. To get the name of the account use
(xaccAccountGetName (xaccSplitGetAccount split))
xaccSplitGetCorrAccountName swig-engine.c - Returns the account name at the other end of the split as a string.
xaccSplitGetParent swig-engine.c - Returns the parent transaction the split belongs to. See gnc-transaction-get-date-posted for an example how to use it.

Other Resources

One other way to create custom reports outside GnuCash, but directly from GnuCash data, is to use Ledger-CLI.

Old GnuCash Report Information

(may be very out of date)

Learning Scheme