Difference between revisions of "Custom Reports"

From GnuCash
Jump to: navigation, search
(Use some styling to show highlight where reader should be making changes. Reword a bit. Highlighting in preformatted does not seem to be supported in lists, so lost the list formatting; hopefully it is more readable.)
(maint -> stable)
 
(101 intermediate revisions by 10 users not shown)
Line 1: Line 1:
 +
[[Category:API]] [[Category:Customization]] [[Category:Development‏‎]]
 +
 +
This documentation applies from '''GnuCash Version 5.0'''. For prior versons use the '''[https://wiki.gnucash.org/wiki/index.php?title=Custom_Reports&oldid=21603 previous version]'''.
 +
 
== Custom Reports in GnuCash ==
 
== Custom Reports in GnuCash ==
 
 
The term ''Custom Reports'' has several contexts in GnuCash:
 
The term ''Custom Reports'' has several contexts in GnuCash:
 
* Customizing settings for standard reports ([[Using GnuCash#Saved Report Configurations]])
 
* Customizing settings for standard reports ([[Using GnuCash#Saved Report Configurations]])
 
* Combining selected standard reports into one view ([[Using GnuCash#Custom Multicolumn Report]])
 
* Combining selected standard reports into one view ([[Using GnuCash#Custom Multicolumn Report]])
 
* Customized output format for reports ([[Custom Reports Using Eguile]])
 
* Customized output format for reports ([[Custom Reports Using Eguile]])
* Reports written in Scheme which are not delivered as part of the standard reports (this page)
+
* Reports written in the Scheme programming language which are not delivered as part of the standard reports (this page)
  
If you are not up into coding, you should check the
+
If you are not up for coding, you should check the
 
* report options
 
* report options
 
* stylesheets and
 
* stylesheets and
 
* stylesheet options and
 
* stylesheet options and
 
* file properties.
 
* file properties.
Possibly there are ways to get what you desired.
+
Possibly there are ways to get what you desire without coding.
  
 
If you are ready for coding (and even already firm in Scheme and Guile) then this is the place to contribute.
 
If you are ready for coding (and even already firm in Scheme and Guile) then this is the place to contribute.
  
 
== Introduction ==
 
== Introduction ==
 +
Custom reports can be fairly challenging and while the information presented here is brief it should be enough to get you started. The focus is on enough understanding to change (hack) existing reports.
  
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''. Understanding Scheme is one of the prerequisites to create new reports.
 +
The obvious drawback is that one must learn yet another programming language (if not already familiar with it) but saves the effort of having to alter and build GnuCash's source code.
  
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.
+
''Guile'' is used as an 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.
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.
  
Last but not least the API for that sort of thing is not formally specified.
+
Still reading? Not yet discouraged? Good for you! Thankfully, lots of help is available.
  
Still reading? Not yet discouraged? Good on you! Because there is lots of help available.
+
First of all, there is good educational material available on the web to help you learn Scheme and Guile. Secondly, there is a simple <tt>sample-report.scm</tt> example report specifically written to show you the base layout of a GnuCash report. And finally, this Wiki page will give you some guidance when starting this venture.
 
 
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 <code>hello-world.scm</code> 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 ==
 
== Getting Started ==
 +
This tutorial will give you an overview of GnuCash reports and might give you the confidence to make simple changes to existing reports.
  
=== Get to know ''Scheme''===
+
=== Appreciation of ''Scheme'' language ===
 +
GnuCash reports are written in the Scheme programming language. For a quick introduction try [https://artanis.dev/scheme.html Learn Scheme in 15 minutes] using an [https://replit.com/languages/scheme online scheme repl].
  
* Mastering Scheme is highly eased after reading [http://www.scheme.com/tspl2d/ The Scheme Progamming Language] by R. Kent Dybvig
+
=== Language details ===
 +
This tutorial is self-contained but to extend it in reports you'll want to use the following references and learn about the language. Just be aware of them for now.
  
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 [http://www.scheme.com/tspl2d/start.html#g1546 Getting Started] section.
+
==== Get to know ''Scheme'' ====
 +
* Mastering Scheme is much easier if you've read [https://www.scheme.com/tspl4/ The Scheme Programming Language] by R. Kent Dybvig.
  
=== Get to know ''Guile''===
+
If you are new to ''Scheme'' it is not necessary to read and understand all of it right now. For anything more than this tutorial you should, at least, have gone through the [https://www.scheme.com/tspl4/start.html#./start:h0 Getting Started] section.
  
* [http://www.gnu.org/software/guile/docs/docs.html Guile documentation]
+
==== Get to know ''Guile'' ====
 +
Guile is used internally by GnuCash to ''interpret'' the Scheme reports.  
  
This comes with a marvellous [http://www.gnu.org/software/guile/docs/guile-tut/tutorial.html 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''.
+
* [{{URL:guile}}docs/docs.html Guile documentation]
  
=== Get to know ''Gettext''===
+
This comes with a marvelous [{{URL:guile}}docs/guile-tut/tutorial.html Tutorial]. You don't need this for writing the reports themselves, but it gives a clue of how reports are created in GnuCash. This should be good motivation to go and tackle the learning curve for ''Scheme''.
  
That is the tool which makes the strings translatable. <code>(_ "Some Text")</code>, <code>(N_ "Some Text")</code> and similar mark the text for translation. See [[Translation#How to make strings in code translatable]] for details.
+
==== Get to know ''Gettext'' ====
 +
That is the tool which makes the strings translatable. <syntaxhighlight lang="scm" inline>(G_ "Some Text")</syntaxhighlight>, <syntaxhighlight lang="scm" inline>(N_ "Some Text")</syntaxhighlight> and similar mark the text for translation. See [[I18N#How to make strings in code translatable]] for details.
 +
<references />
  
 
=== Where to find existing reports ===
 
=== Where to find existing reports ===
  
The location varies with different operating systems:
+
The location of existing reports varies with by operating systems. The <tt>guile</tt> path can be found in <tt>Help -> About -> GNC_DATA</tt> by selecting the parent folder.:
  
{| border="1" cellspacing="0" cellpadding="2"
+
{| class="wikitable"
|-
 
!scope="col"| Operating System
 
!scope="col"| Existing Reports Location (2.4.x)
 
!scope="col"| Existing Reports Location (2.6.x)
 
|-
 
!scope="row"| BSD
 
| <tt>/usr/local/share/gnucash/guile-modules/gnucash/report</tt>
 
| <tt>/usr/local/share/gnucash/scm/gnucash/report</tt>
 
|-
 
!scope="row"| ''Debian''
 
incl. derivatives
 
such as Ubuntu
 
| <tt>/usr/share/gnucash/guile-modules/gnucash/report</tt>
 
| <tt>/usr/share/gnucash/scm/gnucash/report</tt>
 
|-
 
!scope="row"| ''Gentoo'' and
 
''Foresight''
 
| <tt>/usr/share/gnucash/guile-modules/gnucash/report</tt>
 
| <tt>/usr/share/gnucash/scm/gnucash/report</tt>
 
|-
 
!scope="row"| ''OpenSuse''
 
10.x and newer
 
| <tt>/usr/share/gnucash/guile-modules/gnucash/report</tt>
 
| <tt>/usr/share/gnucash/scm/gnucash/report</tt>
 
 
|-
 
|-
!scope="row"| ''OpenSuse''
+
!scope="col" style="width: 150px;" | Operating System
up to 10.x
+
!scope="col"| Path
| <tt>/opt/gnome/share/gnucash/guile-modules/gnucash/report</tt>
 
|  
 
 
|-
 
|-
!scope="row"| ''OSX bundle''
+
!scope="row"| All Linux except Debian with flatpak including derivatives such as UbuntuBSD
(Gnucash.app)
+
| <tt>.../<''guile-version''>/gnucash/reports</tt>
| <tt>Gnucash.app/Contents/Resources/share/gnucash/guile-modules/gnucash/report</tt>
 
| <tt>Gnucash.app/Contents/Resources/share/gnucash/scm/gnucash/report</tt>
 
 
|-
 
|-
!scope="row"| ''Windows''
+
!scope="row"| Debian with flatpak including derivatives such as Ubuntu, OSX bundle (Gnucash.app), Windows
| <tt>C:\Program Files\gnucash\share\gnucash\guile-modules\gnucash\report</tt>
+
| <tt>.../guile/site/2.2/gnucash/reports</tt>
| <tt>C:\Program Files\gnucash\share\gnucash\scm\gnucash\report</tt>
 
 
|}
 
|}
  
=== Read the <code>hello-world.scm</code> report ===
+
=== Study some example reports ===
  
<tt>hello-world.scm</tt> 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.
+
==== sample-report ====
 +
<tt>sample-report.scm</tt> was created in GnuCash V5.0 from <tt>hello-world.scm</tt> to demonstrate the basic structure of a report. Don't get too confused by the huge number of options that are shown in this report - they were added to show off the variety of options available in 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
+
Have a look under [[#Where to find existing reports]] to find the source code for this report. Alternatively, you can browse [https://github.com/Gnucash/gnucash/blob/stable/gnucash/report/reports/example/sample-report.scm the current source code for this report on github].
* Reports
 
** Sample & Custom
 
*** Sample Report with Examples
 
  
==== account-piechart ====
+
By looking at the result of this report while you study the source code, you will easily get clues to how it functions. You can run this report in GnuCash via the menu: Reports -> Examples -> Sample Report
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.
+
==== account-piecharts ====
 +
If you want to walk through a much more complicated report, study [https://github.com/Gnucash/gnucash/blob/65bb60d62182d17eeb885f25976bc49767068ee3/gnucash/report/standard-reports/account-piecharts.scm <tt>account-piecharts.scm</tt>]. 
 +
 
 +
There are two long functions in this report.
 +
# [https://github.com/Gnucash/gnucash/blob/65bb60d62182d17eeb885f25976bc49767068ee3/gnucash/report/standard-reports/account-piecharts.scm#L86 <code>option-generator</code>] defines the options for this report.
 +
# [https://github.com/Gnucash/gnucash/blob/65bb60d62182d17eeb885f25976bc49767068ee3/gnucash/report/standard-reports/account-piecharts.scm#L354 <code>piechart-renderer</code>] makes all the calculations and renders the pie chart.
 +
 
 +
The list of values to be shown in the pie chart can be calculated in two ways - [https://github.com/Gnucash/gnucash/blob/65bb60d62182d17eeb885f25976bc49767068ee3/gnucash/report/standard-reports/account-piecharts.scm#L322 depth-based] or [https://github.com/Gnucash/gnucash/blob/65bb60d62182d17eeb885f25976bc49767068ee3/gnucash/report/standard-reports/account-piecharts.scm#L282 via a method that traverses all accounts]. The decision for this is made when [https://github.com/Gnucash/gnucash/blob/65bb60d62182d17eeb885f25976bc49767068ee3/gnucash/report/standard-reports/account-piecharts.scm#L642 calling the <code>piechart-renderer</code> function]. Both methods will work from a list of selected accounts stored in the [https://github.com/Gnucash/gnucash/blob/65bb60d62182d17eeb885f25976bc49767068ee3/gnucash/report/standard-reports/account-piecharts.scm#L404 <code>topl-accounts</code> variable].
 +
 
 +
[https://github.com/Gnucash/gnucash/blob/65bb60d62182d17eeb885f25976bc49767068ee3/gnucash/report/standard-reports/account-piecharts.scm#L282 <code>traverse-accounts</code>] is a recursive function that [https://github.com/Gnucash/gnucash/blob/65bb60d62182d17eeb885f25976bc49767068ee3/gnucash/report/standard-reports/account-piecharts.scm#L294 calls itself] to traverse through all child accounts in the account tree. To get the balance for a single account, it makes a [https://github.com/Gnucash/gnucash/blob/65bb60d62182d17eeb885f25976bc49767068ee3/gnucash/report/standard-reports/account-piecharts.scm#L482 call to <code>profit-fn</code>].  [https://github.com/Gnucash/gnucash/blob/65bb60d62182d17eeb885f25976bc49767068ee3/gnucash/report/standard-reports/account-piecharts.scm#L418 <code>profit-fn</code>] obtains the account balance for either one interval or at a given date. It calls out to [https://github.com/Gnucash/gnucash/blob/65bb60d62182d17eeb885f25976bc49767068ee3/gnucash/report/report-system/report-utilities.scm#L502 <code>gnc:account-get-comm-balance-at-date</code> in <tt>report-utilities.scm</tt>] where, finally, lower level calls are made, which create a query for the account balance at the given date.
 +
 
 +
Well, long story short, this report is rather involved. Sorry.
  
 
=== Setup a prototype report ===
 
=== 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.
+
Even if you haven't ever written a report before, and you don't have 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 <tt>hello-world.scm</tt> report source file, store it in your preferred working directory, and rename it to a unique name, say <tt>my-world.scm</tt>.
+
The beginners amongst us might not have a final picture of what report to write. No worries, take the <tt>[[Custom_Reports#sample-report_report|sample-report.scm]]</tt> report source file, store it in your preferred working directory, and rename it to a unique name, say <tt>my-world.scm</tt>.
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 <tt>my-world.scm</tt> that you have loaded and the <tt>hello-world.scm</tt> that is available in GnuCash by default (see previous section). So feel free to implement some fancy printout changes.
+
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 <tt>my-world.scm</tt> that you have loaded and the <tt>sample-report.scm</tt> that is available in GnuCash by default (see previous section). So feel free to implement some fancy printout changes.
  
 
==== Prerequisites ====
 
==== Prerequisites ====
Line 126: Line 114:
 
To enable ''GnuCash'' to register your report into the Report menu, scroll to the end of the code and update the '''gnc:define-report statement'''.
 
To enable ''GnuCash'' to register your report into the Report menu, scroll to the end of the code and update the '''gnc:define-report statement'''.
  
Set the '''name''' of your report to be shown in the  Report menu. For GnuCash 2.2.x and before this name must be unique across all reports.
+
Set the '''name''' of your report to be shown in the  Report menu. This name must be unique across all reports.
 
  'name (N_ "<span style="color:green">My World</span>")
 
  'name (N_ "<span style="color:green">My World</span>")
  
Line 135: Line 123:
 
  'menu-tip (N_ "<span style="color:green">Unstable. Used for Testing.</span>")
 
  'menu-tip (N_ "<span style="color:green">Unstable. Used for Testing.</span>")
  
For GnuCash 2.3.x and later, your report must have a globally unique identifier (guid). 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
+
Your report must have a globally unique identifier (guid). 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, use an online uuid generator like [https://www.guidgenerator.com/ this one] (any other one will do as well). Be sure to untick "Hyphens" to generate gnucash compatible guids. If you forget or the site you use doesn't offer that option, simply remove the hyphens yourself.
<pre>gnucash-make-guids</pre>
+
 
which is included with gnucash. You may alternatively run the command:
+
Alternatively, in linux, run this construct <syntaxhighlight lang="sh">
<pre>uuidgen | sed -e s/-//g</pre>
+
uuidgen | sed -e 's/-//g'
 +
</syntaxhighlight><ref>Program 'uuidgen' is present in package 'util-linux' and 'sed' in 'sed'.</ref>
 +
 
 
Copy the newly generated ID and paste it into the '''report-guid''' value:
 
Copy the newly generated ID and paste it into the '''report-guid''' value:
 
  'report-guid "<span style="color:red">paste generated report unique id here</span>"
 
  'report-guid "<span style="color:red">paste generated report unique id here</span>"
  
==== Loading Your Report ====
+
=== Loading Your Report ===
 
There are ''two ways to load a report'' at startup of GnuCash:
 
There are ''two ways to load a report'' at startup of GnuCash:
 
* from a user account or
 
* from a user account or
Line 152: Line 142:
 
This method is used if you edit your report source file in a working directory.
 
This method is used if you edit your report source file in a working directory.
  
In your settings directory:
+
* Edit [[Configuration_Locations#GNC_CONFIG_HOME|GNC_CONFIG_HOME]]/<tt>config-user.scm</tt> to add a line of the form:
  
{| border="1" cellspacing="0" cellpadding="2"
+
<SyntaxHighlight lang="scheme">
|-
+
(load (gnc-build-userdata-path "my-world.scm"))
!scope="col"| Operating System
+
</SyntaxHighlight>
!scope="col"| Settings Directory
 
|-
 
!scope="row"| ''Linux/Unix
 
| <tt>.gnucash</tt> in your home directory
 
|-
 
!scope="row"| ''Windows Vista, Win7, and newer''
 
| <tt>C:\Users\YourName\.gnucash</tt>
 
|-
 
!scope="row"| ''Windows XP''
 
| <tt>C:\Documents and Settings\YourName\.gnucash</tt>
 
|-
 
!scope="row"| ''OSX Bundle'' (Gnucash.app)  
 
| <tt>Library/Applications Defaults/Gnucash</tt> or <tt>Library/Applications Support/Gnucash</tt> (Lion) in your home folder
 
|}
 
  
... edit <tt>config.user</tt> to add a line of the form:
+
;Notes:
 
+
:* ''(gnc-build-userdata-path ...)'' or ''(gnc-build-dotgnucash-path ...)'' will complement your report name with the full path of your [[Configuration_Locations#GNC_DATA_HOME|GNC_DATA_HOME]] or [[Configuration_Locations#DOT_GNUCASH_DIR|DOT_GNUCASH_DIR]] directory respectively. If you are comfortable with file locations you could equally well use the form
<pre>
+
:<SyntaxHighlight lang="scheme">
(load (gnc-build-dotgnucash-path "my-report.scm"))
+
(load "<absolute path to>/my-world.scm")
</pre>
+
</SyntaxHighlight>
'''Note:''' ''(gnc-build-dotgnucash-path ...)'' will complement your report name with the full path of your settings directory as shown in above table.
+
::to load your report from any arbitrary location on your file system.
* If the <tt>config.user</tt> file is not yet found in your settings directory, simply create it.
+
:* The instructions refer to two separate directories: [[Configuration_Locations#GNC_CONFIG_HOME|GNC_CONFIG_HOME]] and [[Configuration_Locations#GNC_DATA_HOME|GNC_DATA_HOME]]. Be careful to use the proper one in the different locations as indicated.
 +
:*If the <tt>config.user</tt> or <tt>config-user.scm</tt> file is not yet found in your settings directory, simply create it.
  
Move, copy, or link* your report file (<tt>my-report.scm</tt>) from your working directory to the above settings directory. The report should be visible in the Reports menu after the next restart.
+
Move, copy, or link* your report file (<tt>my-world.scm</tt>) from your working directory to the proper [[Configuration_Locations#GNC_DATA_HOME|GNC_DATA_HOME]] or [[Configuration_Locations#DOT_GNUCASH_DIR|DOT_GNUCASH_DIR]] directory. The report should be visible in the Reports menu after the next restart.
  
 
<tt>*</tt> On Unix-like OSs you can use the <tt>ln</tt> command; on Windows (7 and higher) you can use the <tt>mklink</tt> command.
 
<tt>*</tt> On Unix-like OSs you can use the <tt>ln</tt> command; on Windows (7 and higher) you can use the <tt>mklink</tt> 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 [https://bugzilla.gnome.org/show_bug.cgi?id=618670 a crash]
 
  
 
To reload your report, you must '''restart''' GnuCash. You will have to do this '''every time''' you change a report.
 
To reload your report, you must '''restart''' GnuCash. You will have to do this '''every time''' you change a report.
  
''Thanks to [[User:DeanCording|DeanCording]] for clarifying the define-module/load bits''
+
==== Load the report from the installed report directory ====
  
 +
{| class="wikitable"
 +
|-
 +
|'''Tip:''' Despite the warning below, this can be the easiest method in Windows by sandboxing report development with a [https://sourceforge.net/projects/portableapps/files/GnuCash%20Portable/ <tt>Portable Apps version</tt>]. Since GnuCash 4.12 the portable <tt>guile</tt> path can be found in <tt>Help -> About -> GNC_DATA</tt> by selecting the parent folder.
 +
|}
  
 +
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 <tt>*.scm</tt> files from the <tt>gnucash/scm/gnucash/report/standard-reports/</tt> directory will be loaded automatically. This applies ''only'' to the <tt>standard-reports/</tt> 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.
  
==== Load the report from the installed report directory ====
+
;Note: In case of an eguile based report only the foo.scm file should be stored in the standard-reports directory. The accompanying <tt>foo.eguile.scm</tt> and <tt>foo.css</tt> should go in to <tt>gnucash/scm/gnucash/report</tt> instead.
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.
 
Then '''restart''' GnuCash. You will have to do this '''every time''' you change the report definition file.
  
 
=== Debugging your report ===
 
=== 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.
+
When guile cannot make sense of your report, or your report throws an error, GnuCash will present the following error message in place of your report:
 +
{| class="wikitable"
 +
|-
 +
|'''Report error'''
 +
An error occurred while running the report.
 +
|}
 +
 
 +
This lets you know there was a problem, but now you need to pinpoint where the problem lies.  Here are some tips that might help.
 +
 
 +
{| class="wikitable"
 +
|-
 +
! scope = "col" | Tip
 +
! scope = "col" | Details
 +
 
 +
|- style="vertical-align:top;"
 +
| Enable debug messages
 +
| Start GnuCash with debug command line parameters: <syntaxhighlight lang="sh">gnucash --debug --log gnc.scm=debug</syntaxhighlight> 
 +
On macOS, assuming GnuCash is in your <code>/Applications</code> folder, this would be:
 +
<syntaxhighlight lang="sh>/Applications/Gnucash.app/Contents/MacOS/Gnucash --debug --log gnc.scm=debug</syntaxhighlight>
 +
There are other debug related options, run GnuCash with the <code>--help</code> for a complete list.
 +
|- style="vertical-align:top;"
 +
| Study the trace logs
 +
| The GnuCash trace logs can sometimes give you that satisfying "oh, I see". By default you'll find the trace log:
 +
{| class="wikitable"
 +
|-
 +
! scope ="col" | Operating System
 +
! scope ="col" | Location
 +
|- style="vertical-align:top;"
 +
| Unix/Linux
 +
| <code>$TEMP/gnucash.something.trace</code>
 +
|- style="vertical-align:top;"
 +
| Windows
 +
| <code>%TEMP%/gnucash.something.trace</code>
 +
|- style="vertical-align:top;"
 +
| macOS
 +
| Somewhere under <code>/var/folders/</code> You can find it via:
 +
<syntaxhighlight lang="sh">find /var/folders -name "gnucash.trace" 2> /dev/null</syntaxhighlight>
 +
|}
 +
You can change the trace log file location via GnuCash command line parameter <code>--logto</code>. This parameter includes support for logging to <code>'stderr'</code> and <code>'stdout'</code>
 +
 
 +
|- style="vertical-align:top;"
 +
| Add your own debug messages
 +
| You can use the <code>gnc:debug</code> function to add your own messages.  For example: <syntaxhighlight lang="scheme">(gnc:debug "here I am")</syntaxhighlight>
 +
 
 +
|- style="vertical-align:top;"
 +
| Add other messages
 +
| There are also <code>gnc:msg</code>, <code>gnc:warn</code> and <code>gnc:error</code> functions; see [https://github.com/Gnucash/gnucash/blob/unstable/libgnucash/scm/utilities.scm] for more details.
 +
 
 +
|- style="vertical-align:top;"
 +
| Use a Scheme friendly editor
 +
| For the uninitiated, matching parentheses properly in a Scheme program can make one's eyes cross. A Lisp/Scheme friendly editor can really help here. DrRacket or a properly configured Emacs really helps.
 +
 
 +
|- style="vertical-align:top;"
 +
| Run often
 +
| Test your report often after making very small changes.  This will make it easier to understand when and where problems are introduced.
 +
|}
  
* Start GnuCash like <pre>gnucash --debug --log gnc.scm=debug</pre> to enable debugging messages.
+
Although guile does have debug support, this wiki page updater has not found a way, at this time, to hook GnuCash up to the guile debugger.
* Add debugging messages with the <tt>(gnc:debug)</tt> variable, e.g. <tt>(gnc:debug "here I am")</tt>.
 
* There are also (gnc:msg), (gnc:warn) and (gnc:error) functions; see src/scm/main.scm for more details.
 
* Messages will be logged to <tt>$TEMP/gnucash.something.trace</tt> by default (on Windows <tt>%TEMP%/gnucash.something.trace</tt>), you can change this with --logto (try 'stderr' or 'stdout').
 
  
 
== Development Environment ==
 
== Development Environment ==
Line 209: Line 240:
 
=== Programming tools ===
 
=== 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 [http://www.drscheme.org/ drScheme]) might also be useful for editing the sources, but note that they might allow constructs that are not valid in guile.
+
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-like environments (such as [https://racket-lang.org/ DrRacket]) might also be useful for editing the sources, but note that they might allow constructs that are not valid in guile. Beware Racket is a scheme dialect not 100% compatible with Guile, but provides a nice GUI for understanding scheme functions.
  
 
=== Simple Proposal for Linux ===
 
=== Simple Proposal for Linux ===
Line 216: Line 247:
 
Assume  
 
Assume  
 
* there is a working directory <code>~/GnuCash/CustomReports</code> in your home directory.
 
* there is a working directory <code>~/GnuCash/CustomReports</code> in your home directory.
* the new report is stored in the <code>test00.scm</code> file
+
* the new report is stored in the <tt>test00.scm</tt> file
 
Here is the proposal how to setup up your environment
 
Here is the proposal how to setup up your environment
<pre>
+
<syntaxhighlight lang="sh">
 
cd ~/GnuCash/CustomReports
 
cd ~/GnuCash/CustomReports
 
ln -s test00.scm prototype.scm
 
ln -s test00.scm prototype.scm
Line 227: Line 258:
 
ln -s ~/GnuCash/CustomReports/config.user
 
ln -s ~/GnuCash/CustomReports/config.user
 
uuidgen | sed -e s/-//g
 
uuidgen | sed -e s/-//g
</pre>
+
</syntaxhighlight>
  
Prepare <code>test00.scm</code> to include
+
Prepare <tt>test00.scm</tt> to include
 
* the define-module statement  
 
* the define-module statement  
<pre>(define-module (gnucash report prototype-report))</pre>
+
<syntaxhighlight lang="scheme">(define-module (gnucash report prototype-report))</syntaxhighlight>
 
* following updates in the <code>gnc:define-report</code> statement
 
* following updates in the <code>gnc:define-report</code> statement
<pre>'name (N_ "Prototype")</pre>
+
<syntaxhighlight lang="Scheme">'name (N_ "Prototype")
<pre>;;'menu-name (N_ "Sample Report with Examples")</pre>
+
;;'menu-name (N_ "Sample Report with Examples")
<pre>'menu-tip (N_ "Unstable. Used for Testing.")</pre>
+
'menu-tip (N_ "Unstable. Used for Testing.")
<pre>'report-guid "the-new-generated-unique-ID"</pre>
+
'report-guid "the-new-generated-unique-ID"</syntaxhighlight>
  
 
See also the minimum report defintion in the [[#Designing new Reports]] chapter.
 
See also the minimum report defintion in the [[#Designing new Reports]] chapter.
  
 
By this you can
 
By this you can
* use <code>test00.scm</code> as a template test report and use the lines as described above without further changes
+
* use <tt>test00.scm</tt> 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
 
* 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
 
* switch between them by making the prototype.scm point to the desired report
Line 259: Line 290:
 
# the meat of your report.  This contains actual report code for the options generator and renderer.
 
# 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.
+
Both files must parse and execute correctly before the reload will function.
 +
 
 +
Note that, at least in GnuCash 2.6.17, for changes to report options to take effect,  the report must closed and then relaunched from the Report menu. Changes to the render portion seem to be handled just fine by the reload button.  
  
 
====Minimal Example ====
 
====Minimal Example ====
 
The following is a skeleton outline of what is required for a report  
 
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.
 
to be reloaded on the fly. Tested with GnuCash 2.6.17.
 +
 +
;WARNING: This section is out of date and will not run with GnuCash &ge; 4.6
  
 
=====Minimal Loader  =====
 
=====Minimal Loader  =====
 +
Update <code>name</code>, <code>report-guid</code> and <code>menu-tip</code> values appropriately for your report.
 +
 
custom_import.scm:
 
custom_import.scm:
(define-module (custom_import))
+
<syntaxhighlight lang="scheme" highlight="24-26">
(use-modules (gnucash gnc-module))
+
(define-module (custom_import))
(use-modules (gnucash gettext))
+
(use-modules (gnucash gnc-module))
(gnc:module-load "gnucash/report/report-system" 0)
+
(use-modules (gnucash gettext))
; load the renderer module once at the top level to get the symbols
+
(gnc:module-load "gnucash/report/report-system" 0)
(use-modules (custom_import_renderer))
+
; 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)
+
; get and reload the module
  (reload-module (resolve-module '(custom_import_renderer))))
+
(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))
 
   
 
   
; every time options are generated, reload the meat of the report
+
(gnc:define-report
(define (options_loader)
+
'version 1
  (reload-report-module)
+
'name (N_ "<type your report name here>")
  (custom_import_options))
+
'report-guid "<paste report unique id here>"
+
'menu-tip (N_"<type your report menu tip here>")
; every time report is rendered, reload the meat of the report
+
'menu-path (list gnc:menuname-utility)
(define (renderer_loader report-obj)
+
'options-generator options_loader
  (reload-report-module)
+
'renderer renderer_loader)
  (custom_import_renderer report-obj))
+
</syntaxhighlight>
 
(gnc:define-report
 
  'version 1
 
  'name (N_ "<span style="color: red">report name</span>")
 
  'report-guid "<span style="color: red">report unique id</span>"
 
  'menu-tip (N_"<span style="color: red">report menu tip</span>")
 
  '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 =====
 
=====The Meat of Your Report =====
 
custom_import_renderer.scm:
 
custom_import_renderer.scm:
(define-module (custom_import_renderer))
+
<syntaxhighlight lang="scheme">
 
+
(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)
+
; options for the report (called by loader after it reloads this module)
(define (custom_import_renderer report-obj)  
+
(define (custom_import_options)  
  (let ((document (gnc:make-html-document)))
+
  (let* ((options (gnc:new-options)))
      ; add your renderer here
+
    ; add your options here      
      document))
+
    options))
 
   
 
   
(export custom_import_options)
+
; report renderer (called by loader after it reloads this module)
(export custom_import_renderer)
+
(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)
 +
</syntaxhighlight>
  
 
=====Configuration =====
 
=====Configuration =====
 
You'll also need to edit config.user so that GnuCash can find the files above.
 
You'll also need to edit config.user so that GnuCash can find the files above.
 +
Update <code>add-to-load-path</code> value appropriately for your setup.
  
 
config.user:
 
config.user:
(add-to-load-path "<span style="color: red">type the full path to above report files here</span>")
+
<syntaxhighlight lang="scheme" highlight="1">
(use-modules (custom_import))
+
(add-to-load-path "<type the full path to above report files here>")
 +
(use-modules (custom_import))
 +
</syntaxhighlight>
  
 
== Designing new Reports ==
 
== Designing new Reports ==
Line 330: Line 372:
 
* the Options-Generator (define the options for the report)
 
* the Options-Generator (define the options for the report)
 
* the Report-Renderer (create the HTML report)
 
* the Report-Renderer (create the HTML report)
* the <code>gnc:define-report</code> statement (make the report available in ''GnuCash'')
+
* the <code>gnc:define-report</code> statement (makes the report available in ''GnuCash'')
 +
 
 +
This is the minimum definition needed for a new ''GnuCash'' report. Update <code>name</code>, <code>report-guid</code><ref>Table of existing GUIDs: [[Report GUIDs]]</ref> and <code>menu-tip</code> values appropriately.
 +
 
 +
prototype.scm:
 +
 
 +
<syntaxhighlight lang="scheme" highlight="13,61-63">
 +
;; -*-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 reports example prototype))
 +
 
 +
(use-modules (gnucash engine))
 +
(use-modules (gnucash utilities))
 +
(use-modules (gnucash core-utils))
 +
(use-modules (gnucash app-utils))
 +
(use-modules (gnucash report))
 +
(use-modules (gnucash html))
 +
 
 +
(debug-enable 'backtrace)
 +
 
 +
;; ------------------------------------------------------------------
 +
;; Define the Options for this report
 +
;; ------------------------------------------------------------------
 +
 
 +
(define (options-generator)   
 +
  (let* ((options (gnc-new-optiondb)))       
 +
    options))
 +
 
 +
;; ------------------------------------------------------------------
 +
;; Render the HTML document
 +
;; ------------------------------------------------------------------
 +
 
 +
(define (document-renderer report-obj)
 +
  ;; Helper function for looking up option values
 +
  (define (get-option section name)
 +
    (gnc-optiondb-lookup-value (gnc:report-options report-obj) section name))
  
This is the minimum definition needed for a new ''GnuCash'' report:
+
  (let* (
 +
        (doc (gnc:make-html-document))
 +
        (report-title (get-option gnc:pagename-general
 +
                                  gnc:optname-reportname))
 +
)
  
;; -*-scheme-*-
+
        (gnc:html-document-add-object!
 +
        doc
 +
        (gnc:make-html-text
 +
          (gnc:html-markup-h3
 +
          (format #f (G_ "~a")
 +
                  report-title))))
 +
    doc))
 
   
 
   
;; This is a minimum report definition in GnuCash.
+
;; ------------------------------------------------------------------
;; It illustrates the the minimum definitions needed to create
+
;; Define the actual report
;; a new GnuCash report.
+
;; ------------------------------------------------------------------
;; It will create an empty page with heading 'Prototype'.
+
 
;; To be used as template.
+
(gnc:define-report
+
  'version 1
;; ------------------------------------------------------------------
+
'name (N_ "Prototype")
;; Top-level definitions
+
'report-guid "<paste generated unique report id here>"
;; ------------------------------------------------------------------
+
'menu-tip (N_ "Unstable. Used for Testing.")
+
'menu-path (list gnc:menuname-example)
(define-module (gnucash report prototype))
+
'options-generator options-generator
(use-modules (gnucash gnc-module))
+
'renderer document-renderer)</syntaxhighlight>
(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 384: Line 450:
 
Each report takes responsibility to build up an own database that holds the options for the report.
 
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 <code>hello-world.scm</code>.
+
Usually it is a good habit to copy the relavant code from the <tt>sample-report.scm</tt>.
In there you will find the database initializing
+
In there you will find the code initializing the database and filling it with options:
*call to <code>gnc:new-options</code>
+
 
which will
+
<syntaxhighlight lang="scheme">
*create the container called <code>options</code>
+
(define (options-generator)   
which will later on be filled by
+
  (let* ((options (gnc-new-optiondb)))       
*calling the help function <code>add-option</code>
+
    options))
which is a nice wrapper to eventually
+
</syntaxhighlight>
*call <code>gnc:register-option</code>
 
  
The <code>gnc:...</code>-procedures to create this database and to fill it with values are contained in <code>gnucash/src/app-utils/options.scm</code>.
+
Options are directly registered in the option database with a call to <code>gnc-register-<type>-option</code>.
  
<code>gnucash/src/report/utility-reports/hello-world.scm</code> presents a nice selection of example option definitions of following types:
+
<tt>sample-report.scm</tt> presents a nice selection of example option definitions of the following types:
<pre>
+
<syntaxhighlight lang="scheme">
gnc:make-simple-boolean-option
+
gnc-register-simple-boolean-option
gnc:make-multichoice-option
+
gnc-register-multichoice-option
gnc:make-string-option
+
gnc-register-string-option
gnc:make-date-option
+
gnc-register-date-option-set
gnc:make-number-range-option
+
gnc-register-number-range-option
gnc:make-color-option
+
gnc-register-color-option
gnc:make-account-list-option
+
gnc-register-account-list-option
gnc:make-list-option
+
gnc-register-list-option
</pre>
+
</syntaxhighlight>
  
On top of these, you find
+
Elsewhere you find:
<pre>
+
<syntaxhighlight lang="scheme">
gnc:make-text-option
+
gnc-register-text-option
gnc:make-font-option
+
gnc-register-font-option
gnc:make-currency-option
+
gnc-register-currency-option
gnc:make-budget-option
+
gnc-register-budget-option
gnc:make-commodity-option
+
gnc-register-commodity-option
gnc:make-complex-boolean-option
+
gnc-register-complex-boolean-option
gnc:make-pixmap-option  
+
gnc-register-pixmap-option  
gnc:make-account-list-limited-option
+
gnc-register-account-list-limited-option
gnc:make-account-sel-option
+
gnc-register-account-sel-option
gnc:make-account-sel-limited-option
+
gnc-register-account-sel-limited-option
gnc:make-multichoice-callback-option
+
gnc-register-multichoice-callback-option
gnc:make-radiobutton-option
+
gnc-register-radiobutton-option
gnc:make-radiobutton-callback-option
+
gnc-register-radiobutton-callback-option
gnc:make-internal-option
+
gnc-register-internal-option
gnc:make-query-option
+
gnc-register-query-option
gnc:make-dateformat-option
+
gnc-register-dateformat-option
</pre>
+
</syntaxhighlight>
in <code>gnucash/src/app-utils/options.scm</code>.
 
  
Also, <code>gnucash/src/business/business-utils/business-options.scm</code> provides some options
+
Also, business options:
<pre>
+
<syntaxhighlight lang="scheme">
gnc:make-invoice-option
+
gnc-register-invoice-option
gnc:make-customer-option
+
gnc-register-customer-option
gnc:make-vendor-option
+
gnc-register-vendor-option
gnc:make-employee-option
+
gnc-register-employee-option
gnc:make-owner-option
+
gnc-register-owner-option
gnc:make-taxtable-option
+
gnc-register-taxtable-option
gnc:make-counter-option
+
gnc-register-counter-option
gnc:make-counter-format-option
+
gnc-register-counter-format-option
</pre>
+
</syntaxhighlight>
  
In general, the syntax for creating an option is
+
In general, the syntax for creating an option is:
<pre>
+
<syntaxhighlight lang="scheme">
(define (gnc:make-<__type__>-option
+
(define (gnc-register-<type>-option opitiondb
         section                      ;; the tab-string in the option dialog
+
         section                      ;; the tab-string in the option dialog presented to the user
         name                        ;; the text for this option in the option dialog
+
         name                        ;; the text for this option in the option dialog presented to the user
 
         sort-tag                    ;; used to define the order in which the options are listed
 
         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
 
         documentation-string        ;; help string shown when the mouse moved over the option
 
         default-value
 
         default-value
         <__optioinal type specific parameters__>)
+
         <optional type specific parameters>)
</pre>
+
</syntaxhighlight>
  
Note that <code>section</code> 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 <code>gnucash/src/report/report-system/report.scm</code> provides three default names. Re-use these before creating new names:
+
Note that <code>section</code> 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 <tt>report-core.scm</tt> provides three default names. Re-use these before creating new names:
<pre>
+
<syntaxhighlight lang="scheme">
 
(define gnc:pagename-general (N_ "General"))
 
(define gnc:pagename-general (N_ "General"))
 
(define gnc:pagename-accounts (N_ "Accounts"))
 
(define gnc:pagename-accounts (N_ "Accounts"))
 
(define gnc:pagename-display (N_ "Display"))
 
(define gnc:pagename-display (N_ "Display"))
</pre>
+
</syntaxhighlight>
  
For a start, simply read through the <code>define (options-generator)</code> statement in <code>hello-world.scm</code> and copy what you need.
+
For a start, simply read through the <code>define (options-generator)</code> statement in <tt>sample-report.scm</tt> and copy what you need.
  
 
Nice to know:
 
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 <code>Report Name</code>, a selection box for the <code>Stylesheet</code>, and a button to <code>Reset defaults</code>.
 
* 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 <code>Report Name</code>, a selection box for the <code>Stylesheet</code>, and a button to <code>Reset defaults</code>.
* To find the option creation procedures in the source file tree you can use <b><code>grep gnc:make-.*-option `find . -name "*.scm"` | grep define</code></b>
+
* The <tt>guile</tt> path can be found in <tt>Help -> About -> GNC_DATA</tt> by selecting the parent folder.
* The source file tree is found in
 
** Debian and Ubuntu Linux: <code>/usr/share/gnucash/scm</code>
 
  
 
=== The Report-Renderer ===
 
=== The Report-Renderer ===
Line 472: Line 534:
 
Define how to apply the options (the actual report contents).
 
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.
+
The overall goal of the ''Report-Renderer'' is to create an ''HTML''-document and fill it with the report results to display to the user. You should refer to the [https://github.com/Gnucash/gnucash/blob/stable/gnucash/report/doc/report-html.txt HTML generation description] documentation in the source code.
  
Similar as with the ''Options-Generator'', <code>hello-world.scm</code> gives you a great introduction how this works in general.
+
Similar to ''Options-Generator'', <tt>sample-report.scm</tt> gives you a great introduction to how this works in general.
  
The <code>gnc:...</code>-procedures are found in the <code>src/report/report-system/html-*.scm</code> source files.
+
The <code>gnc:...</code>-procedures are found in the <tt>src/report/report-system/html-*.scm</tt> source files.
  
 
After runnning the report you can press the <code>Export</code> button to save the generated ''HTML-Code'' into a file for viewing. Doing this for the above minimum prototype report gives the following result:
 
After runnning the report you can press the <code>Export</code> button to save the generated ''HTML-Code'' into a file for viewing. Doing this for the above minimum prototype report gives the following result:
<pre>
+
<syntaxhighlight lang="html">
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+
<!DOCTYPE html>
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml">
+
<html dir='auto'>
 
<head>
 
<head>
 
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
 
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
 
<style type="text/css">
 
<style type="text/css">
h3 { font-family: Ubuntu; font-size: 15pt; font-weight: bold;  }
+
@media (prefers-color-scheme: dark) {body {color: #000; background-color: #fff;}}
a { font-family: Ubuntu; font-size: 10pt; font-style: italic;  }
+
h3 { font-family: "Segoe UI", sans-serif; font-size: 15pt; font-weight: bold;  }
body, p, table, tr, td { text-align: left; font-family: Ubuntu; font-size: 10pt;  }
+
a { font-family: "Segoe UI", sans-serif; font-size: 10pt; font-style: italic;  }
 +
body, p, table, tr, td { vertical-align: top; font-family: "Segoe UI", sans-serif; font-size: 10pt;  }
 
tr.alternate-row { background: #ffffff }
 
tr.alternate-row { background: #ffffff }
th.column-heading-left { text-align: left; font-family: Ubuntu; font-size: 10pt;  }
+
tr { page-break-inside: avoid !important;}
th.column-heading-center { text-align: center; font-family: Ubuntu; font-size: 10pt;  }
+
html, body { height: 100vh; margin-top: 0px; margin-bottom: 0px; margin-left: 8px; margin-right: 8px; }
th.column-heading-right { text-align: right; font-family: Ubuntu; font-size: 10pt;  }
+
td, th { border-color: grey }
td.neg { color: red;  }
+
th.column-heading-left { text-align: left; font-family: "Segoe UI", sans-serif; font-size: 10pt;  }
 +
th.column-heading-center { text-align: center; font-family: "Segoe UI", sans-serif; font-size: 10pt;  }
 +
th.column-heading-right { text-align: right; font-family: "Segoe UI", sans-serif; font-size: 10pt;  }
 +
td.highlight {background-color:#e1e1e1}td.neg { color: red;  }
 
td.number-cell, td.total-number-cell { text-align: right; white-space: nowrap; }
 
td.number-cell, td.total-number-cell { text-align: right; white-space: nowrap; }
 
td.date-cell { white-space: nowrap; }
 
td.date-cell { white-space: nowrap; }
td.anchor-cell { white-space: nowrap; font-family: Ubuntu; font-size: 10pt;  }
+
td.anchor-cell { white-space: nowrap; font-family: "Segoe UI", sans-serif; font-size: 10pt;  }
td.number-cell { font-family: Ubuntu; font-size: 10pt;  }
+
td.number-cell { font-family: "Segoe UI", sans-serif; font-size: 10pt;  }
td.number-header { text-align: right; font-family: Ubuntu; font-size: 10pt;  }
+
td.number-header { text-align: right; font-family: "Segoe UI", sans-serif; font-size: 10pt;  }
td.text-cell { font-family: Ubuntu; font-size: 10pt;  }
+
td.text-cell { font-family: "Segoe UI", sans-serif; font-size: 10pt;  }
td.total-number-cell { font-family: Ubuntu; font-size: 12pt; font-weight: bold;  }
+
td.total-number-cell { font-family: "Segoe UI", sans-serif; font-size: 10pt; font-weight: bold;  }
td.total-label-cell { font-family: Ubuntu; font-size: 12pt; font-weight: bold;  }
+
td.total-label-cell { font-family: "Segoe UI", sans-serif; font-size: 12pt; font-weight: bold;  }
td.centered-label-cell { text-align: center; font-family: Ubuntu; font-size: 12pt; font-weight: bold;  }
+
td.centered-label-cell { text-align: center; font-family: "Segoe UI", sans-serif; font-size: 12pt; font-weight: bold;  }
</style>
+
sub { top: 0.4em; }
<title></title>
+
sub, sup { vertical-align: baseline; position: relative; top: -0.4em; }
</head>
+
@media print { html, body { height: unset; }}
 
+
</style></head><body bgcolor="#ffffff"><h3>Report name</h3>
<body bgcolor="#ffffff">
 
<h3></h3>
 
 
</body>
 
</body>
 
</html>
 
</html>
</pre>
+
</syntaxhighlight>
It can be seen that the style section is added automatically without specific definitions inside the prototoype source.
+
The style section is added automatically without specific definitions inside the prototype source.
 
Also note that the register name in ''GnuCash'' is not part of the ''HTML'' document.
 
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
+
The procedures to fill this ''HTML''-document with life and further formatting are given in the following <code>report/</code> source files:
* Linux Ubuntu: <code>/usr/share/gnucash/scm</code>  
 
in the following files:
 
 
<pre>
 
<pre>
 
html-acct-table.scm
 
html-acct-table.scm
Line 532: Line 594:
 
</pre>
 
</pre>
  
Start making the prototype report a little nicer, adding the following line to the <code>document-renderer</code> from <code>html-document.scm</code>
+
Start making the prototype report a little nicer by adding the following line to the <code>document-renderer</code> from <tt>html-document.scm</tt>
<pre>
+
<syntaxhighlight lang="scheme">
 
(gnc:html-document-set-title! document (_ "GnuCash Report Prototype"))
 
(gnc:html-document-set-title! document (_ "GnuCash Report Prototype"))
</pre>
+
</syntaxhighlight>
 
will result in an update of the <code>title</code> and <code>h3</code> lines:
 
will result in an update of the <code>title</code> and <code>h3</code> lines:
<pre>
+
<syntaxhighlight lang="html">
 
[...]
 
[...]
 
<title>GnuCash Report Prototype</title>
 
<title>GnuCash Report Prototype</title>
Line 543: Line 605:
 
<h3>GnuCash Report Prototype</h3>
 
<h3>GnuCash Report Prototype</h3>
 
[...]
 
[...]
</pre>
+
</syntaxhighlight>
  
 
Next it is possible to add attributes to the body line.
 
Next it is possible to add attributes to the body line.
  
'''''Note:'''''
+
{| class="wikitable"
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. ([http://www.w3.org/TR/html401/struct/global.html#edef-BODY quoted from W3.org])
+
|-
 +
|'''Note:''' You should read the following section for informational purposes only: Style sheets are now the preferred way to specify a document's presentation, the presentational attributes of BODY have been deprecated. ([{{URL:W3C}}TR/html401/struct/global.html#edef-BODY quoted from W3.org])
 
(Currently in ''GnuCash'' the <code>bgcolor</code>-tag is default part of the <code>body</code>-tag.)
 
(Currently in ''GnuCash'' the <code>bgcolor</code>-tag is default part of the <code>body</code>-tag.)
 +
|}
  
 
The <code>body</code>-tag can be enhanced with attributes via the <code>gnc:html-document-set-style!</code> funtion. The general sytax:
 
The <code>body</code>-tag can be enhanced with attributes via the <code>gnc:html-document-set-style!</code> funtion. The general sytax:
<pre>
+
<syntaxhighlight lang="scheme">
 
(gnc:html-document-set-style!
 
(gnc:html-document-set-style!
        document                              ;; the reference to the current html-document
+
    document                              ;; the reference to the current html-document
"body"                                ;; specify the tag to add attributes to
+
    "body"                                ;; specify the tag to add attributes to
        'attribute (list "blabla" "balabala")  ;; first additional attribute
+
    'attribute (list "blabla" "balabala")  ;; first additional attribute
        'attribute (list "nonstop" "nonsens")  ;; second additional attribute
+
    'attribute (list "nonstop" "nonsens")  ;; second additional attribute
        'attribute (list "bgcolor" "#f6ffdb")  ;; third additional attribute
+
    'attribute (list "bgcolor" "#f6ffdb")  ;; third additional attribute
        [...]                                  ;; further attributes
+
    [...]                                  ;; further attributes
 
)
 
)
</pre>
+
</syntaxhighlight>
  
 
The example above lists some imaginary attributes to indicate that the attribute definition will be added to the <code>body</code>-tag without further validity check. Invalid attributes will appear in the ''HTML''-code but will have no visible effect on the document representation.
 
The example above lists some imaginary attributes to indicate that the attribute definition will be added to the <code>body</code>-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
 
The rest of the body is filled with ''HTML''-text by defintion of text objects, which gives the following structure
<pre>
+
<syntaxhighlight lang="html">
 
<body bgcolor="#ffffff">
 
<body bgcolor="#ffffff">
 
<h3>[title]</h3>
 
<h3>[title]</h3>
Line 578: Line 642:
  
 
</body>
 
</body>
</pre>
+
</syntaxhighlight>
 
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.
 
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
 
In ''Scheme'' these objects are defined like
<pre>
+
<syntaxhighlight lang="scheme">
 
(gnc:html-document-add-object!
 
(gnc:html-document-add-object!
        document              ;; the overall HTML document defined above
+
    document              ;; the overall HTML document defined above
        (gnc:make-html-text    ;; a text object
+
    (gnc:make-html-text    ;; a text object
  [text 1]            ;; part 1 of the text
+
        [text 1]            ;; part 1 of the text
          [text 2]            ;; part 2 of the text
+
        [text 2]            ;; part 2 of the text
 
             .  .
 
             .  .
 
             .  .
 
             .  .
 
             .  .
 
             .  .
          [text m]            ;; part m of the text
+
        [text m]            ;; part m of the text
)
+
    )
 
)
 
)
</pre>
+
</syntaxhighlight>
 
Note the above structure is the definition of 1 text object, which consists of m (sub-)text elements.
 
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
+
The text elements can be simple strings, or ''markup''-formatted. ''Markup''-commands are found in <tt>html-text.scm</tt>:
* Linux Ubuntu: <code>/usr/share/gnucash/scm/html-text.scm</code>:
 
  
<pre>
+
<syntaxhighlight lang="scheme">
 
gnc:html-markup-p        ;; markup for "paragraph"
 
gnc:html-markup-p        ;; markup for "paragraph"
 
gnc:html-markup-tt      ;; markup for fixed font (type writer style)
 
gnc:html-markup-tt      ;; markup for fixed font (type writer style)
Line 614: Line 677:
 
gnc:html-markup-anchor  ;; markup for hyperlinks
 
gnc:html-markup-anchor  ;; markup for hyperlinks
 
gnc:html-markup-img      ;; markup for images
 
gnc:html-markup-img      ;; markup for images
</pre>
+
</syntaxhighlight>
  
To give you a basic idea: Following example of simple text objects
+
To give you a basic idea, an example of simple text objects:
<pre>
+
<syntaxhighlight lang="scheme">
 
(gnc:html-document-add-object!
 
(gnc:html-document-add-object!
        document
+
    document
        (gnc:make-html-text  
+
    (gnc:make-html-text  
  "some text"  
+
        "some text"  
  "some other text"  
+
        "some other text"  
  (gnc:html-markup-br)
+
        (gnc:html-markup-br)
  (gnc:html-markup-tt "tt text")
+
        (gnc:html-markup-tt "tt text")
  (gnc:html-markup-h1 "header1 text")
+
        (gnc:html-markup-h1 "header1 text")
  (gnc:html-markup "bla" "tirili flöt")
+
        (gnc:html-markup "bla" "tirili flöt")
  (gnc:html-markup "i" "italic text")
+
        (gnc:html-markup "i" "italic text")
)
+
    )
 
)
 
)
</pre>
+
</syntaxhighlight>  
will result in following ''HTML''-code
+
 
<pre>
+
results in following ''HTML''-code
 +
<syntaxhighlight lang="html">
 
<body bgcolor="#f6ffdb">
 
<body bgcolor="#f6ffdb">
 
<h3>GnuCash Report Prototype</h3>
 
<h3>GnuCash Report Prototype</h3>
Line 638: Line 702:
 
<br />
 
<br />
 
<tt>tt text</tt>
 
<tt>tt text</tt>
 
 
<h1>header1 text</h1>
 
<h1>header1 text</h1>
 
 
<bla>tirili flöt</bla>
 
<bla>tirili flöt</bla>
 
 
<i>italic text</i>
 
<i>italic text</i>
 
 
</body>
 
</body>
</pre>
+
</syntaxhighlight>
 
Note that it is possible to define new tags (here: "bla") if needed by using <code>gnc:html-markup</code>.
 
Note that it is possible to define new tags (here: "bla") if needed by using <code>gnc:html-markup</code>.
  
Again: Take a good look at <code>hello-world.scm</code> and explore many more expamples how to format ''HTML''-text.
+
Again: Take a good look at <tt>sample-report.scm</tt> and explore many more examples how to format ''HTML''-text.
 
+
Also, be aware to examine
+
Examine:
 
<pre>
 
<pre>
 
html-scatter.scm
 
html-scatter.scm
Line 660: Line 720:
 
</pre>
 
</pre>
 
to find out more about
 
to find out more about
<pre>
+
<syntaxhighlight lang="scheme">
 
gnc:make-html-scatter
 
gnc:make-html-scatter
 
gnc:make-html-acct-table
 
gnc:make-html-acct-table
Line 666: Line 726:
 
gnc:make-html-table
 
gnc:make-html-table
 
gnc:make-html-linechart
 
gnc:make-html-linechart
</pre>
+
</syntaxhighlight>
  
 
=== The <code>gnc:define-report</code> Statement ===
 
=== The <code>gnc:define-report</code> Statement ===
Line 674: Line 734:
 
* once that your report is ready, fully tested, and shall become part of your standard reports
 
* once that your report is ready, fully tested, and shall become part of your standard reports
  
And again, <code>hello-world.scm</code> already proposes how you should proceed in the latter case
+
And again, <tt>sample-report.scm</tt> already proposes how you should proceed in the latter case
 
<pre>
 
<pre>
 
[...]  
 
[...]  
Line 683: Line 743:
 
=== Barcharts ===
 
=== Barcharts ===
  
The minimum definition is of a bar chart report is shown in the example below:
+
The minimum definition of a bar chart report is shown in the following example based on a simple [[Tutorial for html-chart.scm|tutorial]] for generating charts using <tt>html-chart.scm</tt>. Before running, update <code>name</code>, <code>report-guid</code> and <code>menu-tip</code> values appropriately.
  
;; -*-scheme-*-
+
<syntaxhighlight lang="scheme" highlight="13,70-72">
+
;; -*-scheme-*-
;; This is a minimum barchart report definition in GnuCash.
+
 
;; It illustrates the the minimum definitions needed to create
+
;; This is a minimum report definition in GnuCash.
;; a new GnuCash barchart report.
+
;; It illustrates the the minimum definitions needed to create
;; It will create a page with heading 'Prototype'.
+
;; a new GnuCash report.
;; To be used as template.
+
;; It will create an empty page with heading 'Prototype'.
+
;; To be used as template.
;; ------------------------------------------------------------------
+
 
;; Top-level definitions
+
;; ------------------------------------------------------------------
;; ------------------------------------------------------------------
+
;; Top-level definitions
+
;; ------------------------------------------------------------------
(define-module (gnucash report prototype))
+
 
(use-modules (gnucash gnc-module))
+
(define-module (gnucash reports example prototype))
(gnc:module-load "gnucash/report/report-system" 0)
+
 
+
(use-modules (gnucash engine))
;; ------------------------------------------------------------------
+
(use-modules (gnucash utilities))
;; Define the Options for this report
+
(use-modules (gnucash core-utils))
;; ------------------------------------------------------------------
+
(use-modules (gnucash app-utils))
+
(use-modules (gnucash report))
(define (options-generator)  
+
(use-modules (gnucash html))
  (let* ((options (gnc:new-options)))        
+
 
    options))
+
(debug-enable 'backtrace)
+
 
;; ------------------------------------------------------------------
+
;; ------------------------------------------------------------------
;; Render the HTML document
+
;; Define the Options for this report
;; ------------------------------------------------------------------
+
;; ------------------------------------------------------------------
+
 
(define (document-renderer report-obj)
+
(define (options-generator)
  (let (
+
  (gnc-new-optiondb))
          (document (gnc:make-html-document))
+
 
          (chart (gnc:make-html-barchart))
+
;; ------------------------------------------------------------------
        )
+
;; Render the HTML document
+
;; ------------------------------------------------------------------
        (gnc:html-barchart-set-title! chart "Barchart Title") ;; optional
+
 
        (gnc:html-barchart-set-subtitle! chart "Barchart Sub-Title") ;; optional
+
(define (document-renderer report-obj)
        (gnc:html-barchart-set-width! chart 400)
+
  (let (
        (gnc:html-barchart-set-height! chart 400)
+
        (doc (gnc:make-html-document))
        (gnc:html-barchart-set-row-labels! chart '("row1" "row2"))
+
        (chart (gnc:make-html-chart))
        (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-chart-set-title! chart "title")
        (gnc:html-barchart-append-column! chart '(110 210))
+
      (gnc:html-chart-set-type! chart "bar")
+
      (gnc:html-chart-set-width! chart '(pixels . 800))
        (gnc:html-barchart-set-col-labels! chart '("col1" "col2"))
+
      (gnc:html-chart-set-height! chart '(pixels . 600))
         (gnc:html-barchart-set-col-colors! chart '("green" "blue"))
+
      (gnc:html-chart-set-y-axis-label! chart "yAxis")
       
+
      (gnc:html-chart-set-data-labels! chart '("a" "b" "c"))
        (gnc:html-document-add-object! document chart)
+
      (gnc:html-chart-add-data-series! chart "series1" '(20 40 30) "red")
+
      (gnc:html-chart-add-data-series! chart "series2" '(30 25 25) "green")
        document ;; RETURN value
+
      (gnc:html-chart-set! chart '(options chartArea backgroundColor) "wheat")
  )
+
 
)
+
      (gnc:html-document-add-object!
+
        doc
;; ------------------------------------------------------------------
+
         (gnc:make-html-text
;; Define the actual report
+
        (gnc:html-markup-h3
;; ------------------------------------------------------------------
+
          (format #f (G_ "~a")
+
              N_ "Demonstration"))))
(gnc:define-report
+
 
  'version 1
+
      (gnc:html-document-add-object! doc chart)
  'name (N_ "Prototype")
+
 
  'report-guid "<span style="color:red">paste generated unique report id here</span>"
+
      doc
  'menu-tip (N_ "Unstable. Used for Testing.")
+
  )
  'menu-path (list gnc:menuname-utility)
+
)
  'options-generator options-generator
+
 
  'renderer document-renderer)
+
;; ------------------------------------------------------------------
 +
;; 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)
 +
</syntaxhighlight>
  
and it will create the following line in the report:
+
If you look at the HMTL source for this report after it is generated, you will see a line  with the <code><img></code> tag. The image for the report is encoded inline in a very long ASCII code string.
  
<pre>
+
<syntaxhighlight lang="html">
 
<img src="data:image/png;base64,<very_long_ASCII_coded_string>" alt="Cannot display barchart"/> &nbsp;
 
<img src="data:image/png;base64,<very_long_ASCII_coded_string>" alt="Cannot display barchart"/> &nbsp;
</pre>
+
</syntaxhighlight>
 
 
meaning, the graph is coded inline as ASCII-string within the <img> statement.
 
  
 
== The GnuCash API ==
 
== The GnuCash API ==
The GnuCash application programming interface ([http://code.gnucash.org/docs/HEAD/ 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):
+
The GnuCash application programming interface ([{{URL:docs:API}} stable] or after the implementation of the first future feature [{{URL:docs:API|future}} future] 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 <tt>src/engine/gnc-numeric.scm</tt>
+
* create a monetary object via <code>gnc:make-gnc-monetary</code> <tt>libgnucash/engine/gnc-numeric.scm</tt>
* get the amount of a monetary object: gnc:gnc-monetary-amount <tt>src/engine/gnc-numeric.scm</tt>
+
* get the amount of a monetary object via <code>gnc:gnc-monetary-amount</code> <tt>libgnucash/engine/gnc-numeric.scm</tt>
* get an account name: gnc-account-get-name <tt>src/engine/swig-engine.c</tt>
+
* get an account name via <code>xaccAccountGetName</code> <tt>libgnucash/engine/Account.cpp</tt>
* create a commodity collector: gnc:make-commodity-collector <tt>src/report/report-system/report-utilities.scm</tt>
+
* create a commodity collector via <code>gnc:make-commodity-collector</code> <tt>gnucash/report/report-system/report-utilities.scm</tt>
  
Watch out for the gnucash version in use: In '''2.0.x''', the Scheme wrappers were created by G-WRAP, started with <tt>gnc:</tt> (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 <tt>gnc-</tt> (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'' <tt>src/engine/gw-engine-spec.scm</tt> - such a function would now be called ''gnc-account-get-name'' and would be found in <tt>src/engine/engine.i</tt> or the generated file <tt>src/engine/swig-engine.c</tt>.
+
The mightiness of the API is huge. As of GnuCash 2.4.10, there were over 1000 GnuCash api calls that could be made from reports.
 
 
The mightiness of the API is huge. Doing a <tt>grep</tt> on <tt>swig-engine.c</tt> for
 
*<tt>scm_c_define_gsubr</tt> will return 866 results (i.e. in theory 866 routines that can be called via ''guile'')
 
*<tt>scm_c_define_gsubr\.*gnc-\.*</tt> will return 337 results
 
(Status: ''GnuCash'' 2.4.10)
 
  
 
It is by far too much to be documented in this Wiki-page.
 
It is by far too much to be documented in this Wiki-page.
Line 779: Line 844:
 
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.
 
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.
  
<table border=1>
+
{| class="wikitable"
  <tr>
+
|-
    <th>Name</th>
+
! scope="col"| Name
    <th>Source</th>
+
! scope="col"| Source
    <th>Example</th>
+
! scope="col"| Example
    <th>Comments</th>
+
! scope="col"| Comments
  </tr>
+
 
  <tr valign="top" bgcolor="#c6cfcb">
+
|- style="vertical-align:top;"
    <td>gnc:account-get-balance-at-date</td>
+
| style="white-space: nowrap;" | xaccAccountGetBalanceAsOfDate
    <td>report-utilities.scm</td>
+
| style="white-space: nowrap;" | Account.cpp
    <td></td>
+
|
    <td>Returns the account balance as a gnc-numeric record. To get the float value it is possible to use <tt>gnc:gnc-numeric-num</tt> and <tt>gnc:gnc-numeric-denom</tt> (see below). Example:
+
| Returns the account balance as a number.
<pre>
+
Example:
(let* (
+
<syntaxhighlight lang="scheme">
        (bal
+
(xaccAccountGetBalanceAsOfDate acct date)
            (gnc:account-get-balance-at-date
+
</syntaxhighlight>
              acct  
 
              date
 
              #f ;; include children?
 
            )
 
        )
 
        (num (gnc:gnc-numeric-num bal))
 
        (denom (gnc:gnc-numeric-denom bal))
 
      )
 
      (/ num denom 1.0)
 
)
 
</pre></td>
 
  </tr>
 
  
    <tr valign="top" bgcolor="#c6cfcb">
+
|- style="vertical-align:top;"
    <td>gnc:html-table-append-row!</td>
+
| gnc:html-table-append-row!
    <td>html-table.scm</td>
+
| html-table.scm
    <td>-</td>
+
|
    <td>Appends a row to a HTML table.<br>Note that <tt>row</tt> can be a list. If so then each list element represents a column entry.<br>Example:<br><tt>(gnc:html-table-append-row! table (list e1 e2 e3))</tt><br>will result in<br>
+
| Appends a row to an HTML table.  
<pre>
+
Note that <tt>row</tt> can be a list. If so, then each list element represents a column entry.
 +
Example:
 +
<syntaxhighlight lang="scheme">(gnc:html-table-append-row! table (list e1 e2 e3))</syntaxhighlight>
 +
will result in:
 +
<syntaxhighlight lang="html">
 
<tr>
 
<tr>
 
<td>e1<td>
 
<td>e1<td>
Line 819: Line 876:
 
<td>e3<td>
 
<td>e3<td>
 
</tr>
 
</tr>
</pre>
+
</syntaxhighlight>
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.</td>
+
Note that only simple lists are supported for. If you use nested lists as input, then the whole list contents of the nested lists will be displayed.
   </tr>
+
 
 +
|- style="vertical-align:top;"
 +
| gnc:gnc-numeric-denom
 +
| gnc-numeric.scm
 +
|
 +
| Returns the denominator part of a gnc-numeric record.
 +
 
 +
|- style="vertical-align:top;"
 +
| gnc:gnc-numeric-num
 +
| gnc-numeric.scm
 +
|
 +
| Returns the numerator part of a gnc-numeric record.
 +
 
 +
|- style="vertical-align:top;"
 +
| gnc-account-get-full-name
 +
| gnc_account_get_full_name() in Account.cpp
 +
| sample-report.scm
 +
| Returns the account name in the format
 +
<tt>ParentLevel1:ParentLevel2:...:AccountName</tt>
 +
 
 +
To only get the <tt>AccountName</tt> use <tt>xaccAccountGetName</tt>
 +
 
 +
|- style="vertical-align:top;"
 +
| xaccTransGetDate
 +
| xaccTransGetDate() in Transaction.c
 +
|
 +
| Returns the posting date of a transaction. Transactions are return e.g. by <tt>xaccSplitGetParent</tt>, 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, like so:
 +
<syntaxhighlight lang="scheme">
 +
(qof-print-date (xaccTransGetDate (xaccSplitGetParent split)))
 +
</syntaxhighlight>
 +
 
 +
|- style="vertical-align:top;"
 +
| gnc-window-show-progress
 +
| gnc_window_show_progress() in gnc-window.c
 +
| report-utilities.scm
 +
| Used to forward processing progress information to the user. In <tt>report-utilities.scm</tt> this is wrapped in the routines:
 +
* <tt>gnc:report-starting
 +
* gnc:report-render-starting
 +
* gnc:report-percent-done
 +
* gnc:report-finished</tt>
 +
 
 +
|- style="vertical-align:top;"
 +
| xaccAccountGetDescription
 +
| Account.cpp
 +
|
 +
| Returns the account description. To be used with the account as input parameter:
 +
<syntaxhighlight lang="scheme">(xaccAccountGetDescription acct)</syntaxhighlight>
 +
 
 +
|- style="vertical-align:top;"
 +
| xaccAccountGetName
 +
| Account.cpp
 +
| sample-report.scm
 +
| Returns the account name. To get the full account name including parent names use <tt>gnc-account-get-full-name</tt>
 +
 
 +
|- style="vertical-align:top;"
 +
| xaccAccountGetNotes
 +
| Account.cpp
 +
|
 +
| Returns the account notes. This is the text field that is found in the <tt>edit</tt> dialog of the accounts. To be used with the account as input parameter:
 +
<syntaxhighlight lang="scheme">(xaccAccountGetNotes acct)</syntaxhighlight>
 +
 
 +
|- style="vertical-align:top;"
 +
| xaccAccountGetSplitList
 +
| Account.cpp
 +
| 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 <tt>gnc:accounts-count-splits</tt> defined in <tt>report-utilities.scm</tt>.
 +
The standard report <tt>cash-flow.scm</tt> makes use of this api.
 +
 
 +
|- style="vertical-align:top;"
 +
| xaccAccountGetType
 +
| Account.cpp
 +
|
 +
| Returns the account type, which is the text field that is found in the <tt>edit</tt> dialog of the accounts. To be used with the account as input parameter <tt>(xaccAccountGetNotes acct)</tt>
 +
The following account types are available:
 +
<tt>
 +
* 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</tt>
 +
 
 +
|- style="vertical-align:top;"
 +
| xaccSplitGetAccount
 +
| Split.c
 +
|
 +
| Returns the account object that the split belongs to. To get the name from the returned account, use:
 +
<syntaxhighlight lang="scheme">(xaccAccountGetName (xaccSplitGetAccount split))</syntaxhighlight>
 +
 
 +
|- style="vertical-align:top;"
 +
| xaccSplitGetCorrAccountName
 +
| Split.c
 +
|
 +
| Returns the account name at the other end of the split as a string.
 +
 
 +
|- style="vertical-align:top;"
 +
| xaccSplitGetParent
 +
| Split.c
 +
|
 +
| Returns the parent transaction the split belongs to. See <tt>xaccTransGetDate</tt> for an example how to use it.
 +
 
 +
|}
 +
 
 +
 
 +
=== Command line access to the API ===
 +
 
 +
(Written Jan 2018)
 +
It is convenient to access the full API from a Guile Command-line for newbie report developers. This requires the developer is familiar with Linux, and can set up CMake, unit testing environments.
 +
 
 +
The full GUI-generated reporting construct described above is important to test a custom report, however, is very inconvenient to explore the API.
 +
 
 +
The preparation work involves:
 +
 
 +
1. Create a special unit test program in scheme, perhaps naming it test-server.scm - this shall reside in a convenient folder with other unit test files e.g. gnucash/report/standard-reports/test.
 +
 
 +
<syntaxhighlight lang="scheme">
 +
(use-modules (gnucash gnc-module))
 +
(use-modules (gnucash app-utils))
 +
(use-modules (gnucash engine test test-extras))
 +
 
 +
;; The following needed for Guile REPL
 +
(use-modules (system repl server))
 +
(define (run-test)
 +
   (run-server))
 +
 
 +
;; The following needed for reports:
 +
(use-modules (gnucash report stylesheets))
 +
(use-modules (gnucash report report-system))
 +
(define constructor (record-constructor <report>))
 +
</syntaxhighlight>
 +
 
 +
2. Adding test-server.scm onto the CMakeFiles.txt in the same folder to enable compilation
 +
 
 +
3. Running make or ninja to generate the build directory
 +
 
 +
4. Running test-server.scm from the build directory by
 +
<syntaxhighlight lang="sh">cd build/gnucash/report/standard-reports/test
 +
/usr/bin/ctest -R test-server</syntaxhighlight>
 +
 
 +
This will run the test server.
 +
 
 +
5. Switch to another terminal, run
 +
<syntaxhighlight lang="sh">nc localhost 37146 (the default guile port, upside down 37146 looks like guile...)
 +
</syntaxhighlight>
 +
 
 +
This will now present a full Guile REPL prompt, with full access to the test-server.scm bindings as well as the Gnucash API. People familiar with emacs and the geiser package may also connect to the server by
 +
<code>M-x connect-to-guile</code>. Unfortunately so far, only the environment is loaded. I do not think the file-load mechanism is accessible to scheme, which is an inconvenience for testing reports.
 +
 
 +
The developer can try:
 +
 
 +
<syntaxhighlight lang="scheme">
 +
> ,apropos xacc [RET]
 +
(sw_engine): xaccTransEqual #<procedure xaccTransEqual (_ _ _ _ _ _)>
 +
(sw_engine): xaccSplitGetCorrAccountCode #<procedure xaccSplitGetCorrAccountCode (_)>
 +
(sw_engine): xaccAccountGetReconciledBalance #<procedure xaccAccountGetReconciledBalance (_)>
 +
(sw_engine): xaccClearMarkDown #<procedure xaccClearMarkDown (_ _)>
 +
(sw_engine): xaccSplitSetBaseValue #<procedure xaccSplitSetBaseValue (_ _ _)>
 +
(sw_engine): xaccTransGetFirstAPARAcctSplit #<procedure xaccTransGetFirstAP
 +
 
 +
etc
 +
 
 +
> ,apropos gnc- [RET]
 +
(sw_engine): gnc-monetary-list-delete-zeros #<procedure gnc-monetary-list-delete-zeros (_)>
 +
(sw_engine): gnc-gdate-set-prev-fiscal-year-start #<procedure gnc-gdate-set-prev-fiscal-year-start (_ _)>
 +
(sw_engine): gnc-quote-source-get-internal-name #<procedure gnc-quote-source-get-internal-name (_)>
 +
(sw_engine): gnc-numeric-check #<procedure gnc-numeric-check (_)>
 +
(sw_engine): gnc-timegm #<procedure gnc-timegm (_)>
 +
(sw_engine): gnc-account-join-children #<procedure gnc-account-join-c
 +
 
 +
etc
 +
 
 +
> ,bindings
 +
constructor            #<variable 55cae1534b70 value: #<procedure 55cae11ff080 at ice-9/boot-9.scm:1340:17 (a b c d e f g h)>>
 +
%module-public-interface #<variable 55cae0652da0 value: #<interface (guile-user) 55cae0638b40>>
 +
run-test                #<variable 55cae1534cc0 value: #<procedure run-test ()>>
 +
 
 +
> (current-time)
 +
1515297631
 +
 
 +
> (qof-print-date (current-time))
 +
"07/01/18"
 +
 
 +
> (qof-date-format-set QOF-DATE-FORMAT-ISO)
 +
> (qof-print-date (current-time))
 +
"2018-01-07"
 +
 
 +
</syntaxhighlight>
 +
 
 +
=== Adding Menu Items ===
 +
 
 +
The following example shows how to add a menu item from Scheme. The
 +
code adds the menu item <q>Tools › Scheme REPL</q> and the corresponding
 +
command starts a Scheme REPL in the tty.
 +
 
 +
Installation:
 +
 
 +
1. Save the code somewhere in your file system like in <tt>~/hacking/gnucash/commands/repl.scm</tt>.
 +
 
 +
2. Add something like this to your ~/.config/gnucash/config-user.scm:
 +
<syntaxhighlight lang="scheme">
 +
(add-to-load-path "/home/helmut/hacking/gnucash/")
 +
(import (only (commands repl) register-repl-command))
 +
(register-repl-command)
 +
</syntaxhighlight>
 +
 
 +
3. Start GnuCash as usual.
 +
 
 +
 
 +
-----
 +
 
 +
'''Code:'''
 +
 
 +
<syntaxhighlight lang="scheme">
 +
(library (commands repl)
 +
  (export register-repl-command)
 +
  (import (rnrs base)
 +
  (only (guile) format getenv resolve-module current-module
 +
set-current-module save-module-excursion)
 +
  (only (system repl repl) start-repl)
 +
  (only (ice-9 readline) activate-readline write-history read-history)
 +
  (only (gnucash gnome-utils) gnc-add-scm-extension)
 +
  (only (gnucash gnome-utils gnc-menu-extensions) gnc:make-menu-item)
 +
  (only (gnucash core-utils) G_ N_))
 +
 
 +
  (define history-filename (format #f "~a/.gnucash_history" (getenv "HOME")))
  
   <tr valign="top" bgcolor="#c6cfcb">
+
   (define previous-module #f)
    <td>gnc:gnc-numeric-denom</td>
 
    <td>gnc-numeric.scm</td>
 
    <td></td>
 
    <td>Returns the denominator part of a gnc-numeric record.</td>
 
  </tr>
 
  
   <tr valign="top" bgcolor="#c6cfcb">
+
   (define (repl)
     <td>gnc:gnc-numeric-num</td>
+
     (save-module-excursion
    <td>gnc-numeric.scm</td>
+
    (lambda ()
    <td></td>
+
      (set-current-module (or previous-module
    <td>Returns the numerator part of a gnc-numeric record.</td>
+
      (begin
  </tr>
+
(read-history history-filename)
 +
(activate-readline)
 +
(resolve-module '(guile-user)))))
 +
      (start-repl)
 +
      (set! previous-module (current-module))
 +
      (write-history history-filename)
 +
      (format #t "Goodbye~%"))))
  
   <tr valign="top" bgcolor="#c6cfcb">
+
   (define menuname-tools (N_ "Tools"))
    <td>gnc-account-get-full-name</td>
 
    <td>swig-engine.c</td>
 
    <td>hello-world.scm</td>
 
    <td>Returns the account name in the format<br><tt>ParentLevel1:ParentLevel2:...:AccountName</tt><br>To only get the <tt>AccountName</tt> use <tt>xaccAccountGetName</tt></td>
 
  </tr>
 
  
   <tr valign="top" bgcolor="#c6cfcb">
+
   (define (register-repl-command)
     <td>gnc-transaction-get-date-posted</td>
+
     (gnc-add-scm-extension
    <td>swig-engine.c</td>
+
    (gnc:make-menu-item
    <td>-</td>
+
      "Scheme REPL"
    <td>Returns the posting date of a transaction. Transactions are return e.g. by <tt>xaccSplitGetParent</tt>, 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:
+
      "0155032a4b41443388f6cf8effc98169"
<pre>
+
      "Start a Scheme REPL in the tty"
(gnc-print-date (gnc-transaction-get-date-posted (xaccSplitGetParent split)))
+
      (list menuname-tools)
</pre>
+
      (lambda (window)
</td>
+
(repl)))))
  </tr>
 
  
   <tr valign="top" bgcolor="#c6cfcb">
+
   )
    <td>gnc-window-show-progress</td>
+
</syntaxhighlight>
    <td>swig-gnome-utils.c</td>
 
    <td>report-utilities.scm</td>
 
    <td>Used to forward processing progress information to the user. In <tt>report-utilities.scm</tt> this is wrapped in the routines<br><tt>gnc:report-starting<br>gnc:report-render-starting<br>gnc:report-percent-done<br>gnc:report-finished</tt><br>The standard report <tt>cash-flow.scm</tt> is making use of this.</td>
 
  </tr>
 
  <tr valign="top" bgcolor="#c6cfcb">
 
    <td>xaccAccountGetDescription</td>
 
    <td>swig-engine.c</td>
 
    <td>-</td>
 
    <td>Returns the account description. To be used with the account as input parameter
 
<br><tt>(xaccAccountGetDescription acct)</tt></td>
 
  </tr>
 
  <tr valign="top" bgcolor="#c6cfcb">
 
    <td>xaccAccountGetName</td>
 
    <td>swig-engine.c</td>
 
    <td>hello-world.scm</td>
 
    <td>Returns the account name in the format<br><tt>AccountName</tt><br>To get the full <tt>AccountName</tt> including parent names use <tt>gnc-account-get-full-name</tt></td>
 
  </tr>
 
  <tr valign="top" bgcolor="#c6cfcb">
 
    <td>xaccAccountGetNotes</td>
 
    <td>swig-engine.c</td>
 
    <td>-</td>
 
    <td>Returns the account notes, which is the text field that is found in the <tt>edit</tt> dialog of the accounts. To be used with the account as input parameter
 
<br><tt>(xaccAccountGetNotes acct)</tt></td>
 
  </tr>
 
  <tr valign="top" bgcolor="#c6cfcb">
 
    <td>xaccAccountGetSplitList</td>
 
    <td>swig-engine.c</td>
 
    <td>report-utilities.scm</td>
 
    <td>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.<br>To get the numerical value for the amount of splits in a list of accounts use <tt>gnc:accounts-count-splits</tt> defined in <tt>report-utilities.scm</tt><br>The standard report <tt>cash-flow.scm</tt> is making use of this.</td>
 
  </tr>
 
  <tr valign="top" bgcolor="#c6cfcb">
 
    <td>xaccAccountGetType</td>
 
    <td>swig-engine.c</td>
 
    <td>-</td>
 
    <td>Returns the account type, which is the text field that is found in the <tt>edit</tt> dialog of the accounts. To be used with the account as input parameter <tt>(xaccAccountGetNotes acct)</tt>
 
<br>Following types are available:
 
<pre>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</pre></td>
 
  </tr>
 
  <tr valign="top" bgcolor="#c6cfcb">
 
    <td>xaccSplitGetAccount</td>
 
    <td>swig-engine.c</td>
 
    <td>-</td>
 
    <td>Returns the account that the split belongs to. Note that this is not a name string. To get the name of the account use<br><tt>(xaccAccountGetName (xaccSplitGetAccount split))</tt></td>
 
  </tr>
 
  <tr valign="top" bgcolor="#c6cfcb">
 
    <td>xaccSplitGetCorrAccountName</td>
 
    <td>swig-engine.c</td>
 
    <td>-</td>
 
    <td>Returns the account name at the other end of the split as a string.</td>
 
  </tr>
 
  <tr valign="top" bgcolor="#c6cfcb">
 
    <td>xaccSplitGetParent</td>
 
    <td>swig-engine.c</td>
 
    <td>-</td>
 
    <td>Returns the parent transaction the split belongs to. See <tt>gnc-transaction-get-date-posted</tt> for an example how to use it.</td>
 
  </tr>
 
</table>
 
  
 
== Other Resources ==
 
== Other Resources ==
Line 937: Line 1,152:
 
=== Old GnuCash Report Information ===
 
=== Old GnuCash Report Information ===
 
(may be very out of date)
 
(may be very out of date)
* [http://www.gnucash.org/docs/v1.6/C/x4501.html Version 1.6 report documentation]
+
* [{{URL:www}}docs/v1.6/C/x4501.html Version 1.6 report documentation]
 
* [[FAQ#Q:_I.27d_like_to_write_my_own_custom_reports._Where_should_I_start.3F]]
 
* [[FAQ#Q:_I.27d_like_to_write_my_own_custom_reports._Where_should_I_start.3F]]
* [http://www.gnucash.org/pipermail/gnucash-devel/2001-May/003493.html From the mailing list]
+
* [{{URL:mail archive|devel}}2001-May/003493.html From the mailing list]
  
 
=== Learning Scheme ===
 
=== Learning Scheme ===
* [http://groups.csail.mit.edu/mac/projects/scheme/ MIT Scheme Index]
+
* [https://groups.csail.mit.edu/mac/projects/scheme/ MIT Scheme Index]
 
* [http://download.plt-scheme.org/doc/360/html/t-y-scheme/t-y-scheme.html Teach Yourself Scheme in Fixnum Days]
 
* [http://download.plt-scheme.org/doc/360/html/t-y-scheme/t-y-scheme.html Teach Yourself Scheme in Fixnum Days]
 
* [http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-1.html Structure and Interpretation of Computer Programs]
 
* [http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-1.html Structure and Interpretation of Computer Programs]
* [http://www.htdp.org/  How to Design Programs]
+
* [https://www.htdp.org/  How to Design Programs] and [https://www.ccs.neu.edu/home/matthias/HtDP2e/ HtDP, 2nd Edition]
* Mastering Scheme is highly eased after reading [http://www.scheme.com/tspl2d/ The Scheme Progamming Language] by R. Kent Dybvig
+
* [https://mitpress.mit.edu/books/little-schemer-fourth-edition The Little Schemer]
* [http://www.gnu.org/software/guile/docs/docs.html Guile documentation]
+
* Mastering Scheme is highly eased after reading [https://www.scheme.com/tspl4/ The Scheme Progamming Language] by R. Kent Dybvig
 +
* [{{URL:guile}}docs/docs.html Guile documentation]
 +
* Some guile code uses pattern matching. [http://ceaude.twoticketsplease.de/articles/an-introduction-to-lispy-pattern-matching.html An Introduction to Lispy Pattern Matching]

Latest revision as of 23:26, 24 October 2023


This documentation applies from GnuCash Version 5.0. For prior versons use the previous version.

Custom Reports in GnuCash

The term Custom Reports has several contexts in GnuCash:

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

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

Possibly there are ways to get what you desire without coding.

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

Introduction

Custom reports can be fairly challenging and while the information presented here is brief it should be enough to get you started. The focus is on enough understanding to change (hack) existing reports.

In the GnuCash project the reports are coded in Scheme, not in C. Understanding Scheme is one of the prerequisites to create new reports. The obvious drawback is that one must learn yet another programming language (if not already familiar with it) but saves the effort of having to alter and build GnuCash's source code.

Guile is used as an 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 for you! Thankfully, lots of help is available.

First of all, there is good educational material available on the web to help you learn Scheme and Guile. Secondly, there is a simple sample-report.scm example report specifically written to show you the base layout of a GnuCash report. And finally, this Wiki page will give you some guidance when starting this venture.

Getting Started

This tutorial will give you an overview of GnuCash reports and might give you the confidence to make simple changes to existing reports.

Appreciation of Scheme language

GnuCash reports are written in the Scheme programming language. For a quick introduction try Learn Scheme in 15 minutes using an online scheme repl.

Language details

This tutorial is self-contained but to extend it in reports you'll want to use the following references and learn about the language. Just be aware of them for now.

Get to know Scheme

If you are new to Scheme it is not necessary to read and understand all of it right now. For anything more than this tutorial you should, at least, have gone through the Getting Started section.

Get to know Guile

Guile is used internally by GnuCash to interpret the Scheme reports.

This comes with a marvelous Tutorial. You don't need this for writing the reports themselves, but it gives a clue of how reports are created in GnuCash. This should be good motivation to go and tackle the learning curve for Scheme.

Get to know Gettext

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


Where to find existing reports

The location of existing reports varies with by operating systems. The guile path can be found in Help -> About -> GNC_DATA by selecting the parent folder.:

Operating System Path
All Linux except Debian with flatpak including derivatives such as UbuntuBSD .../<guile-version>/gnucash/reports
Debian with flatpak including derivatives such as Ubuntu, OSX bundle (Gnucash.app), Windows .../guile/site/2.2/gnucash/reports

Study some example reports

sample-report

sample-report.scm was created in GnuCash V5.0 from hello-world.scm to demonstrate the basic structure of a report. Don't get too confused by the huge number of options that are shown in this report - they were added to show off the variety of options available in GnuCash.

Have a look under #Where to find existing reports to find the source code for this report. Alternatively, you can browse the current source code for this report on github.

By looking at the result of this report while you study the source code, you will easily get clues to how it functions. You can run this report in GnuCash via the menu: Reports -> Examples -> Sample Report

account-piecharts

If you want to walk through a much more complicated report, study account-piecharts.scm.

There are two long functions in this report.

  1. option-generator defines the options for this report.
  2. piechart-renderer makes all the calculations and renders the pie chart.

The list of values to be shown in the pie chart can be calculated in two ways - depth-based or via a method that traverses all accounts. The decision for this is made when calling the piechart-renderer function. Both methods will work from a list of selected accounts stored in the topl-accounts variable.

traverse-accounts is a recursive function that calls itself to traverse through all child accounts in the account tree. To get the balance for a single account, it makes a call to profit-fn. profit-fn obtains the account balance for either one interval or at a given date. It calls out to gnc:account-get-comm-balance-at-date in report-utilities.scm where, finally, lower level calls are made, which create a query for the account balance at the given date.

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

Setup a prototype report

Even if you haven't ever written a report before, and you don't have 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 sample-report.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 sample-report.scm that is available in GnuCash by default (see previous section). So feel free to implement some fancy printout changes.

Prerequisites

GnuCash will not be able to load your report until you make changes in two areas of your report source file:

Give report a unique symbol name

To avoid symbol definition conflicts with other reports, make sure your report code begins with a define-module statement with a report name not used by any other report, for example:

(define-module (gnucash report my-world-report))
Define report with unique name and id

To enable GnuCash to register your report into the Report menu, scroll to the end of the code and update the gnc:define-report statement.

Set the name of your report to be shown in the Report menu. This name must be unique across all reports.

'name (N_ "My World")

Further down below, if it is present, comment out the menu-name line:

;;'menu-name (N_ "Sample Report with Examples")

Update the tool tip text to something appropriate for your report:

'menu-tip (N_ "Unstable. Used for Testing.")

Your report must have a globally unique identifier (guid). 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, use an online uuid generator like this one (any other one will do as well). Be sure to untick "Hyphens" to generate gnucash compatible guids. If you forget or the site you use doesn't offer that option, simply remove the hyphens yourself.

Alternatively, in linux, run this construct
uuidgen | sed -e 's/-//g'
[1]

Copy the newly generated ID and paste it into the report-guid value:

'report-guid "paste generated report unique id here"

Loading Your Report

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.

(load (gnc-build-userdata-path "my-world.scm"))
Notes
  • (gnc-build-userdata-path ...) or (gnc-build-dotgnucash-path ...) will complement your report name with the full path of your GNC_DATA_HOME or DOT_GNUCASH_DIR directory respectively. If you are comfortable with file locations you could equally well use the form
(load "<absolute path to>/my-world.scm")
to load your report from any arbitrary location on your file system.
  • The instructions refer to two separate directories: GNC_CONFIG_HOME and GNC_DATA_HOME. Be careful to use the proper one in the different locations as indicated.
  • If the config.user or config-user.scm file is not yet found in your settings directory, simply create it.

Move, copy, or link* your report file (my-world.scm) from your working directory to the proper GNC_DATA_HOME or DOT_GNUCASH_DIR 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.

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

Load the report from the installed report directory

Tip: Despite the warning below, this can be the easiest method in Windows by sandboxing report development with a Portable Apps version. Since GnuCash 4.12 the portable guile path can be found in Help -> About -> GNC_DATA by selecting the parent folder.

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 gnucash/scm/gnucash/report/standard-reports/ directory 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.

Note
In case of an eguile based report only the foo.scm file should be stored in the standard-reports directory. The accompanying foo.eguile.scm and foo.css should go in to gnucash/scm/gnucash/report instead.

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

Debugging your report

When guile cannot make sense of your report, or your report throws an error, GnuCash will present the following error message in place of your report:

Report error

An error occurred while running the report.

This lets you know there was a problem, but now you need to pinpoint where the problem lies. Here are some tips that might help.

Tip Details
Enable debug messages Start GnuCash with debug command line parameters:
gnucash --debug --log gnc.scm=debug

On macOS, assuming GnuCash is in your /Applications folder, this would be:

/Applications/Gnucash.app/Contents/MacOS/Gnucash --debug --log gnc.scm=debug

There are other debug related options, run GnuCash with the --help for a complete list.

Study the trace logs The GnuCash trace logs can sometimes give you that satisfying "oh, I see". By default you'll find the trace log:
Operating System Location
Unix/Linux $TEMP/gnucash.something.trace
Windows %TEMP%/gnucash.something.trace
macOS Somewhere under /var/folders/ You can find it via:
find /var/folders -name "gnucash.trace" 2> /dev/null

You can change the trace log file location via GnuCash command line parameter --logto. This parameter includes support for logging to 'stderr' and 'stdout'

Add your own debug messages You can use the gnc:debug function to add your own messages. For example:
(gnc:debug "here I am")
Add other messages There are also gnc:msg, gnc:warn and gnc:error functions; see [1] for more details.
Use a Scheme friendly editor For the uninitiated, matching parentheses properly in a Scheme program can make one's eyes cross. A Lisp/Scheme friendly editor can really help here. DrRacket or a properly configured Emacs really helps.
Run often Test your report often after making very small changes. This will make it easier to understand when and where problems are introduced.

Although guile does have debug support, this wiki page updater has not found a way, at this time, to hook GnuCash up to the guile debugger.

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-like environments (such as DrRacket) might also be useful for editing the sources, but note that they might allow constructs that are not valid in guile. Beware Racket is a scheme dialect not 100% compatible with Guile, but provides a nice GUI for understanding scheme functions.

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.

Note that, at least in GnuCash 2.6.17, for changes to report options to take effect, the report must closed and then relaunched from the Report menu. Changes to the render portion seem to be handled just fine by the reload button.

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.

WARNING
This section is out of date and will not run with GnuCash ≥ 4.6
Minimal Loader

Update name, report-guid and menu-tip values appropriately for your report.

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_ "<type your report name here>")
 'report-guid "<paste report unique id here>"
 'menu-tip (N_"<type your report menu tip here>")
 'menu-path (list gnc:menuname-utility)
 'options-generator options_loader
 'renderer renderer_loader)
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. Update add-to-load-path value appropriately for your setup.

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 (makes the report available in GnuCash)

This is the minimum definition needed for a new GnuCash report. Update name, report-guid[2] and menu-tip values appropriately.

prototype.scm:

;; -*-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 reports example prototype))

(use-modules (gnucash engine))
(use-modules (gnucash utilities)) 
(use-modules (gnucash core-utils))
(use-modules (gnucash app-utils))
(use-modules (gnucash report))
(use-modules (gnucash html))

(debug-enable 'backtrace)

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

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

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

(define (document-renderer report-obj)
  ;; Helper function for looking up option values
  (define (get-option section name)
    (gnc-optiondb-lookup-value (gnc:report-options report-obj) section name))

  (let* (
         (doc (gnc:make-html-document))
         (report-title (get-option gnc:pagename-general
                                   gnc:optname-reportname))
		)

        (gnc:html-document-add-object!
         doc
         (gnc:make-html-text
          (gnc:html-markup-h3
           (format #f (G_ "~a")
                   report-title))))
    doc))
 
;; ------------------------------------------------------------------
;; 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-example)
 '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 sample-report.scm. In there you will find the code initializing the database and filling it with options:

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

Options are directly registered in the option database with a call to gnc-register-<type>-option.

sample-report.scm presents a nice selection of example option definitions of the following types:

gnc-register-simple-boolean-option
gnc-register-multichoice-option
gnc-register-string-option
gnc-register-date-option-set
gnc-register-number-range-option
gnc-register-color-option
gnc-register-account-list-option
gnc-register-list-option

Elsewhere you find:

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

Also, business options:

gnc-register-invoice-option
gnc-register-customer-option
gnc-register-vendor-option
gnc-register-employee-option
gnc-register-owner-option
gnc-register-taxtable-option
gnc-register-counter-option
gnc-register-counter-format-option

In general, the syntax for creating an option is:

(define (gnc-register-<type>-option opitiondb
         section                      ;; the tab-string in the option dialog presented to the user
         name                         ;; the text for this option in the option dialog presented to the user
         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
         <optional 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 report-core.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 sample-report.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.
  • The guile path can be found in Help -> About -> GNC_DATA by selecting the parent folder.

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 with the report results to display to the user. You should refer to the HTML generation description documentation in the source code.

Similar to Options-Generator, sample-report.scm gives you a great introduction to 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>
<html dir='auto'>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<style type="text/css">
@media (prefers-color-scheme: dark) {body {color: #000; background-color: #fff;}}
h3 { font-family: "Segoe UI", sans-serif; font-size: 15pt; font-weight: bold;  }
a { font-family: "Segoe UI", sans-serif; font-size: 10pt; font-style: italic;  }
body, p, table, tr, td { vertical-align: top; font-family: "Segoe UI", sans-serif; font-size: 10pt;  }
tr.alternate-row { background: #ffffff }
tr { page-break-inside: avoid !important;}
html, body { height: 100vh; margin-top: 0px; margin-bottom: 0px; margin-left: 8px; margin-right: 8px; }
td, th { border-color: grey }
th.column-heading-left { text-align: left; font-family: "Segoe UI", sans-serif; font-size: 10pt;  }
th.column-heading-center { text-align: center; font-family: "Segoe UI", sans-serif; font-size: 10pt;  }
th.column-heading-right { text-align: right; font-family: "Segoe UI", sans-serif; font-size: 10pt;  }
td.highlight {background-color:#e1e1e1}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: "Segoe UI", sans-serif; font-size: 10pt;  }
td.number-cell { font-family: "Segoe UI", sans-serif; font-size: 10pt;  }
td.number-header { text-align: right; font-family: "Segoe UI", sans-serif; font-size: 10pt;  }
td.text-cell { font-family: "Segoe UI", sans-serif; font-size: 10pt;  }
td.total-number-cell { font-family: "Segoe UI", sans-serif; font-size: 10pt; font-weight: bold;  }
td.total-label-cell { font-family: "Segoe UI", sans-serif; font-size: 12pt; font-weight: bold;  }
td.centered-label-cell { text-align: center; font-family: "Segoe UI", sans-serif; font-size: 12pt; font-weight: bold;  }
sub { top: 0.4em; }
sub, sup { vertical-align: baseline; position: relative; top: -0.4em; }
@media print { html, body { height: unset; }}
</style></head><body bgcolor="#ffffff"><h3>Report name</h3>
</body>
</html>

The style section is added automatically without specific definitions inside the prototype 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 formatting are given in the following report/ source 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 by 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 for informational purposes only: 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 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, an 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")
    )
)

results 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 sample-report.scm and explore many more examples how to format HTML-text.

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, sample-report.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 of a bar chart report is shown in the following example based on a simple tutorial for generating charts using html-chart.scm. Before running, update name, report-guid and menu-tip values appropriately.

;; -*-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 reports example prototype))

(use-modules (gnucash engine))
(use-modules (gnucash utilities)) 
(use-modules (gnucash core-utils))
(use-modules (gnucash app-utils))
(use-modules (gnucash report))
(use-modules (gnucash html))

(debug-enable 'backtrace)

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

(define (options-generator)
  (gnc-new-optiondb))

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

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

       (gnc:html-chart-set-title! chart "title")
       (gnc:html-chart-set-type! chart "bar")
       (gnc:html-chart-set-width! chart '(pixels . 800))
       (gnc:html-chart-set-height! chart '(pixels . 600))
       (gnc:html-chart-set-y-axis-label! chart "yAxis")
       (gnc:html-chart-set-data-labels! chart '("a" "b" "c"))
       (gnc:html-chart-add-data-series! chart "series1" '(20 40 30) "red")
       (gnc:html-chart-add-data-series! chart "series2" '(30 25 25) "green")
       (gnc:html-chart-set! chart '(options chartArea backgroundColor) "wheat")
	   
       (gnc:html-document-add-object!
        doc
        (gnc:make-html-text
         (gnc:html-markup-h3
          (format #f (G_ "~a")
               N_ "Demonstration"))))

       (gnc:html-document-add-object! doc chart)

       doc
  )
)

;; ------------------------------------------------------------------
;; 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)

If you look at the HMTL source for this report after it is generated, you will see a line with the <img> tag. The image for the report is encoded inline in a very long ASCII code string.

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

The GnuCash API

The GnuCash application programming interface (stable or after the implementation of the first future feature future 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 via gnc:make-gnc-monetary libgnucash/engine/gnc-numeric.scm
  • get the amount of a monetary object via gnc:gnc-monetary-amount libgnucash/engine/gnc-numeric.scm
  • get an account name via xaccAccountGetName libgnucash/engine/Account.cpp
  • create a commodity collector via gnc:make-commodity-collector gnucash/report/report-system/report-utilities.scm

The mightiness of the API is huge. As of GnuCash 2.4.10, there were over 1000 GnuCash api calls that could be made from reports.

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
xaccAccountGetBalanceAsOfDate Account.cpp Returns the account balance as a number.

Example:

(xaccAccountGetBalanceAsOfDate acct date)
gnc:html-table-append-row! html-table.scm Appends a row to an 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. 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 gnc_account_get_full_name() in Account.cpp sample-report.scm Returns the account name in the format

ParentLevel1:ParentLevel2:...:AccountName

To only get the AccountName use xaccAccountGetName

xaccTransGetDate xaccTransGetDate() in Transaction.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, like so:
(qof-print-date (xaccTransGetDate (xaccSplitGetParent split)))
gnc-window-show-progress gnc_window_show_progress() in gnc-window.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
xaccAccountGetDescription Account.cpp Returns the account description. To be used with the account as input parameter:
(xaccAccountGetDescription acct)
xaccAccountGetName Account.cpp sample-report.scm Returns the account name. To get the full account name including parent names use gnc-account-get-full-name
xaccAccountGetNotes Account.cpp Returns the account notes. This 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 Account.cpp 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 makes use of this api.

xaccAccountGetType Account.cpp 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)

The following account 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 Split.c Returns the account object that the split belongs to. To get the name from the returned account, use:
(xaccAccountGetName (xaccSplitGetAccount split))
xaccSplitGetCorrAccountName Split.c Returns the account name at the other end of the split as a string.
xaccSplitGetParent Split.c Returns the parent transaction the split belongs to. See xaccTransGetDate for an example how to use it.


Command line access to the API

(Written Jan 2018) It is convenient to access the full API from a Guile Command-line for newbie report developers. This requires the developer is familiar with Linux, and can set up CMake, unit testing environments.

The full GUI-generated reporting construct described above is important to test a custom report, however, is very inconvenient to explore the API.

The preparation work involves:

1. Create a special unit test program in scheme, perhaps naming it test-server.scm - this shall reside in a convenient folder with other unit test files e.g. gnucash/report/standard-reports/test.

(use-modules (gnucash gnc-module))
(use-modules (gnucash app-utils))
(use-modules (gnucash engine test test-extras))

;; The following needed for Guile REPL
(use-modules (system repl server))
(define (run-test)
  (run-server))

;; The following needed for reports:
(use-modules (gnucash report stylesheets))
(use-modules (gnucash report report-system))
(define constructor (record-constructor <report>))

2. Adding test-server.scm onto the CMakeFiles.txt in the same folder to enable compilation

3. Running make or ninja to generate the build directory

4. Running test-server.scm from the build directory by

cd build/gnucash/report/standard-reports/test
/usr/bin/ctest -R test-server

This will run the test server.

5. Switch to another terminal, run

nc localhost 37146 (the default guile port, upside down 37146 looks like guile...)

This will now present a full Guile REPL prompt, with full access to the test-server.scm bindings as well as the Gnucash API. People familiar with emacs and the geiser package may also connect to the server by M-x connect-to-guile. Unfortunately so far, only the environment is loaded. I do not think the file-load mechanism is accessible to scheme, which is an inconvenience for testing reports.

The developer can try:

> ,apropos xacc [RET]
(sw_engine): xaccTransEqual	#<procedure xaccTransEqual (_ _ _ _ _ _)>
(sw_engine): xaccSplitGetCorrAccountCode	#<procedure xaccSplitGetCorrAccountCode (_)>
(sw_engine): xaccAccountGetReconciledBalance	#<procedure xaccAccountGetReconciledBalance (_)>
(sw_engine): xaccClearMarkDown	#<procedure xaccClearMarkDown (_ _)>
(sw_engine): xaccSplitSetBaseValue	#<procedure xaccSplitSetBaseValue (_ _ _)>
(sw_engine): xaccTransGetFirstAPARAcctSplit	#<procedure xaccTransGetFirstAP

etc

> ,apropos gnc- [RET]
(sw_engine): gnc-monetary-list-delete-zeros	#<procedure gnc-monetary-list-delete-zeros (_)>
(sw_engine): gnc-gdate-set-prev-fiscal-year-start	#<procedure gnc-gdate-set-prev-fiscal-year-start (_ _)>
(sw_engine): gnc-quote-source-get-internal-name	#<procedure gnc-quote-source-get-internal-name (_)>
(sw_engine): gnc-numeric-check	#<procedure gnc-numeric-check (_)>
(sw_engine): gnc-timegm	#<procedure gnc-timegm (_)>
(sw_engine): gnc-account-join-children	#<procedure gnc-account-join-c

etc

> ,bindings
constructor             #<variable 55cae1534b70 value: #<procedure 55cae11ff080 at ice-9/boot-9.scm:1340:17 (a b c d e f g h)>>
%module-public-interface #<variable 55cae0652da0 value: #<interface (guile-user) 55cae0638b40>>
run-test                #<variable 55cae1534cc0 value: #<procedure run-test ()>>

> (current-time)
1515297631

> (qof-print-date (current-time))
"07/01/18"

> (qof-date-format-set QOF-DATE-FORMAT-ISO)
> (qof-print-date (current-time))
"2018-01-07"

Adding Menu Items

The following example shows how to add a menu item from Scheme. The code adds the menu item Tools › Scheme REPL and the corresponding command starts a Scheme REPL in the tty.

Installation:

1. Save the code somewhere in your file system like in ~/hacking/gnucash/commands/repl.scm.

2. Add something like this to your ~/.config/gnucash/config-user.scm:

(add-to-load-path "/home/helmut/hacking/gnucash/")
(import (only (commands repl) register-repl-command))
(register-repl-command)

3. Start GnuCash as usual.



Code:

(library (commands repl)
  (export register-repl-command)
  (import (rnrs base)
	  (only (guile) format getenv resolve-module current-module
		set-current-module save-module-excursion)
	  (only (system repl repl) start-repl)
	  (only (ice-9 readline) activate-readline write-history read-history)
	  (only (gnucash gnome-utils) gnc-add-scm-extension)
	  (only (gnucash gnome-utils gnc-menu-extensions) gnc:make-menu-item)
	  (only (gnucash core-utils) G_ N_))

  (define history-filename (format #f "~a/.gnucash_history" (getenv "HOME")))

  (define previous-module #f)

  (define (repl)
    (save-module-excursion
     (lambda ()
       (set-current-module (or previous-module
			       (begin
				 (read-history history-filename)
				 (activate-readline)
				 (resolve-module '(guile-user)))))
       (start-repl)
       (set! previous-module (current-module))
       (write-history history-filename)
       (format #t "Goodbye~%"))))

  (define menuname-tools (N_ "Tools"))

  (define (register-repl-command)
    (gnc-add-scm-extension
     (gnc:make-menu-item
      "Scheme REPL"
      "0155032a4b41443388f6cf8effc98169"
      "Start a Scheme REPL in the tty"
      (list menuname-tools)
      (lambda (window)
	(repl)))))

  )

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

  • Program 'uuidgen' is present in package 'util-linux' and 'sed' in 'sed'.
  • Table of existing GUIDs: Report GUIDs
  • Retrieved from "https://wiki.gnucash.org/wiki/index.php?title=Custom_Reports&oldid=21929"