Banana Accounting API Extensions Reference

Extensions API, Namespace, Formats, Versions

Banana namespace

The whole API (Application Program Interface) made available for Banana is under the namespace "Banana".
There are different objects and methods that belong to the namespace Banana, that can be accessed by the javascript at run time:

String Data Type

String Data Type are String that contains text for different purposes. 
Banana Accounting Extensions make a lot of use of String Data Types. 
For example Data.row.value("columnNameXML) return a String that may contains a different value based on the column type.
It is up to the developer to know what kind of Data Type the String contains and use the content appropriately.

Date

Date values are in ISO 8601 format "YYYY-MM-DD".

Decimal

Decimal values have a  '.' (dot) as decimal separator and don't have a group separator. For example: "12345.67".
Decimal values are rounded according to the accounting settings.

Text

Text values can contain any character supported by UTF-8.

Time

Time values are in ISO 8601 format "HH:MM:SS". The formats "HH:MM" and "HH:MM:SS.ZZZ" are also accepted.

API Version

List of API Version made available by Banana Accounting.

In the script you can set the attribute @api to notify the required minimum version.

Banana Accounting VersionAPI Version
7.0.61.0
8.0.7 or more recent1.0
9.0.0 or more recent1.0
Plus1.2.4
Plus Insider1.2.5

 

Banana (Objects)

Banana is the namespace (object) through which all Banana script's methods, class and objects are accessible.

Banana Properties

Banana.application

The object Banana.application represents the running application.

Banana.console

The object Banana.console is used to send messages to the debug script.

Banana.Converter

The class Banana.Converter contains methods useful to convert data from and to various formats.

Banana.document

The object Banana.document represents the document currently open in the application. It contains base properties and methods, see Banana.Document (Base), and if the document represents an accounting document that contains additional accounting's properties and methods, see Banana.Document (Accounting). If any document is opened this object is of type Undefined.

Banana.IO

The class Banana.IO is used to read and write files.

Banana.Report

The class Banana.Report enables you to create reports, preview and print them in Banana Accounting.

Banana.script

The object Banana.script is used to get information about the running script.

Banana.SDecimal

The class Banana.SDecimal contains methods useful for decimal math calculation.

Banana.Test

The class Banana.Test contains methods to run test units.

Banana.Ui

The class Banana.Ui contains predefined dialogs to interact with the user, and methods to load dialogs from .ui or .qml files.

Banana.Xml

The class Banana.Xml contains methods to parse and access Xml data.

Banana Methods

Banana.compareVersion(v1, v2)

Compares two version strings. Version strings are in the form of "x.y.w.z". Returns 0 if v1 and v2 are equal, -1 if v2 is later and 1 if v1 is later.


var requiredVersion = "8.0.5";
if (Banana.compareVersion && Banana.compareVersion(Banana.application.version, requiredVersion) >= 0)
   Banana.Ui.showInformation("Message", "More recent or equal than version " + requiredVersion);
else
   Banana.Ui.showInformation("Message", "Older than version " + requiredVersion);

Banana.include(path)

The method Banana.include(path) includes a javascript file evaluating it.
If an error occurs, i.e. the file is not found or is not valid, the method throws an exception.

The path is relative to the current script being executed, if no protocol is specified. 

The application searches for include files in this order:
1) In the same directory as the current file.
2) In the directories of the currently opened include files, in the reverse order in which they were opened. 

If a protocol is defined, depending on the protocol, the path is relative to the main script's folder, the document's folder or the name of a document attacched to the current file.
- <relative_path_to_current_script>/<file_name>
- file:script/<relative_path_to_main_script>/<file_name>
- file:document/<relative_path_to_file>/<file_name>
- documents:<attachment_name>

Scripts included through the method Banana.include(path) can include other scripts through the method Banana.include(path), but not via the script's attibute @includejs. The method Banana.include(path) garantees that each distinct script is evaluated once, even if it is included more than one time from differents scripts. Path can contain ".." (parent folder), in the case the destination path is outside the main script's folder, the method will throw a security exception.


Banana.include("cashflowlib.js"); // a js file in the same folder
Banana.include("folder/cashflowlib.js"); // a js file in a subfolder
Banana.include("file:document/cashflowlib.js"); // a js file stored in the document table

 

Banana.Application

Banana.Application represents the interface to the program and can be accessed through Banana.application.

Properties

 apiVersion

Returns the version of the implemented Js Banana API in the form of "1.2.2".

For the different versions see API Versions and the changelog.



var qtVersion = Banana.application.apiVersion; // Returns "1.2.2"

 

 isExperimental

Returns true if the application is an experimental version.



var isExperimental = Banana.application.isExperimental;

 isInternal

Returns true if the application is an internal version.



var isInternal = Banana.application.isInternal;

 

 license

Returns an object containing informations about the active license, or null if no license is active.

The properties of the returned object are:

  • licenseType (string):  one of "professional" or "advanced"
  • exprirationDate (string):  null if no expiration, or the expiration in form of "yyyy-mm-dd"
  • language (string):  "all" if all languages are available, or the licensed language code, i.e: "it", "nl", ...
  • isWithinMaxFreeLines(bool): (from version 10.0.7)  true if you have not yet passed the limits of the demonstration mode. For accounting applications: 70 Transaction rows, 20 Budget rows, 20 rows for added table. For other applications (Invoices, Inventory, Addresses) 20 rows for any table.
    isWithinMaxFreeLines returns always false if the license type is Advanced, because the rows limit is not checked


var license = Banana.application.license;

// Example:
// { 
//    "licenseType": "professional",
//    "expirationDate": "2022-10-24",
//    "language":"all",
//    "isWithinMaxFreeLines":true
// }

if (!Banana.application.license || Banana.application.license.licenseType !== "advanced") {
   Banana.document.addMessage("This extension requires Banana Accounting+ Advanced");
}

 

 qtVersion

Returns the version of the used qt framework in the form of "6.4.1".



var qtVersion = Banana.application.qtVersion; // Returns "6.4.1"

 

 serial

Returns the serial of the application in the form of "100010-320".



var serial = Banana.application.serial; // Returns "100012-320"

 

 version

Returns the version of the application in the form of "10.0.12".



var version = Banana.application.version;

 

locale

Returns the locale of the application in the form of "language_country", where language is a lowercase, two-letter ISO 639 language code, and country is an uppercase, two- or three-letter ISO 3166 country code.



var locale = Banana.application.locale;

 

progressBar

Returns an object of type ProgressBar used to give the user an indication of the progress of an operation and the ability to cancel it.



var progerssBar = Banana.application.progressBar;

 

Methods

 

 addMessage(msg [, idMsg])

Adds the message msg to the application. The message is showed in the pane "Messages", and in a dialog if the application option "Show Messages" is turned on.

If idMsg is not empty, the help button calls an url with script's id and message's id (idMsg) as parameters.



Banana.application.addMessage("Hello World");

 

See also: Table.AddMessage, Row.AddMessage, Document.AddMessage.

 

clearMessages()

Clears all the messages showed in the pane "Messages".



Banana.application.clearMessages();

 

 getMessages()

Returns all messages showed in the pane "Messages".


let msgs = Banana.application.getMessages();
for (let i = 0; i < msgs.length; ++i) {
   let msg = msgs[i];
   Banana.console.log("Error: " + msg.message);
}

The message object contains following properties:

  • message: the message in the application language;
  • referer:  a string describing to which the message refer (usually the file name);
  • level: the level of the message as string, can be one of "debug", "info", "warning", "debug";
  • helpId: the help id of the message, used to link to the documentation;
  • fileUuid: an id as string that uniquely identifies the file to which the message refer or empty;
  • fileName: the file name that identifies the file to which the message refer or empty;
  • tableName: the table name to which the message refer, or empty;
  • rowNr: the row number as number to which the message refer, or -1;
  • columnName: the column name to  which the message refer to, or empty;

See also: Document.getMessages.

showMessages([show])

Enable or disable the notification of new messages through the message dialog.



Banana.application.showMessages(); // Next messages are showed to the user through the message dialog.
Banana.application.showMessages(false); // Next messages will not pop up the message dialog.

 

 openDocument(ac2FilePath [, password] [, title])

Opens the ac2 file located in filePath and returns an Object of type Banana.Document or undefined if the file is not found. The path can be relative, in this case the base directory is the path of the current document.

If the path is empty or contains a "*" or a "?" an open file dialog is showed to the user, and the title is used in the caption of the file open dialog.

With this function you can also open ISO 20022 and MT940 files, in this case a cash book with the transactions of the file is returned.



var file1 = Banana.application.openDocument("*.*");
if (!file1)
   return;

var file2 = Banana.application.openDocument("c:/temp/accounting_2015.ac2");
if (!file2)
   return;

 

Banana.Application.ProgressBar

Banana.Application.ProgressBar is the interface to the program progress bar and can be accessed through Banana.application.progressBar. The progressBar object is used to give the user an indication of the progress of an operation and the possibility to interrupt the running process. The progress bar is showed in bottom left corner of the application windows.



// Example use of a progress bar
var progressBar = Banana.application.progressBar;
progressBar.start(10);
for (var i = 0; i < 10; i++) {
   ...
   if (!progressBar.step(1)) {
      return; // Operation canceled by the user
   }
}
progressBar.finish();

Properties

showDetails

If true details are showed in the progess bar. If false only the text set by the first progressBar.start() call is showed.



progressBar.showDetails = false; // Example without details: "VAT Report"
progressBar.showDetails = true; // Example with details: "Vat Report; Sales; Row: 120"

Since Banana Accounting 9.0.3.

Methods

finish()

Notifies that the operation has been completed and closes the progress bar.

Returns false if the user canceled the operation, otherwise true.



progressBar.finish();

 pause()

Notifies that the operation has been paused, the cursor icon is set to the arrow cursor or poiting hand cursor. This is usually called before showing a dialog.



Banana.application.progressBar.pause();
var result = dialog.exec();
Banana.application.progressBar.resume();

resume()

Notifies that the operation has been resumed, the cursor icon is set back to an hourglass or watch cursor. This is usually called after a dialog has been closed.



Banana.application.progressBar.pause();
var result = dialog.exec();
Banana.application.progressBar.resume();

start(maxSteps)

Starts the progress indicator and defines the number of steps this operation needs before being complete.

You can call this method several times to split the progress in main and sub steps. Every call of the method start() should be paired with a call of the method finish().

Returns false if the user canceled the operation, otherwise true.



// Example use of a progress bar
var progressBar = Banana.application.progressBar;
progressBar.start(10);
for (var i = 0; i < 10; i++) {
   ...
   if (!progressBar.step(1)) {
      return; // Operation canceled by the user
   }
}
progressBar.finish();

start(text, maxSteps)

Starts the progress indicator and defines the text to be showed in the progress bar as well as the number of steps this operation needs before being complete.

You can call this method several times to split the progress in main and sub steps. Every call of the method start() should be paired with a call of the method finish().

Returns false if the user canceled the operation, otherwise true.



// Example use of a progress bar
var progressBar = Banana.application.progressBar;
progressBar.start("Checking rows", 10);
for (var i = 0; i < 10; i++) {
   ...
   if (!progressBar.step("Row: " + i.toString())) {
      return; // Operation canceled by the user
   }
}
progressBar.finish();

Since Banana Accounting 9.0.3.

setText(text)

Sets the text to show in the progress bar. 



progressBar.setText("Checking vat rates");

Since Banana Accounting 9.0.3.

step([stepCount])

Advances the progress indicator of stepCount steps. If stepCount is not defined, it advances of one step.

Returns false if the user canceled the operation, otherwise true.



progressBar.step(1);

step(text, [stepCount])

Advances the progress indicator of stepCount steps and sets the text of the progress bar. If stepCount is not defined it advances of one step.

Returns false if the user canceled the operation, otherwise true.



progressBar.step("Row: " i.toString());

Since Banana Accounting 9.0.3.

Example multiple steps inside a block



// Two blocks of progress bar inside a progressBar
var progressBar = Banana.application.progressBar;

progressBar.start("Vat Report", 2);

// Block 1
progressBar.start("Sales", 10)
for (i = 0; i < 10; i++) {
   progressBar.step("Row: " + i.toString());
}
progressBar.finish();

// Block 2
progressBar.start("Purchases", 10)
for (i = 0; i < 10; i++) {
   progressBar.step("Row: " + i.toString());
}
progressBar.finish();

progressBar.finish();

 

 

Banana.Console

The Banana.console object is used to output messages to the Debug output panel or to the terminal (command prompt). The methods in this object are mainly used for Debugging purposes.

  • To open the debug panel you have to enable the option "Display Debug output panel" under -> Program Options -> Tab Developer options
  • The debug panel is located on the bottom of the main window near the Info and Messages panels
  • In the debug panel you can choose the level of messages to shows, using the right button of the mouse. The levels are: Warnings, Debug and Info
  • Debug messages can also be displayed in the terminal (command prompt) if the application is started from a terminal (command prompt) 

Methods

console.critical(msg)

Display the msg in the debug panel as critical message.



Banana.console.critical("critical message");

console.debug(msg)

Display the msg in the debug panel as a debug message.
Debug messages are shown if either the 'Debug level' or 'Info level' is selected in the panel.



Banana.console.debug("Debug message");

console.info(msg)

Display the msg in the debug panel as an info message.
Info messages are shown in the panel only if the 'Info level' is selected.



Banana.console.info("Debug message");

console.log(msg)

Display the msg in the debug panel as an info message.
Log messages are shown only if in the panel 'Info level' is selected.



Banana.console.log("Debug message");

Since Banana 9.0.4

console.warn(msg)

Display the msg in the debug panel as a warning.



Banana.console.warn("Warning message");

Deprecated since Banana 9.0.4 use console.warning method instead.

console.warning(msg)

Display the msg in the debug panel as a warning.



Banana.console.warning("Warning message");

Since Banana 9.0.4

Banana.Converter

The class Banana.Converter is static only class, with static methods useful to convert various formats to and from data tables (array of arrays).

It is not possible to have instance of Banana.Converter.

Methods

arrayToObject( headers, arrData, skipVoid)

Static method.
Converts an array of arrays of string to an array of objects

  • headers is an array of strings that will become the properties of the objects.
  • arrData is an array containing arrays of strings
  • skipVoid if true skip void lines, if not present is set to false

// read a CSV file
var ppData = Banana.Converter.csvToArray(string, ',');    
// first line is header
var headers = ppData[0];
// remove first line
ppData.splice(0, 1);
// convert in array of objects
var arrayOfObjects = Banana.Converter.arrayToObject(headers, ppData, true);
// you can now access the data with a the column name used in the csv header 
let name = arrayOfObjects[0]["name"]

csvToArray(string [, separator, textdelim])

Static method.
Convert a csv file (coma separated values) to an array of arrays.

The parameter string contains the text to convert. The parameter separator specifies the character that separates the values, default is a comma ','. The parameter textDelim specifies the delimiter character for text values, default is a double quote '"'.

Example:


var text = "1, 2, 3\n4, 5, 6\n7, 8, 9";
var table = Banana.Converter.csvToArray(text);
var value = table[0][1];
value == '2'; // true

flvToArray(string, fieldLengths)

Static method.
Convert a flv file (fixed length values) to an array of arrays.

The parameter string contains the text to convert. The parameter fieldLengths is an array with the lengths of the fields.

Example:


//               6                  20       8
var text = "120608Phone               00002345";
var table = Banana.Converter.flvToArray(text, [6,20,8]);
var value = table[0][2];
value == '00002345'; // true

mt940ToTable(string)

Static method.
Converts a mt940 file to a table (array of array).

naturalCompare(a, b [, caseSensitive])

Compares two strings so that the string "2" is considered less then "100" as it would be with normal string compare.
This function can be passed to array.sort function.

  • a first value to compare
  • b second value to compare
  • return value is -1 if a < b, 1 if a > b and 0 if a == b

Banana.Converter.naturalCompare(a,b);

objectArrayToCsv(headers, objArray, [separator])

Static method.
Converts an array of objects (with identical schemas) into a CSV table.

  • headers An array of strings with the list of properties to export
  • objArray An array of objects. Each object in the array must have the same property list.
  • separator The CSV  column delimiter. Defaults to a comma (,) if omitted.
  • return value a string containing the CSV text.

var csvText = Banana.Converter.objectArrayToCsv(headers, objArray, ";");

stringToCamelCase(string)

Static method.
Converts a text to camel case, where only the first letter of every word is upper case.


Banana.Converter.stringToCamelCase("this is an example"); 
// returns "This Is An Example";

stringToLines(string)

Static method.
Convert a text in an array of lines. The end line character can be '\n', \r' or a combination of both.


Banana.Converter.stringToLines("this is\nan\nexample");
// returns ["this is", "an", "example"]

stringToTitleCase(string)

Static method.
Converts a text to title case, where only the first letter of the text is upper case.


Banana.Converter.stringToTitleCase("this is an example"); 
// returns "This is an example";

arrayToTsv(table [, defaultChar])

Static method.
Converts a table (array of arrays) to a tsv file (tabulator separated values). If a string contains a tab it will be replaced with defaultChar or a space if defaultChar is undefined.


Banana.Converter.arrayToTsv(table);

arrayToCsv(table)

Static method.
Converts a table (array of arrays) to a csv file (comma separated values). Double quotes in text are replaced by apos. Texts containing commas are inserted in doubles quotes.


Banana.Converter.arrayToCsv(table);

textToHash(text, algorithmName)

Static method.
Converts a text string into a hash using the algorithm passed as a parameter, to see the available algorithms see QCryptographicHash::Algorithm.


Banana.Converter.textToHash(text,algorithmName);

toDate(date[, time])

Static method.
Converts a date and/or time to a javascript date object.

The parameter date is a Date String in the formats yyyymmdd or yyyy-mm-dd.

The time parameter is a Date String in the fromats HHMM[SSZZZ] or HH:MM[:SS.ZZZ].


Banana.Converter.toDate("2015-12-31");
Banana.Converter.toDate("20151231");

toInternalDateFormat(date [, inputFormat])

Static method.
Convert the date argument in Date String Format.
Internal means Date String format "yyyy-mm-dd".

The parameter date  can be a String or a Date object.

The parameter inputFormat is a string that specifies the date input format.

  • If it is not specified the local date format is used
  • Format use lower case characters y, m, d for example "yyyy-mm-dd".
  • Possibly specify exactly the input format and also the separator used in the input date, or else use the "-" as a separator.
  • For example:
    • date "31.12.2024"  inputFormat "dd.mm.yyyy" convert to "2024-12-31"
    • date "31-12-24"  inputFormat "dd.mm.yy"convert to "2024-12-31"
    • date "12/31/24"  inputFormat "mm/dd/yy"convert to "2024-12-31"

Example: 


Banana.Converter.toInternalDateFormat("31-12-13", "dd-mm-yy");
// returns "2013-12-31"
Banana.Converter.toInternalDateFormat(new Date());
// return current date in format "yyyy-mm-dd"

toInternalNumberFormat(value [, decimalSeparator])

Static method.
Internal Number format means a Numeric String containing only number.
Converts a localized number into the a Numeric String used by the system. 
The function strip all character that are not numeric or minus "-" or decimalSeparator. 

Parameters:

  1. value (string | number):
    The number to be converted. This can be a string or a number object and may include locale-specific formatting (e.g., thousand separators and a localized decimal separator).
  2. decimalSeparator (optional, string):
    Specifies the character used as the decimal separator in the input. If not provided, the function will use the decimal separator of the current locale.
    The first occurrence of decimalSeparator is replaced by the "." and the others are discarded.

Returns:

  • A Numeric String representing the number in the internal format, with a period (.) as the decimal separator and no thousand separators.

Example: 


Banana.Converter.toInternalNumberFormat("1200,25", ",");
// returns "1200.25";

toInternalTimeFormat(string)

Static method.
Converts a time value to the system's internal format, represented as HH:MM:SS.ZZZ. If the milliseconds are zero, they are omitted from the returned string.

Parameters:

  1. value (string | Date):
    • The input time value to be converted.
    • Can be a string representing a time (e.g., "12:34:56.789") or a JavaScript Date object.

Returns:

  • A string in the internal time format: HH:MM:SS.ZZZ.
  • If the milliseconds portion is 0, it will return the format as HH:MM:SS without the .ZZZ part.

Banana.Converter.toInternalTimeFormat("11:24")
// returns "11:24:00";
Banana.Converter.toInternalTimeFormat(new Date(2020, 1, 1, 10, 24, 0, 0))
// returns "11:24:00";
Banana.Converter.toInternalTimeFormat(new Date());

toLocaleDateFormat(date [, format])

Static method.
Converts a date to the local format. The format is taken from the operating system settings.

The parameter date can be a string or  a date object.

The parameter format specifies the date ouptut format, if it is not specified the local date format is used.


Banana.Converter.toLocaleDateFormat("2014-02-24")
// returns "24.02.2014"

 toLocaleNumberFormat(value [, decimals = 2, convZero = true])

Static method.
Converts a number to the local format.

The parameter value can be a string or a number object.

The parameter decimals sets the number of decimals.

The parameter convZero sets the format returned for zero values. If false the method returns an empty string, if true it returns the zero value as string.

Example: 


Banana.Converter.toLocaleNumberFormat("1200.25") 
// returns "1'200,25";

toLocalePeriodFormat(startDate , endDate [, format])

Static method.
Converts a period defined by startDate and endDate to a readable string.

The parameter startDate specifies the start date of the preriod, can be a date object or a string.
The parameter endDate specifies the end date of the preriod, can be a date object or a string.
The parameter format can be empty or one of the following strings: 'short', 'long'. Default is 'long'.

Return the period as a readable string in the current language of the application.


Banana.Converter.toLocalePeriodFormat("2017-01-01", "2017-01-31"); // returns "January '17"
Banana.Converter.toLocalePeriodFormat("2017-01-01", "2017-01-31", "short"); // returns "Jan '17" 
Banana.Converter.toLocalePeriodFormat("2017-01-01", "2017-01-31", "long"); // returns "January '17"

toLocaleTimeFormat(string [, format])

Static method.
Converts a time to the local format.

The parameter format specifies the time ouptut format, if it is not specified the local time format is used.


Banana.Converter.toLocaleTimeFormat("11:24:42");
// returns "11:24";

 

 

Banana.Document (Accounting)

Methods for accounting's files

Banana is built with object oriented techologies. Each file is a Banana.document class.

Accounting files are elements of class that derive from the Banana.document.
For each file there are:

The following explanations relate to the accounting functions.

Date functions

endPeriod([period])

Return the end date in the form of 'YYYY-MM-DD'.

The endDate and startDate functions are used to retrieve the date of the accounting, so that you can create scripts that work on files from different years.



var dateEnd = Banana.document.endPeriod();
var dateStartFebruary = Banana.document.endPeriod('2M');
  • Period:
    • If period is not present the return value is the end date of the accounting.
    • The period is added to the starting account date, and the last date of the period is returned.
    • Period (for example 2M = 2 months) is a number followed by one of the following charachters
      • D for days
      • M for months
      • Q for quarters
      • S for semesters
      • Y for years
    • Assuming that the Start accounting date is 2015-01-01
      • 1M return 2015-01-02
      • 2M return 2015-02-28
      • 2Q return 2015-06-30
      • 2S return 2015-12-31
      • 2Y return 2016-12-31

 

startPeriod ([period])

Return the end date in the form of 'YYYY-MM-DD'.

The endPeriod and startPeriod functions are used to retrieve the date of the accounting, so that you can create scripts that work on files from different years.



var dateStart = Banana.document.endPeriod();
var dateStart3Q = Banana.document.endPeriod('3Q');
  • Period:
    If period is not present return the start date.
    • Period (for example 2M = 2 months) is a number followed by one of the following charachters
      • D is for Days
      • M for Months
      • Q for Quorters
      • S for Semester
      • Y for year
    • With 1 the starting date of the accounting is returned.
    • Assuming that the Start accounting date is 2015-01-01
      • 1M return 2015-01-01
      • 2M return 2015-02-01
      • 2Q return 2015-04-01
      • 2S return 2015-07-01
      • 2Y return 2016-01-01

 previousYear([nrYears])

Returns the previous year as a Banana.Document object. If the previous year is not defined or it is not found, it returns null.

  • nrYears is the number of years to go back, default is one.


var previousYearDoc = Banana.document.previousYear();
var previousTwoYearDoc = Banana.document.previousYear(2);

Current accounting functions

The functions that start with "current" retrieve values calculated based on the actual accounting data, comprising:

  • Opening amounts (Table accounts)
  • Transactions entered in the Transactions table

 currentBalance(account [, startDate, endDate, function(rowObj, rowNr, table) ])

Sum the amounts of opening, debit, credit, total and balance calculated based on the opening and all transactions for this account / group.

The calculations are performed by traversing by creating a journal (see journal() function) with all the transactions, and selecting the transactions with the parameters specified.
The computation is usually very fast. But if you  have a file with many transactions especially the first query could take some time. 



var currentBal = Banana.document.currentBalance('1000','','');
var openingBalance = currentBal.opening;
var endBalance = currentBal.balance;
  • Return value
    Is an object that has
    • opening the amount at the begining of the period (all transactions before)
    • debit the amount of debit transactions for the period
    • credit the amount of credit transactions for the period
    • total the difference between debit-credit for the period
    • balance opening + debit-credit for the period
    • amount it the "normalized" amount based on the bclass of the account or group.
      If there are multiple accounts or groups, takes the first BClass of the first.
      • for BClass 1 or 2 it returns the balance (value at a specific instant).
      • for BClass 3 or 4 it returns the total (value for the duration).
      • For BClass 2 and 4 the amount is inverted.
    • openingCurrency the amount at the begining of the period in the account currency
    • debitCurrency the amount of debit transactions for the period in the account currency
    • creditCurrency the amount of credit transactions for the period in the account currency
    • totalCurrency the difference between debit-credit for the period in the account currency
    • balanceCurrency opening + debit-credit for the period in the account currency
    • rowCount the number of lines that have been found and used for this computation
    • bclass (double entry accounting only) is the bclass of the account or group used to express the amount.
      The bclass is the value entered in the columns bclass.
      It is taken in consideration the first account or group specified. If for example you query two accounts that first has bclass 2 and the second has bclass 1. The bclass would be 2.
      The bclass is assigned by following this steps. :
      • The bclass of the specified account or group.
      • The bclass of the partent group, for the same section.
      • The bclass of the section.
  • Account
    • can be an account id, a cost center, a segment or a group.
    • can be a combination of account and segments, separated by the semicolon ":"
      In this case it returns all the transactions that have the indicated account and segments
      • 1000:A1:B1
    • can be different accounts and multiple segments separated by the "|"
      In this case it includes all transactions that have one of the specified accounts and one of the specified segments
      • 1000|1001
      • 1000|1001:A1:B1
      • 1000|1001:A1|A2:B1
    • can be a wildCardMatching
      Wildcards can be used for accounts, segments, Groups or BClass and in combination
      • ?  Matches any single character.
      • *  Matches zero or more of any characters
      • [...] Set of charachtes
      • "100?" match "1001, 1002, 1003, 100A, ...)
      • "100*" Matches all accounts starting with 100
      • "100*|200*:A?" Matches all accounts starting with 100 or 200 and with segments with A and of two charachters.
      • "[1234]000" Matches "1000 2000 3000 4000"
    • Can be a group or a BClass.
      It includes all the transactions where the account used belongs to a specified Group or BClass.
      It is also possible to use wildcards.
      The program first creates a list of accounts and then uses the account list.
      Do non mix groups relative to normal accounts, with groups relative to cost center or segments. Calculation could provide unexpected results.
      • BClass (for the double entry accounting only)
        • BClass=1
        • BClass=1|2
      • Gr for groups that are in Accounts table.
        • Gr=100
        • Gr=10*
        • Gr=100|101|102
      • GrC for group that are in the Category table of the income and expenses accounting type.
        • GrC=300
        • GrC=300|301
    • Can be Contra Accounts or other fields selection
      Transactions are included only if they have also a value corresponding
      After the "&&" you can insert a field name of the table journal.
      • 1000&&JContraAccount=2000 returns all transactions of the account 1000 that have a contra account 2000.
        As per accounts you can specify multiple contra accounts, BClass=, Gr= with also wildcards.
      • 1000&&JCC1=P1|P2 will use only transactions on account 1000 and that also have the CC1=.P1 or .P2
    • Do not mix accounts or groups with cost centers ("1020|,RF2" or ",RF2|10"). It only returns the cost center amount.
  • StartDate
    • is a string in form 'YYYY-MM-DD' or a date object.
    • If startDate is empty the accounting start date is taken.
  • End date:
    • is a string in form 'YYYY-MM-DD' or a date object.
    • If endDate is empty the accounting end date is taken.
  • function(rowObj, rowNr, table)
    This fuction will be called for each row of the selected account.
    The function should return true if you want this row to be included in the calculation.


function exec( string) {
    // We retrive the total sales (account 4000) only for the cost center P1
    var balanceData = Banana.document.currentBalance('4000','', '', onlyCostCenter);
    // sales is a revenue so is negative and we invert the value
    var salesCC1 = -balanceData.total;
    // display the information
    Banana.Ui.showText("Sales of Project P1: " + salesCC1);
}

// this function returns true only if the row has the cost center code  "P1"
function onlyCostCenter( row, rowNr, table){
   if(row.value('JCC1') === 'P1') {
      return true;
   }
   return false;
}

Examples



Banana.document.currentBalance("1000")              // Account 1000 
Banana.document.currentBalance("1000|1010")         // Account 1000 or  1010 
Banana.document.currentBalance("10*|20*")           // All account that start with 10 or with 20
Banana.document.currentBalance("Gr=10")             // Group 10
Banana.document.currentBalance("Gr=10|20")          // Group 10 or  20
Banana.document.currentBalance(".P1")               // Cost center .P1
Banana.document.currentBalance(";C01|;C02")         // Cost center ;C01 and C2
Banana.document.currentBalance(":S1|S2")            // Segment :S1  and :S2
Banana.document.currentBalance("1000:S1:T1")        // Account 1000 with segment :S1 or ::T1
Banana.document.currentBalance("1000:{}")           // Account 1000 with segment not assigned 
Banana.document.currentBalance("1000:S1|S2:T1|T2")  // Account 1000 with segment :S1 or ::S2 and ::T1 or ::T2
Banana.document.currentBalance("1000&&JCC1=P1")     // Account 1000 and cost center .P1

 currentBalances(account, frequency [, startDate, endDate, function(rowObj, rowNr, table) ])

It returns the time series balance for the specified periods. It is used for chart rendering, with one command you can have the monthly data for an account.

Sum the amounts of opening, debit, credit, total and balance for all transactions for this account and returns the values according to the indicated frequency indicated.

The calculations are perfermed by traversing by creating a journal (see journal() function) with all the transactions , and selecting the transactions with the parameters specified.
The computation is usually very fast. But if you  have a file with many transactions especially the first query could take some time. 



var currentBalances = Banana.document.currentBalances('1000', 'M');
var openingBalance = currentBalances[0].opening;
var endBalance = currentBalances[0].balance;
  • Return value
    Return an array of objects that have
    • opening the amount at the begining of the period (all transactions before)
    • debit the amount of debit transactions for the period
    • credit the amount of credit transactions for the period
    • total the difference between debit-credit for the period
    • balance opening + debit-credit for the period
    • amount it the "normalized" amount based on the bclass of the account or group.
      If there are multiple accounts or groups, takes the first BClass of the first.
      • for BClass 1 or 2 it return the balance (value at a specific instant).
      • for BClass 3 or 4 it return the total (value for the duration).
      • For BClass 2 and 4 the amount is inverted.
    • openingCurrency the amount at the begining of the period in the account currency
    • debitCurrency the amount of debit transactions for the period in the account currency
    • creditCurrency the amount of credit transactions for the period in the account currency
    • totalCurrency the difference between debit-credit for the period in the account currency
    • balanceCurrency opening + debit-credit for the period in the account currency
    • rowCount the number of lines that have bben found and used for this computation
    • bclass (double entry accounting only) is the bclass of the account or group used to express the amount.
      The bclass is the value entered in the columns bclass.
      It is taken in consideration the first account or group specified. If for example you query two accounts, the first has bclass 2 and the second has bclass 1. The bclass would be 2.
      The bclass is assigned by following this steps. :
      • The bclass of the specified account or group.
      • The blcass of the partent group, for the same section.
      • The blcass of the section.
    • startDate period's start date
    • endDate period's end date
  • Account
    • can be an account id, a cost center or a segment.
    • can be a combination of account and segments, separeted by the semicolon ":"
      In this case it returns all the transactions that have the indicated account and segments
      • 1000:A1:B1
    • can be different accounts and multiple segments separated by the "|"
      In this case it includes all transactions that have one of the specified accounts and one of the specified segments
      • 1000|1001
      • 1000|1001:A1:B1
      • 1000|1001:A1|A2:B1
    • can be a wildCardMatching
      Wildcards can be used for accounts, segments, Groups or BClass and in combination
      • ?  Matches any single character.
      • *  Matches zero or more of any characters
      • [...] Set of charachtes
      • "100?" match "1001, 1002, 1003, 100A, ...)
      • "100*" Matches all accounts starting with 100
      • "100*|200*:A?" Matches all accounts starting with 100 or 200 and with segments with A and of two charachters.
      • "[1234]000" Matches "1000 2000 3000 4000"
    • Can be a group or a BClass.
      It includes all the transactions where the account used to belong to a specified Group or BClass.
      It is also possible to use wildcards.
      The program first create a list of accounts and then use the account list.
      Do non mix mix groups relative to normal accounts, with groups relative to cost center or segments. Calculation could provide unexpected results.
      • BClass (for the double entry accounting only)
        • BClass=1
        • BClass=1|2
      • Gr for groups that are in Accounts table.
        • Gr=100
        • Gr=10*
        • Gr=100|101|102
      • GrC for group that are in the Category table of the income and expenses accounting type.
        • GrC=300
        • GrC=300|301
    • Can be Contra Accounts or other fields selection
      Transactions are included only if they have also a value corresponding
      After the "&&" you can insert a field name of the table journal.
      • 1000&&JContraAccount=2000 return all transctions of the account 1000 that have a contra account 2000.
        As per accounts you can specify multiple contra accounts, BClass=, Gr= with also wildcards.
      • 1000&&JCC1=P1|P2 will use only transactions on account 1000 and that also have the CC1=.P1 or .P2
    • Do not mix accounts or groups with cost centers ("1020|,RF2" or ",RF2|10"). It only returns the cost center amount.
  • Frequency
    • Specifiy the frequency to be returned, is one of the following charachters
      • D for daily
      • W for weekly
      • M for montly
      • Q for quarterly
      • S for semeterly
      • Y for yearly
  • StartDate
    • is a string in form 'YYYY-MM-DD' or a date object.
    • If startDate is empty the accounting start date is taken.
  • End date:
    • is a string in form 'YYYY-MM-DD' or a date object.
    • If endDate is empty the accounting end date is taken.
  • function(rowObj, rowNr, table)
    This fuction will be called for each row of the selected account.
    The function should return true if you want this row to be included in the calculation.


function exec( string) {
    // We retrive the montly total sales (account 4000) only for the cost center P1
    var balanceData = Banana.document.currentBalances('4000', 'M', '', '', onlyCostCenter);
    // sales is a revenue so is negative and we invert the value
    var salesCC1 = -balanceData[0].total;
    // display the information
    Banana.Ui.showText("Sales of Project P1: " + salesCC1);
}

// this function return true only if the row has the cost center code  "P1"
function onlyCostCenter( row, rowNr, table){
   if(row.value('JCC1') === 'P1') {
      return true;
   }
   return false;
}

Examples



Banana.document.currentBalances("1000", 'M')
// Montly values for account 1000 and for the accounting start and end period
// See also the examples for the function currentBalance

 currentCard(account [, startDate, endDate, function(rowObj, rowNr, table)])

Return for the given account and period a Table object with the transactions for this account.

Row are sorted by JDate

parameters:

  • account can be any accounts, cost center or segment as specifiend in currentBalance.
  • startDate any date or symbol as specifiend in currentBalance.
  • endDate any date or symbol as specifiend in currentBalance.

Return columns the same as for the Journal() function.



var transactions = Banana.document.currentCard('1000','2015-01-01','2015-12-31');

 currentInterest( account, interestRate, [startDate, endDate, , function(rowObj, rowNr, table)])

Returns the calculated interest on the specified account.
Interest is calculated on the effective number of days for 365 days in the years.

  • account is the account or group (same as in the function currentBalance)
  • interestRate. In percentage "5", "3.25". Decimal separator must be a "."
    • If positive it calculates the interest on the debit amounts.
    • If negative it calculates the interest on the credit amounts.
  • startDate, endDate, function see the currentBalance description.
    If no parameters are specified it calculate the interest for the whole year.


// calculate the interest debit for the whole period
var interestDebit = Banana.document.currentInterest('1000','5.75');

// calculate the interest credit for the whole period
var interestDebit = Banana.document.currentInterest('1000','-4.75');

Budget Functions

These functions are similar to the "current" functions, but they work on the budget data. They consider:

  • The opening amount (table Accounts and Categories)
  • Transactions entered in the Budget table.

For detailed information check the documentation on the equivalent "current" functions.

When using the API in the column Formula of the Table Budget a special budget API is available that allows you to use predefined periods instead of dates, like:

  • "MC" current month
  • "QC" current trimester
  • "MP" previous month
  • "QP" previous quarter

In the formula "budgetBalance('1000', 'MP'); the program will calculate automatically the start and end date of the month, based on the Date of the budget transaction.  

budgetBalance(account [, startDate, endDate, function(rowObj, rowNr, table)])

Sums the amounts of opening, debit, credit, total and balance for all budget transactions for this accounts .



var budget = Banana.document.budgetBalance('1000');

It works the same as the function currentBalance, but for the budgeting data.

budgetBalances(account, frequency [, startDate, endDate, function(rowObj, rowNr, table)])

Time series function. Sums the amounts of opening, debit, credit, total and balance for all budget transactions for this account and returns the values according to the indicated frequency indicated.



var budgets = Banana.document.budgetBalances('1000', 'M');

It works the same as the function currentBalances, but for the budgeting data.

budgetCard(account [, startDate, endDate, function(rowObj, rowNr, table)])

Returns, for the given account and period, a Table object with the budget account card.



var card = Banana.document.budgetCard('1000');

It works the same as the function currentCard, but for the budgeting data.

budgetExchangeDifference( account, [date, exchangeRate])

Returns the unrealized exchange rate Profit or Loss o the account at the specified date. 

  • account must be a valid account number not in base currency
  • date
    • a date that is used to calculate the balance
    • if empty calculate up to the end of the period
  • exchangeRate
    • if empty use the historic exchange rate for the specified date or the current if not a valid exchange rate for the date are found.
    • if "current" use the current exchange
    • if number for example "1.95" use the specified exchange rate.
  • Return value
    • Positive number (debit) are exchange rate Loss.
    • Negative number (credit) are exchange rate Profit.
    • empty if no difference or if the account has not been found or not a multicurrency accounting file.


// unrealized exchange rate profit or loss for the account 1000
// last balance and current exchange rate
var exchangeRateDifference = Banana.document.budgetExchangeRateDifference('1000');

// at the end of Semptember and hystoric exchange rate
var exchangeRateDifference = Banana.document.budgetExchangeRateDifference('1000', "2017-09-31");

// at the end of Semptember and current exchange rate
var exchangeRateDifference = Banana.document.budgetExchangeRateDifference('1000', "2017-09-31", "current");

// at the end of Semptember and specified exchange rate
var exchangeRateDifference = Banana.document.budgetExchangeRateDifference('1000', "2017-09-31", "1.65");

budgetInterest( account, interestRate, [startDate, endDate, function(rowObj, rowNr, table)])

Return the calculated interest for the budget transactions. 

It works the same as the function currentInterest, but for the budgeting data.



// calculate the interest debit for the whole period
var interestDebit = Banana.document.budgetInterest('1000','5.75');

// calculate the interest credit for the whole period
var interestDebit = Banana.document.budgetInterest('1000','-4.75');

Projections functions

This function is a mix of actual and budget data. It has a parameter projectionStartDate that defines up to when to use actual data and budget data.

The value of a projection is calculated as follows:

  • It uses the actual data up to the day before the projectionStartDate.
  • From the projectionStartDate it uses the budgeting data.

Assume you have prepared the budget for the year and you have entered accounting data up to the end of March (2015-03-31).
With the projectionBalance function you can have the projected balance up to the end of year, comprised from the actual data up to end of March and the budgeting data starting form 1. April.
In this case the projectionStartDate should be "2015-04-01".

projectionBalance(account, projectionStartDate [, startDate, endDate, function(rowObj, rowNr, table) ])

Same as currentBalance but use the budget data starting from the projectionStartDate.

This function calculates a projection of the end of year result (or specified period) combining the current data and the budget data for the period not yet booked.

If projectionStartDate is empty the result will be the same as currentBalance.

If you have already booked the 1. semester and would like to have a projection up to the end of the year



// We have booked the 1. semester and would like to have
// a projection up to the end of the yer
var cashProjection = Banana.document.projectionBalance('1000','2015-07-01');
var cashEnd = projection.balance;
var salesProjection = Banana.document.projectionBalance('3000','2015-07-01').total;
var salesForYear = -salesProjection.total;

projectionBalances(account, projectionStartDate, frequency [, startDate, endDate, function(rowObj, rowNr, table) ])

Same as currentBalances but use the budget data starting from the projectionStartDate.

projectionCard(account, projectionStartDate [, startDate, endDate, function(rowObj, rowNr, table) ])

Same as currentCard but use the budget data starting from the projectionStartDate.

If projectionStart date is empty result will be the same s currentCard.



var transactions = Banana.document.projectionCard('1000','2015-01-01','','');

 

Descriptions and Reporting functions

accountDescription(account [,column])

Return the Description of the specified account.

  • Account can be an account or a Group (Gr=)
  • Column can be an alternative column name to retrieve.


var descriptionAccount = Banana.document.accountDescription('1000');
var descriptionGroup = Banana.document.accountDescription('Gr=10');
var gr = Banana.document.accountDescription('1000','Gr');

accountsReport([startDate, endDate])

Returns the account report for the specified period. Start and end date can be a string in form 'YYYY-MM-DD' or a date object.



var report = Banana.document.accountsReport();
var report = Banana.document.accountsReport('2017-01-01', '2017-03-31');

Journal

This function retrieves an array of transactions, with one line per account. The Journal is the basic data structure for all accounting-related calculations, like account cards, balance sheet, VAT report. 

See an Example extension for journal reporting.

Journal Structure

The software, generate the Journal from the data that the user enter in the Accounts, Categories, Transactions and Budget Table. 

  • For each movement affecting an account a row in the Journal is created.
  •  
  • The Journal contains separate line for Current data (Transactions) and for Budget Data.  (Each Journal line specifies the data source origin; it can be Current or Budget.
    If both transaction and budget data exist, the Journal includes separate lines for Current and Budget transactions for each account.

The Journal i composed by this elements:

  • Opening amounts.
    A line is generated for each account with an opening balance.
    • OriginType is ORIGINTYPE_CURRENT.
    • AccountType is set accortding to the account.
  • Double-entry transactions or income and expense accounts.
    • OriginType is ORIGINTYPE_CURRENT.
    • Transactions with Debit and Credit accounts.
      The Journal will generate two lines.
      • One for the Debit account, with the corresponding amount.
      • One for the Credit account, with the corresponding amount.
    • Transactions with Debit and Credit accounts plus VAT.
      The Journal will generate three lines:
      • One for the Debit account, with the corresponding amount.
      • One for the Credit account, with the corresponding amount.
      • One for the VAT account, with the corresponding amount.
      • AccountType is ACCOUNTTYPE_NORMAL.
    • Transactions with cost centers.
      • For each cost center used (CC1, CC2, CC3), a separate Journal line is created with the cost center account and its corresponding amount.
      • AccountType is ACCOUNTTYPE_CC1,ACCOUNTTYPE_CC2,ACCOUNTTYPE_CC3.
    • The amount is the effective amount registered on the account.
      • Exclusive or inclusive of VAT, depending on the operation.
      • Positive amounts indicate debits, while negative amounts indicate credits.
      • In case of an error, the amount is set to zero.
    • Segments are stored in dedicated columns (Segment1, Segment2, … Segment10).
  • Budget Table Transactions
    • The software generate, in a similar way as for Transactions, also lines for the Budget data (Budget Table)
    • The generated line include has the Origin Type ORIGINTYPE_BUDGET.

 journal([originType = ORIGINTYPE_NONE, int accountType = ACCOUNTTYPE_NONE])

This function returns a Table object containing all registered amounts for the specified parameters.

Parameters:

  • originType - Specifies which transaction rows to filter. Possible values:
    • ORIGINTYPE_NONE (default)
      No filter is applied; all rows are returned, including both current and budget transactions.
      For current transactions ORIGINTYPE_NONE = 1
      For budget transactoins ORIGINTYPE_NONE = 2
    • ORIGINTYPE_CURRENT
      Returns only current transactions; ORIGINTYPE_CURRENT = 1.
    • ORIGINTYPE_BUDGET
      Returns only budget transactions; ORIGINTYPE_BUDGET = 2.
  • accountType - Specifies which account rows to filter. Possible values:
    • ACCOUNTTYPE_NONE (default)
      No filter is applied; all account rows are returned.
    • ACCOUNTTYPE_NORMAL
      Returns only normal account rows.
    • ACCOUNTTYPE_CC1
      Returns only rows for Cost Center 1 (CC1).
    • ACCOUNTTYPE_CC2
      Returns only rows for Cost Center 2 (CC2).
    • ACCOUNTTYPE_CC3
      Returns only rows for Cost Center 3 (CC3).
    • ACCOUNTTYPE_CC
      Returns all Cost Center rows (CC1, CC2, CC3), equivalent to using ACCOUNTTYPE_CC1 | ACCOUNTTYPE_CC2 | ACCOUNTTYPE_CC3.
// Get current transactions for normal accounts (exclude budget transactions)
var journal = Banana.document.journal(Banana.document.ORIGINTYPE_CURRENT, Banana.document.ACCOUNTTYPE_NORMAL);

// Get budget transactions for normal accounts (exclude current transactions)
var journal = Banana.document.journal(Banana.document.ORIGINTYPE_BUDGET, Banana.document.ACCOUNTTYPE_NORMAL);

// Get current and budget transactions for normal accounts
var journal = Banana.document.journal(Banana.document.ORIGINTYPE_NONE, Banana.document.ACCOUNTTYPE_NORMAL);

// Get current and budget transactions for all accounts
var journal = Banana.document.journal(Banana.document.ORIGINTYPE_NONE, Banana.document.ACCOUNTTYPE_NONE);

Returned Table Structure:

The returned table contains all the columns of the Transactions table, plus the following additional columns:

  • JOriginType - Defines the transaction's origin type:
    • ORIGINTYPE_CURRENT
      Value is 1 (Current transactions).
    • ORIGINTYPE_BUDGET
      Value is 2 (Budget transactions).
  • JOriginFile - The file name where the transaction originates.
  • JTableOrigin - The source table.
  • JRowOrigin - The row number of the table where the transaction is located (rows start from 0).
  • JRepeatNumber - The progressive repetition number for budget transactions.
  • JOperationType - Indicates the type of transaction:
    • OPERATIONTYPE_NONE
      Value is 0.
      Transaction not used for calculation.
    • OPERATIONTYPE_OPENING
      Value is 1.
      Transaction used for opening balance calculation; the row is generated from:
      • The Opening balance column in the Accounts table.
      • Transactions with the DocType column with value '01'.
    • OPERATIONTYPE_CARRYFORWARD
      Value is 2.
      OperationType used only in account cards.
      It is the opening balance or the balance of the account prior to the begin of the period of the account card.
      If the account card is for the month of september, the carryforward amount would be the account balance prior to any transactions of september.
    • OPERATIONTYPE_TRANSACTION
      Value is 3.
      The row is a normal transaction and is generated from:
      • Transactions table if JOriginType = ORIGINTYPE_CURRENT.
      • Budget table if JOriginType = ORIGINTYPE_BUDGET.
    • OPERATIONTYPE_INVOICESETTLEMENT
      Value is 21.
      These are rows that are genereted when creating Customer or Suppliers cards.
      They are used to settle invoices, payed.
  • JDate - The transaction date.
  • JDescription - The transaction description.
  • JAccount - The account for this transaction. One row per account (AccountDebit, AccountCredit, AccountVat, CC1, CC2, CC3). Segments are not included.
  • JAccountDescription - The account description.
  • JAccountClass - The BClass number of the account.
  • JAccountGr - The Group (Gr) of the account.
  • JAccountGrDescription - The Group description of the account.
  • JAccountGrPath - The complete Group hierarchy path. It includes all the Gr tree.
  • JAccountCurrency - The currency of the account.
  • JAccountType - The account type as defined above (ACCOUNTTYPE_NORMAL, ACCOUNTTYPE_CC1, …).
  • JAmount - The exact amount in basic currency (positive = debit, negative = credit).
  • JAmountAccountCurrency - The amount in account currency (positive = debit, negative = credit).
  • JTransactionCurrency - The currency of the transaction.
  • JAmountTransactionCurrency - The amount in transaction currency. For account with currency not in transactions currency the exchange rate of the transaction is used.
  • JTransactionCurrencyConversionRate - The conversion rate to transaction currency.
    • Multiply the transaction amount in basic currency by this rate to get the transaction currency amount.
    • This rate has 12 significant figures to minimize conversion differences; only in the case of very large conversions can there be conversion differences.
  • JVatIsVatOperation - 'true' if this row has a VAT code.
  • JVatCodeWithoutSign - The VAT code, excluding a preceding "-" (e.g., "-V10" becomes "V10"). Useful for grouping transactions by the same VatCode.
  • JVatCodeDescription - Description of the VAT code.
  • JVatCodeWithMinus - 'true' if the VAT code has a "-" prefix.
  • JVatCodeNegative - 'true' if the VAT amount is negative (deductible VAT).
  • JVatTaxable - The VatTaxable amount, following the sign of JVatCodeNegative.
  • VatTwinAccount - The account where the net amount (excluding VAT) is registered.
    • Example: If the gross amount is CHF 1100 (100 VAT + 1000 net), VatTwinAccount is the account where CHF 1000 is registered.
    • The sign of VatTwinAccount follows the VatAccount:
      • If VAT is registered in debit, VatTwinAccount = AccountDebit.
      • If VAT is registered in credit, VatTwinAccount = AccountCredit.
  • JContraAccount - The contra account (based on the other accounts and the sequence in the Transactions table).
  • JContraAccountType - Specifies the contra account type:
    • CONTRAACCOUNTTYPE_NONE
      No contra account.
    • CONTRAACCOUNTTYPE_DIRECT
      When debit and credit accounts exist on the same row.
    • CONTRAACCOUNTTYPE_MULTIPLEFIRST
      The first row of a transaction involving multiple accounts (first transaction after a row with debit and credit accounts or with a different date).
    • CONTRAACCOUNTTYPE_MULTIPLEFOLLOW
      A subsequent row following a CONTRAACCOUNTTYPE_MULTIPLEFIRST, with the same date.
    • CONTRAACCOUNTTYPE_VAT
      VAT Account row.
  • JContraAccountGroup – The row number corresponding to CONTRAACCOUNTTYPE_MULTIPLEFIRST.
  • JCC1 - Cost Center 1 (without preceding sign).
  • JCC2 - Cost Center 2 (without preceding sign).
  • JCC3 - Cost Center 3 (without preceding sign).
  • JSegment1 ... JSegment10 - Segments related to the account.
  • JDebitAmount - Debit amount in basic currency.
  • JCreditAmount - Credit amount in basic currency.
  • JDebitAmountAccountCurrency - Debit amount in account currency.
  • JCreditAmountAccountCurrency - Credit amount in account currency.
  • JBalance - Balance (for account cards) in basic currency.
  • JBalanceAccountCurrency - Balance (for account cards) in account currency.

Examples:

// Get the Journal table of all transactions for normal accounts
var journal = Banana.document.journal(Banana.document.ORIGINTYPE_CURRENT, Banana.document.ACCOUNTTYPE_NORMAL);

//Read Journal table row by row
for (var i = 0; i < journal.rowCount; i++) {
	var tRow = journal.row(i);
	
	//Check if the type of transaction is a normal transaction generated from the Transactions or Budget table
	if (tRow.value('JOperationType') == Banana.document.OPERATIONTYPE_TRANSACTION) {
		var jDate = tRow.value('JDate'); // the transaction date
		var jDescription = tRow.value('JDescription'); // the transaction description
		var jAccount = tRow.value('JAccount'); // the transaction account, one row per account
		var jContraAccount = tRow.value('JContraAccount'); // the transaction contra account
		var jAmount = tRow.value('JAmount'); // the transaction amount
		//...
	}
}

journalCustomersSuppliers([originType = ORIGINTYPE_NONE, int accountType = ACCOUNTTYPE_NONE])

Same as journal with additional settlements rows for closing invoices and additional columns:

  • JInvoiceDocType: specifies the type of document (see column DocType)
  • JInvoiceAccountId: customer account id from table accounts
  • JInvoiceCurrency: the currency of the invoice, same as customer account currency from table accounts
  • JInvoiceStatus: paidInvoice (the invoice was offset with the payment that refers to the same document), paidOpening (the invoice was offset with the opening balance of the customer account)
  • JInvoiceDueDate: invoice expiration date
  • JInvoiceDaysPastDue
  • JInvoiceLastReminder
  • JInvoiceLastReminderDate
  • JInvoiceIssueDate
  • JInvoiceExpectedDate
  • JInvoicePaymentDate
  • JInvoiceDuePeriod
  • JInvoiceRowCustomer (1=Customer, 2=Supplier)

 invoicesCustomers()

Returns a table with the customers' invoices from the transaction table. A customer group must be defined and invoices must be numbered using the column DocInvoice.

See:



// Print the content of the table invoicesCustomers 
	var invoicesCustomers = Banana.document.invoicesCustomers();
	if (invoicesCustomers) {
		for (var i = 0; i < invoicesCustomers.rowCount; i++) {
			var tRow = invoicesCustomers.row(i);
			var jsonString = tRow.toJSON();
			if (jsonString.length > 0) {
				var jsonRow = JSON.parse(jsonString);
				for (var key in jsonRow) {
					if (jsonRow[key])
						Banana.console.debug(key + ": " + jsonRow[key].toString());
				}
			}
		}
	}

invoicesSuppliers()

Returns a table with the suppliers' invoices from the transaction table. A supplier group must be defined and invoices must be numbered using the column DocInvoice.

See:


// Print the content of the table invoicesSuppliers
var invoicesSuppliers = Banana.document.invoicesSuppliers();
if (invoicesSuppliers ) {
  for (var i = 0; i < invoicesSuppliers.rowCount; i++) {
   var tRow = invoicesSuppliers.row(i);
   var jsonString = tRow.toJSON();
   if (jsonString.length > 0) {
    var jsonRow = JSON.parse(jsonString);
    for (key in jsonRow) {
     if (jsonRow[key])
      Banana.console.debug(key + ": " + jsonRow[key].toString());
    }
   }
  }
}

 Available columns in invoicesCustomers and invoicesSuppliers table

  • CounterpartyId Customer or supplier accountId
  • Invoice Invoice number
  • ObjectType Type of object in field ObjectJsonData (values are: Counterparty, InvoiceDocument, InvoiceLineItem, InvoiceTotal, Transaction)
  • ObjectIndex Internal index used to print the invoice documents
  • ObjectJSonData Contains a json object. Available object types: Counterparty, InvoiceDocument, InvoiceLineItem, InvoiceTotal, Transaction (Example of row with a counterparty object): 

    {"Counterparty":{"customer_info":
    {"balance":"4176000.00","balance_base_currency":"4176000.00","business_name":"Banana.ch","first_name":"Domenico",
    "last_name":"Zucchetti","number":"411001","origin_row":"950","origin_table":"Accounts"}}}
  • Date Invoice document date
  • TransactionDate Original Transaction date
  • Description Original Transaction description
  • Debit Object amount in debit
  • Credit   Object amount in credit
  • Balance Incremental balance
  • Currency Object currency
  • InvoiceExpectedDate    
  • InvoiceDueDate    
  • InvoiceDuePeriod    
  • InvoiceDaysPastDue    
  • InvoicePaymentDate    
  • InvoiceLastReminder    
  • InvoiceLastReminderDate    
  • Status   
  • JTableOrigin    
  • JRowOrigin

 

Exchange rate functions

 exchangeRate( currency, [date])

Returns the exchange rate that converts the amount in currency in basic currency as object with the properties 'date' and 'exchangeRate'. Returns null if no exchange rate is found.

The exchange rate is retrieved from the Currency table, already considering the multiplier.

  • If no date is specified the exchange rate without date is used.
  • If a date is specified it retrieves the exchange rate with the date minor or equal the specified date.

Vat functions

vatBudgetBalance(vatCode[, startDate, endDate, function(rowObj, rowNr, table) ])

Sum the vat amounts for the specified vat code and period, using the Budget data.



var vatTotal = Banana.document.vatBudgetBalance('V15');

vatBudgetBalances(vatCode, frequency, [, startDate, endDate, function(rowObj, rowNr, table) ])

Sum the vat amounts for the specified vat code and period, using the Budget data and returns the values according to the indicated frequency indicated.



var vatTotal = Banana.document.vatBudgetBalances('V15', 'Q');

vatCurrentCard(vatCode[, startDate, endDate, function(rowObj, rowNr, table) ])

Retrieve the transactions relative to the specified VatCode.



var vatTransactions = Banana.document.vatCurrentCard('V15');

vatCurrentBalance(vatCode[, startDate, endDate, function(rowObj, rowNr, table) ])

Sum the vat amounts for the specified vat code and period.
For more info see :

Example: 



var currentVat = Banana.document.vatCurrentBalance('V15','','');
var vatTaxable = currentVat.vatTaxable;
var vatPosted = currentVat.vatPosted;
  • Return value:
    Is an object that has
    • vatTaxable the amount of the taxable column
      (the sign is the same as the vatAmount)
    • vatAmount the amount of vat
    • vatNotDeductible the amount not deductible
    • vatPosted VatAmount - VatNotDeductible
    • rowCount the number of lines that have been found and used for this computation
  • VatCode
    One or more VatCode defined in the tabel Vat Codes.
    Multiple vat code can be separated by "|" for example "V10|V20", or you can use vildcard "V*".

vatCurrentBalances(vatCode, frequency [, startDate, endDate, function(rowObj, rowNr, table) ])

Sum the vat amounts for the specified vat code and period and returns the values according to the indicated frequency indicated.
For more info see :

Example: 



var currentVat = Banana.document.vatCurrentBalances('V15', 'Q');
var vatTaxable = currentVat[0].vatTaxable;
var vatPosted = currentVat[0].vatPosted;
  • Return value:
    Is an object that has
    • vatTaxable the amount of the taxable column
      (the sign is the same as the vatAmount)
    • vatAmount the amount of vat
    • vatNotDeductible the amount not deductible
    • vatPosted VatAmount - VatNotDeductible
    • rowCount the number of lines that have bben found and used for this computation
  • VatCode
    One or more VatCode defined in the tabel Vat Codes.
    Multiple vat code can be separated by "|" for example "V10|V20", or you can use vildcard "V*".
  • Frequency
    • Specifiy the frequency to be returned, is one of the following charachters
      • D for daily
      • W for weekly
      • M for montly
      • Q for quarterly
      • S for semeterly
      • Y for yearly

vatProjectionBalance(vatCode, projectionStartDate, [, startDate, endDate, function(rowObj, rowNr, table) ])

Same as vatCurrenBalance but use the budget data starting from the projectionStartDate.



var projectionVat = Banana.document.vatProjectionBalance('V15','','');
var vatTaxable = projectionVat.vatTaxable;
var vatPosted = projectionVat.vatPosted;

vatProjectionBalances(vatCode, projectionStartDate, frequency, [, startDate, endDate, function(rowObj, rowNr, table) ])

Same as vatCurrenBalances but use the budget data starting from the projectionStartDate.



var projectionVat = Banana.document.vatProjectionBalances('V15', '2017-03-01', 'Q');
var vatTaxable = projectionVat[0].vatTaxable;
var vatPosted = projectionVat[0].vatPosted;

vatProjectiontCard(vatCode, projectionStartDate, [, startDate, endDate, function(rowObj, rowNr, table) ])

Same as vatCurrentCard but use the budget data starting from the projectionStartDate.



var vatTransactions = Banana.document.vatProjectiontCard('V15','2015-01-01','','');

vatReport([startDate, endDate])

Returns the vat report for the specified period.

Start and end dates are strings in form 'YYYY-MM-DD' or a date object. If startDate is empty the accounting start date is taken. If endDate is empty the accounting end date is taken.



var vatReport = Banana.document.vatReport('','');

 

 

Banana.Document (Base)

Banana.Document is the interface to a document in Banana Accounting. The currently opened document can be accessed through the property Banana.document. A document can be also opened with the method Banana.application.openDocument.

Properties

cursor

Return a Cursor object with the current position of the cursor and the range of the selected rows.


var currentCursor = Banana.document.cursor;

locale

Return the locale of the document in the form of "language_country", where language is a lowercase, two-letter ISO 639 language code, and country is an uppercase, two- or three-letter ISO 3166 country code.


var locale = Banana.document.locale;

rounding

Return the rounding context of the current file that can be used with the SDecimal math functions.


var rounding = Banana.document.rounding;

tableNames

Return an array with the xml names of the tables in the document.


var tableNames = Banana.document.tableNames;

The tables in the document vary depending on the type of accounting. For example in a multi-currency accounting with VAT these are the tables:

  • Accounts,Transactions,Budget,Totals,VatCodes,ExchangeRates,Items,Documents,FileInfo

uuid

Return the uuid (universally unique identifier) fo the document.


var uuid = Banana.document.uuid; // Ex.: "123e4567-e89b-12d3-a456-426652340000"

 

Methods

addMessage(msg[, idMsg])

Add the message msg to the document. The message is showed in the pane "Messages", and in a dialog if the application option "Show Messages" is turned on.
If idMsg is not empty, the help button calls an url with script's id and message's id (idMsg) as parameters.

See also: Application.AddMessage, Table.AddMessage, Row.AddMessage.


Banana.document.addMessage("Message text");

applyDocumentChange(docChange)

Apply a DocumentChange to the document. Returns true if the docChange has been applied, otherwise false.

A dialog showing the changes is showed to the user asking for confirmation.


var documentChange = {
   "format": "documentChange", 
   //...
};
Banana.document.applyDocumentChange(documentChange);

clearMessages()

Clear all the document's messages showed in the pane "Messages".


Banana.document.clearMessages();

getMessages([tableName, rowNr])

Returns all messages showed in the pane "Messages", that refer to this document and optionally to given table and row number.

let msgs = Banana.application.getMessages();
for (let i = 0; i < msgs.length; ++i) {
   let msg = msgs[i];
   Banana.console.log("Error: " + msg.message);
}

The message object contains following properties:

  • message: the message in the application language;
  • referer:  a string describing to which the message refer (usually the file name);
  • level: the level of the message as string, can be one of "debug", "info", "warning", "debug";
  • helpId: the help id of the message, used to link to the documentation;
  • fileUuid: an id as string that uniquely identifies the file to which the message refer or empty;
  • fileName: the file name that identifies the file to which the message refer or empty;
  • tableName: the table name to which the message refer, or empty;
  • rowNr: the row number as number to which the message refer, or -1;
  • columnName: the column name to  which the message refer to, or empty;

See also: Application.getMessages.

getScriptSettings()

Get the settings of the script saved in the document. You use this method to get settings that are private to the running script. It is possible to save the settings of the script through the method "setScriptSettings". 

With this method Settings are saved and restored under the script id, If you change the script's id you will lose the saved settings.

Example:


// Initialise parameter
param = {
   "searchText": "",
   "matchCase": "false",
   "wholeText": "false"
};

// Readscript settings
var strData = Banana.document.getScriptSettings();
if (strData.length > 0) {
   var objData = JSON.parse(strData);
   if (objData)
      param = objData;
}

getScriptSettings(id)

Return the settings saved in the document under the id 'id'.

You use this method to get settings that are shared between scripts. As id we recommend to use a substring of the script's id. For example if you have the scripts 'ch.banana.vat.montlyreport' and 'ch.banana.vat.endofyearreport', then you can use as id 'ch.banana.vat'.

Example:


// Initialise parameter
param = {
   "searchText": "",
   "matchCase": "false",
   "wholeText": "false"
};

// Readscript settings
var strData = Banana.document.getScriptSettings('ch.banana.vat');
if (strData.length > 0) {
   var objData = JSON.parse(strData);
   if (objData)
      param = objData;
}

info(section, id)

Return the info value of the document referenced by section and id. Section and Id correspond to the xml name listed in the Info table, see command File info in menu "Tools" and set the view to complete to see the XML columns. If the value referenced by section and id doesn't exist, an object of type undefined is returned.

Example:

This is not an exhaustive list. For an exhaustive list run the command Menu Tools > File info, and switch to the view Complete. 


// Get some value of the accounting file 
var FileName = Banana.document.info("Base","FileName");
var DecimalsAmounts = Banana.document.info("Base","DecimalsAmounts");
var HeaderLeft = Banana.document.info("Base","HeaderLeft");
var HeaderRight = Banana.document.info("Base","HeaderRight");
var BasicCurrency = Banana.document.info("AccountingDataBase","BasicCurrency");

// For openingDate and closureDate use instead startDate and endDate
var openingDate = Banana.document.info("AccountingDataBase","OpeningDate");
var closureDate = Banana.document.info("AccountingDataBase","ClosureDate");

// For file accounting type
var FileType = Banana.document.info("Base","FileType");
var FileGroup = Banana.document.info("Base","FileTypeGroup");
var FileNumber = Banana.document.info("Base","FileTypeNumber");

// For customer settings
var customersGroup = Banana.document.info("AccountingDataBase","CustomersGroup");
var suppliersGroup = Banana.document.info("AccountingDataBase","SuppliersGroup");

FileTypeGroup / FileTypeNumber combinations:

  • 100 Double entry accounting
    • 100 No VAT
    • 110 With VAT
    • 120 Multi Currency
    • 130 Multi Currency with VAT
  • 110 Income and Expense accounting
    • 100 No VAT
    • 110 With VAT
  • 130 Cash Book
    • 100 No VAT
    • 110 With VAT
  • 400 Address / Labels
    • 110 Labels
    • 120 Address

scriptSaveSettings(string)

Save the settings of the script in the document. The next time the script is run, it is possible to read the saved settings with "scriptReadSettings".

With this method Settings are saved and restored under the script id, If you change the script's id you will lose the saved settings.

Example:


// Save script settings
var paramString = JSON.stringify(param);
var value = Banana.document.scriptSaveSettings(paramString);

Deprecated. Use setScriptSettings instead.

scriptReadSettings()

Return the saved settings of the script.

With this method Settings are saved and restored under the script id, If you change the script's id you will lose the saved settings.

Example:


// Initialise parameter
param = {
   "searchText": "",
   "matchCase": "false",
   "wholeText": "false"
};

// Readscript settings
var strData = Banana.document.scriptReadSettings();
if (strData.length > 0) {
   var objData = JSON.parse(strData);
   if (objData)
      param = objData;
}

Deprecated. Use getScriptSettings instead.

setScriptSettings(value)

Save the settings of the script in the document. It is possible to read the saved settings of the script with the method "getScriptSettings". 

With this method Settings are saved and restored under the script id, If you change the script's id you will lose the saved settings.

Example:


// Save script settings
var paramString = JSON.stringify(param);
var value = Banana.document.setScriptSettings(paramString);

setScriptSettings(id, value)

Save the settings in the document under the id 'id'. It is possible to read the saved settings with "getScriptSettings(id)".

You use this method to set settings that are shared between scripts. As id we recommend to use a substring of the script's id. For example if you have the scripts 'ch.banana.vat.montlyreport' and 'ch.banana.vat.endofyearreport', then you can use as id 'ch.banana.vat'.

Example:


// Save script settings
var paramString = JSON.stringify(param);
var value = Banana.document.setScriptSettings('ch.banana.vat', paramString);

table(xmlTableName)

Return the table referenced by the name xmlTableName as a Table object, or undefined if it doesn't exist.


Banana.document.table("Accounts");

table(xmlTableName, xmlListName)

Return the table referenced by the name xmlTableName with the rows of the list xmlListName as a Table object, or undefined if the table or the list don't exist. The default list is the 'Data' list.


Banana.document.table("Transactions", "Examples");
Banana.document.table("Transactions").list("Examples");  // alternative way

See also: Table.list, Table.listNames.

value(tableName, rowNr, columnName)

Return the value in table tableName, row rowNr and column columnName as string. If the table, row or column are not found, it returns an object of type undefined.


Banana.document.value("Accounts", 5, "Description")

 

Banana.Document (Invoice)

This API is available only for Estimates & Invoices Application.

calculateInvoice(string) 

It receives the Invoice JSON Object as a parameter and completes the fields by calculating their values, returning a string containing the complete structure of a Invoice. 


var invoiceObj = (Invoice JSON Object)
invoiceObj  = JSON.parse(Banana.document.calculateInvoice(JSON.stringify(invoiceObj)));

For example, it is possible to use this function together with the DocumentChange API to import invoices into the accounting.

printInvoice(string) 



// Before printing you can adapt the content through templates
var invoiceObj = (Invoice JSON Object)
// Updates Document title
invoiceObj.document_info.title = invoiceObj.document_info.description;

Banana.document.printInvoice(JSON.stringify(invoiceObj));

Banana.Document.Column

The Banana.Document.Column class provide informations about a column.

The column's informations are described on the documentation page of dialog Columns setup, The column's informations are dependent of the view, therefore the same column can have a different headers depending on the view.

Example:

var tColumn = Banana.document.table("Transactions").column("Description", "Base");
var colHeader = tColumn.header;

This class was introduced in BananaPlus 10.1.7.23164.

Properties

alignment

Returns the column's alignment as string.

The returned string is one of:

  • left
  • center
  • right
var tColumn = Banana.document.table("Transactions").column("Description", "Base");
var alignment = tColumn.alignment;

dataType

Returns the column's data type as string.

The returned string is one of:

  • text
  • number
  • amount
  • date
  • time
  • bool
  • timestamp
  • timecounter
  • links
  • textmultiline
  • xml
  • html
  • json
  • mime
  • markdowm
  • textencrypted
  • none
var tColumn = Banana.document.table("Transactions").column("Description", "Base");
var dataType = tColumn.dataType;

decimal

Return the number of decimals for columns of type 'amount' of 'number'.

var tColumn = Banana.document.table("Transactions").column("Description", "Base");
var decimals = tColumn.decimals;

description

Return the column's description.

var tColumn = Banana.document.table("Transactions").column("Description", "Base");
var description = tColumn.description;

excludeFromPrinting

Return true if the column is to be excluded from printing, false otherwise.

var tColumn = Banana.document.table("Transactions").column("Description", "Base");
var excludedFromPrinting = tColumn.excludedFromPrinting;

format

Return the column's format.

var tColumn = Banana.document.table("Transactions").column("Description", "Base");
var format = tColumn.format;

header

Return the column's header.

var tColumn = Banana.document.table("Transactions").column("Description", "Base");
var header = tColumn.header;

header2

Return the column's header 2.

var tColumn = Banana.document.table("Transactions").column("Description", "Base");
var header2 = tColumn.header2;

style

Return the column's format as object with the properties 'fontSize' as integer, 'bold' as boolean and 'italic' as boolean.

var tColumn = Banana.document.table("Transactions").column("Description", "Base");
var style = tColumn.style;
var fontSize = style.fontSize;
var isBold = style.bold;
var isItalic = style.italic;

visible

Return true if the column is visible, false otherwise.

var tColumn = Banana.document.table("Transactions").column("Description", "Base");
var visible = tColumn.visible;

editable

Return true if the column is editable, false otherwise.

var tColumn = Banana.document.table("Transactions").column("Description", "Base");
var editable= tColumn.editable;

This property was introduced in BananaPlus 10.1.20.

width

Return the column's width in millimeters.

var tColumn = Banana.document.table("Transactions").column("Description", "Base");
var width = tColumn.width;

Methods

No methods are defined for this class.

Banana.Document.Cursor

Banana.Document.Cursor is the interface to the cursor and can be accessed through Banana.document.cursor.

Properties

tableName

Return the xml name of the current table.



var currentTable = Banana.document.cursor.tableName;

rowNr

Return the number of the current row.



var currentRow = Banana.document.cursor.rowNr;

columnName

Return the xml name of the current column.



var currentColumn = Banana.document.cursor.columnName;

selectionTop

Return the index of the top row of the current selection.



var currentSelectionTop = Banana.document.cursor.selectionTop;

selectionBottom

Return the index of the bottom row of the current selection.



var currentSelectionBottom = Banana.document.cursor.selectionBottom;

Banana.Document.Row

Banana.Document.Row is the interface of a row.

Properties

isEmpty

Return true if the row is completly empty.


var isEmpty = tRow.isEmpty;

rowNr

Return the index of the row.


var rowNr = tRow.rowNr;

style

Return the column's format as object with the properties 'fontSize' as integer, 'bold' as boolean and 'italic' as boolean.

var tRow = Banana.document.table("Transactions").row(10);
var style = tRow.style;
var fontSize = style.fontSize;
var isBold = style.bold;
var isItalic = style.italic;

This method was introduced in BananaPlus 10.0.12.088.

 

uniqueId

Return the unique id (an interger value) of the row.
Banana assign to every new row a unique id, this value is fix a will never change.


var uniqueId = tRow.uniqueId;

 

Methods

When using columnName it must always be a valid nameXml of a column.

addMessage(msg [, columnName] [, idMsg])

Add the message msg to the document. The message is showed in the pane "Messages", and in a dialog if the application option "Show Messages" is turned on.

If idMsg is not empty, the help button calls an url with message's id (idMsg) as parameter.

If columnName is not empty, the message is connected to the column columnName. With a double click over message in the message pane, the cursor jump to the corresponding table, rowNr and columnName.

See also: Application.AddMessage, Table.AddMessageDocument.AddMessage.


var accountsTable = Banana.document.table("Accounts");        
var tRow = accountsTable.row(4);
tRow.addMessage("Message text");

toJSON([columnNames])

Return the row as JSON string. If the parameter columnNames is defined, only the columns in the array are included in the file.


// Return all the columns of the row
var json = tRow.toJSON();

// Return only the defined columns of the row
var json = tRow.toJSON(["Account", "Description", "Balance"]);

value(columnName)

Return a String  in the format corresponding to the column Data type.

  • If the column is not found or the object is invalid it return an undefined value.
  • See Table Content and Cell value for more information on the format of the returned String.  
  • If the column is numeric or amount type the return value is a Numeric String.
  • If the column is Date type the return value is a Date String.

var accountsTable = Banana.document.table("Accounts");        
var tRow = accountsTable.row(4);
var description= tRow.value("Description"); // example "Cash account"

Banana.Document.Table

Banana.Document.Table is the interface of a table.

When using table it must always be a valid nameXml of a table.
To view the nameXml of a table: menu Data > Table Setup.

var table = Banana.document.table("Accounts"); // 'Accounts' is the nameXml of the table Accounts

When using columnName it must always be a valid nameXml of a column.
To view the nameXml of a column: menu Data > Column Setup > Settings.

var table = Banana.document.table("Accounts");
var account = table.value(3,'Account'); // 'Account' is the nameXml of the column account of Accounts table

Table content 

A table is a read only data structure that contains 

Cell content and format

The cell content is a String text, returned by the function value is retrieved with the always in text format. 

  • String column 
    Contain a String with any alphanumeric value. 
    Examples: "", "text", "1234ab
  • Numeric and Amounts columns
    Contains a Numeric String. Javascript String containing only digit characters, including a decimal separator "." and minus sign at the beginning. 
    See Banana.SDecimal class.
    Examples: (positive number  "12345.67", negative number  "12345.67")
  • Date columns
    Contains a Date String with a date in the format "yyyy-mm-dd" 
    Example: "2025-12-31".
    See Banana.Converter class.
  • Time columns 
    Contains a String with a time in the format "hh:mm:ss:zzz" or without milliseconds "h:m:ss:zz" .
    Examples: ("04:04:36:089", "4:4:36:89");
    See Banana.Converter class.
  • Boolean columns, 
    Contains a String with values 1 (true) or empty (false).

Properties

name

Return the xml name of the table.


var table = Banana.document.table("Accounts");
var tName = table.name;

columnNames

Return the xml names of the table's columns as an array of strings.


var table = Banana.document.table("Accounts");
var tColumnNames = table.columnNames;

The columns vary depending on the table and accounting type. For example in the Transactions table of a multi-currency accounting with VAT these are the columns:

  • SysCod, Section, Date, DateDocument, DateValue, Doc, DocProtocol, DocType, DocOriginal, DocInvoice, InvoicePrinted, DocLink, ExternalReference, ItemsId, Description, Notes, AccountDebit, AccountDebitDes, AccountCredit, AccountCreditDes, Quantity, ReferenceUnit, UnitPrice, AmountCurrency, ExchangeCurrency, ExchangeRate, ExchangeMultiplier, Amount, Balance, VatCode, VatAmountType, VatExtraInfo, VatRate, VatRateEffective, VatTaxable, VatAmount, VatAccount, VatAccountDes, VatPercentNonDeductible, VatNonDeductible, VatPosted, VatNumber, Cc1, Cc1Des, Cc2, Cc2Des, Cc3, Cc3Des, Segment, DateExpiration, DateExpected, DatePayment, LockNumber, LockAmount, LockProgressive, LockLine

listName

Return the xml name of the list that this table object references to. The default list is the 'Data' list.


var table = Banana.document.table("Accounts");
var tListName = table.listName;

 listNames

Return the xml names of the available lists as an array. The default list is the 'Data' list.


var table = Banana.document.table("Accounts");
var tListNames = table.listNames;

rowCount

Return the number of rows in the table.


var table = Banana.document.table("Accounts");
var tRowCount = table.rowCount;

rows

Return the rows of the table as an array of Row objects.


var table = Banana.document.table("Accounts");
var tRows = table.rows;

Note: In a loop use the method table.row(rowNr) instead of table.rows[rowNr]. The property rows can be very expensive with large tables and slow down or block the execution of the script.

 viewNames

Return the xml names of the available views as an array.


var table = Banana.document.table("Accounts");
var tViewNames = table.viewNames;

This property was introduced in BananaPlus 10.0.12.088.

 

Methods

 addMessage(msg, rowNr [, columnName] [, idMsg])

Add the message msg to the queue of the document. The message is showed in the pane "Messages", and in a dialog if the application option "Show Messages" is turned on.

If idMsg is not empty, the help button calls an url with message's id (idMsg) as parameter.

If rowNr is different than "-1" the message is connected to the row rowNr. if columnName is not empty, the message is connected to the column columnName. With a double click over message in the message pane, the cursor jump to the corresponding table, rowNr and columnName.

See also: Application.AddMessageRow.AddMessage, Document.AddMessage.


var table = Banana.document.table("Accounts");
table.addMessage("Message string", 3, "description");

 column(columnName [, viewName])

Return the Column with the given name in the given view as Column Object.

The viewName is optional, if not defined the view number 1 (usually the "Base" view) or if not present the first view in the list is taken.

The column's informations are dependent of the view, therefore the same column can have for example different headers depending on the given view.


var tColumn = Banana.document.table("Transactions").column("Description", "Base");
var colHeader = tColumn.header;

This method was introduced in BananaPlus 10.0.12.088.

 

extractRows( function(rowObj, rowNr, table), tableTitle)

Return an array of rows filled with all row elements that pass a test (provided as a function) and show them in the table "Selections".
The title of the table is set to tableTitle.


function accountStartsWith201(rowObj,rowNr,table) {
   // Return true if account start with '201'
   return rowObj.value('Account').startsWith('201');
}
var tableAccount = Banana.document.table('Accounts');
// Show a table with all accounts that start with '201'
tableAccount.extractRows(accountStartsWith201, 'Accounts that start with 201');

findRows( function(rowObj, rowNr, table))

Return an array of Row objects that pass a test (provided as a function).


function accountStartsWith201(rowObj,rowNr,table) {
   // Return true if account start with '201'
   return rowObj.value('Account').startsWith('201');
}
var tableAccount = Banana.document.table('Accounts');
// Find rows of all accounts that start with '201'
var rows = tableAccount.findRows(accountStartsWith201);

findRowByValue(columnName, value)

Return the first row as Row object that contains the value in the the column columnName. Or undefined if any row is found.


var cashAccountRow = Banana.document.table('Accounts').findRowByValue('Account','1000');
if (!cashAccountRow)
   //Row not found

 list(xmlListName)

Return a new table object with the rows of the list xmlListName, or undefined if the list xmlListName doesn't exist.


var recurringTransactions = Banana.document.table('Transactions').list('Recurring');
var archivedProducts = Banana.document.table('Products').list('Archive');

 progressiveNumber(columnName [, includeArchive])

Return the progressive number for the column columnName. If includeArchive is true, the Archive table is also take into account.

As API Version 1.2.2 or BananaPlus Version 10.0.13.240 this method works also with alphanumeric ("DOC-021") and composite ("2022-021") numbers. For example, if the last used number is "DOC-021" this method returns "DOC-022", if the the last used number is "2022-021" this method returns "2022-022".


var trasactionsTable = Banana.document.table("Transactions");
var nextDocNr = trasactionsTable.progressiveNumber("Doc");

var invoicesTable = Banana.document.table("Invoices", true);
var nextInvoiceNr = invoicesTable.progressiveNumber("Id", true);

row(rowNr)

Return the Row at index rowNr as Row Object, or undefined if rowNr is outside the valid range.


var table = Banana.document.table("Accounts");
var row = table.row(3);

toJSON([columnNames])

Return the table data content as JSON string. If the parameter columnNames is defined, only the columns in the array are included in the file.


var table = Banana.document.table("Accounts");
var json = table.toJSON();

toHtml([columnNames, formatValues])

Return the table data content as Html file. If the parameter columnNames is defined, only the columns in the array are included in the file. If formatValues is set to true, the values are converted to the locale format.

Example:


//Show the whole row content of the table Accounts
Banana.Ui.showText(Banana.document.table('Accounts').toHtml());

//Show some columns and format dates, amounts, ... as displayed in the program
Banana.Ui.showText(
   Banana.document.table('Accounts').toHtml(['Account','Group','Description','Balance'],true)
);

toTsv([columnNames])

Return the table as Tsv file (Tab separated values). If the parameter columnNames is defined, only the columns in the array are included in the file.


var table = Banana.document.table("Accounts");
var tsv = table.toTsv();

value(rowNr, columnName)

Return the value in row rowNr and column columnName as string. Or undefined if the row or column are not found.

  • If the rowNr or column is not found it returns an undefined value .
  • See Table Content and Cell value form more information on the format of the returned String.   

var table = Banana.document.table("Accounts");
var account = table.value(3,'Account'); 
var description = table.value(3,'Description'); // "Cash Account"

Banana.IO

The Banana.IO is a static class that contains static methods used to read and write to files.

Introduction

The API Banana.IO and Banana.IO.LocalFile allow a script to read or write to files in a secure way. The script can only read or write to files that are first selected by the user through the corresponding dialogs, except for files that resides in the script package. The script has no direct access to files on the file system. After the script finishes, the permissions to write or read files are removed.

For example to write the result of a script to a file:


var fileName = Banana.IO.getSaveFileName("Select save file", "", "Text file (*.txt);;All files (*)");
if (fileName.length) {
   var file = Banana.IO.getLocalFile(fileName)
   file.codecName = "latin1";  // Default is UTF-8
   file.write("Text to save ...");
   if (!file.errorString) {
      Banana.IO.openPath(fileContent);
   } else {
      Banana.Ui.showInformation("Write error", file.errorString);
   }
} else {
   Banana.Ui.showInformation("Info", "no file selected");
}

To read the content from a file:


var fileName = Banana.IO.getOpenFileName("Select open file", "", "Text file (*.txt);;All files (*)")
if (fileName.length) {
   var file = Banana.IO.getLocalFile(fileName)
   file.codecName = "latin1";  // Default is UTF-8
   var fileContent = file.read();
   if (!file.errorString) {
      Banana.IO.openPath(fileContent);
   } else {
      Banana.Ui.showInformation("Read error", file.errorString);
   }
} else {
   Banana.Ui.showInformation("Info", "no file selected");
}

To read the content of a file contained in the script package:


let file = Banana.IO.getLocalFile("file:script/changelog.md")
let text = file.read()

Methods

fileCompleteBaseName(path)

Static method.
The method fileCompleteBaseName Returns the complete base name of the file without the path. The complete base name consists of all characters in the file up to (but not including) the last '.' character.

The parameter path is path inclusive the file name to be selected.


let path = "file:script/../test/testcases/MyTestFile.csv"
let fileName = Banana.IO.fileCompleteBaseName(path); // fileName = MyTestFile.csv

getOpenFileName(caption, path, filter)

Static method.
The method getOpenFileName returns an existing file selected by the user. If the user presses Cancel, it returns an empty string. The file selected by the user is then allowed to be read, but not written.

The parameter caption is the caption of the dialog.

The parameter path is path inclusive the file name to be selected. If the path is relative, the current open document path or the user's document path is used.

The parameter filter set the files types to be showed. If you want multiple filters, separate them with ';;', for example: "Text file (*.txt);;All files (*)".


var fileName = Banana.IO.getOpenFileName("Select file to read", "", "Text file (*.txt);;All files (*)")

Since: Banana Accounting 9.0.7, only in Banana Experimental

getSaveFileName(caption, path, filter)

Static method.
The method getSaveFileName returns an existing file selected by the user. If the user presses Cancel, it returns an empty string. The file selected by the user is then allowed to be read and written.

The parameter caption is the caption of the dialog.

The parameter path is path inclusive the file name to be selected. If the path is relative, the current open document path or the user's document path is used.

The parameter filter set the files types to be showed. If you want multiple filters, separate them with ';;', for example: "Text file (*.txt);;All files (*)".


var fileName = Banana.IO.getSaveFileName("Select file to write", "", "Text file(*.txt);;All files (*)")

getLocalFile(path)

Static method.
The method getLocalFile(path) returns an object of type Banana.IO.LocalFile that represents the requested file. This method always returns a valid Banana.IO.LocalFile object.

The parameter path to the file.

The path can be relative to the script's folder:
file:script/<relative_path_to_script_folder>/<file_name>

openUrl(path)

Static method.
The method openUrl(path) opens the file referred by path in the system default application.

The parameter path to the file. 

openPath(path)

Static method.
The method openPath(path) shows the folder containing the file referred by path in the system file manager.

The parameter path to the file. 

Banana.IO.LocalFile

The LocalFile class represents a file on the local file system. See Banana.IO for an example.

Properties

codecName

The name of the codec to be used for reading or writing the file. Default is 'UTF-8'.

errorString

Read only. The string of the last occured error. If no error occured it is empty.

Methods

read()

Returns the content of the file. This function has no way of reporting errors. Returning an empty string can mean either that the file is empty, or that an error occurred. Check the content of the property errorString to see if an error occured.

write(text [, append])

Write text to the file. If append is set to true, text is appended to the file. Returns true if the operation was succesfully, false otherwise.

 

Banana.Report

The class Banana.Report enables you to create reports, preview, print and export to pdf or other formats.

Introduction

The report logic is similar to the HTML / CSS logic:

  1. Create a Report object .
    • A report contains a list of ReportElements (paragraphs, texts, tables and other)
    • The element can contain other sub-elements
    • For each element you can add a class that is used for rendering the element
  2. Create a StyleSheet using the Banana.Report.newStyleSheet() function.
  3. Add syle elements to the stylesheet.
  4. You preview and print a report by passing the Report and the Stylesheet object.

// Example "Hello World" report

// Create a report object
var report = Banana.Report.newReport("Report title");
report.addParagraph("Hello World !!!", "styleHelloWorld");

// Create stylesheet object
var stylesheet = Banana.Report.newStyleSheet();

// Add style elements to the stylesheet object
var style = stylesheet.addStyle(".styleHelloWorld");
style.setAttribute("font-size", "96pt");
style.setAttribute("text-align", "center");
style.setAttribute("margin-top", "50mm");
var style2 = stylesheet.addStyle("@page");
style2.setAttribute("size", "landscape");

// Print preview using the report and the stylesheet
Banana.Report.preview(report, stylesheet);

Report structure

Each report sturcture has:

  • A Report Element list.
  • A Header Element list.
  • A Footer Element list.

 

Methods

 

logoFormat(name)

Returns the logo format with 'name'. The returned object is of type Banana.Report.ReportLogo.
Returns null if no logo format with name 'name' exists.
Logo formats are defined through the dialog File → Logo Setup .



var headerLogoSection = report.addSection("");
var logoFormat = Banana.Report.logoFormat("Logo");
if (logoFormat) {
   var logoElement = logoFormat.createDocNode(headerLogoSection, reportStyle, "logo");
   report.getHeader().addChild(logoElement);
}

Since: Banana Accounting 9.0.4

 

logoFormatsNames()

Returns a list with the logo formats names.
Logo formats are defined through the dialog File → Logo Setup .



var logoNames = Banana.Report.logoFormatsNames();
// returns ["logo", "first_page_logo", "invoice_logo", ...]

Since: Banana Accounting 9.0.4  

 

newReport(title)

Creates a report with title 'title'. The returned object is of type Banana.Report.ReportElement.

To the report you can then add the desired elements, like paragraphs, texts, tables, and so on that construct the structure of the report.



var report = Banana.Report.newReport("Report title");

 

newStyleSheet()

Creates an empty stylesheet. The returned object is of type Banana.Report.ReportStyleSheet

To the stylesheet you can add the styles that format the report.



var stylesheet = Banana.Report.newStyleSheet();

 

newStyleSheet(fileName)

Creates a stylesheet from a file. The file has the same syntax as CSS stylesheets. The file path is relative to the script's path. The path can't contain a '..'' (parent directory).

The returned object is of type Banana.Report.ReportStyleSheet.

You can add further styles to the returned stylesheet.



var reportStyles = Banana.Report.newStyleSheet("styles.css");

*** Content of file styles.css ***
.helloWorldStyle
{
font-size: 96pt;
text-align: center;
margin-top: 50mm;
}

@page
{
size: landscape;
}
*** End of file styles.css ***

 

preview(report, stylesheet)

Opens a print preview Dialog and shows the report with the given stylesheet. 

The param report is an object of type Banana.Report.ReportElement. The param stylesheet is an object of type Banana.Report.ReportStyle.

The page orientation is given by the stylesheet. The default size and orientation is taken from the default printer, or can be set through the stylesheet.



// Set landscape orientation
stylesheet.addStyle("@page {size: landscape}");

// Set page size and orientation
stylesheet.addStyle("@page {size: A5 lanscape}");

// Displays the report
Banana.Report.preview(report, stylesheet);

 

preview(title, reports, stylesheets)

Opens a print preview Dialog with title 'title' and shows the reports with the given stylesheets. This method allows you to print two or more distinct reports together.

The param report is an array of objects of type Banana.Report.ReportElement. The param stylesheet is an array of objects Banana.Report.ReportStylesheet.

Each report's title will appear in the index of the printed pdf. The numbering of pages will restart from 1 at the beginning of each printed report.

The page orientation is given by the stylesheet. The default size and orientation is taken from the default printer, or can be set through the stylesheet.



var docs = [];
var styles = [];

// Report
for (var i = 0; i < 10; i++) {
   var report = Banana.Report.newReport("Report title");
   report.addParagraph("Hello World #" + i + " !!!", "styleHelloWorld");
   report.setTitle("Document " + i); // The report's title will appear in the pdf's index
   report.getFooter().addFieldPageNr();
   docs.push(report);

   // Styles
   var stylesheet = Banana.Report.newStyleSheet();
   var style = stylesheet.addStyle(".styleHelloWorld");
   style.setAttribute("font-size", "24pt");
   style.setAttribute("text-align", "center");
   style.setAttribute("margin-top", "10mm");
   var style2 = stylesheet.addStyle("@page");
   style2.setAttribute("size", "landscape");
   styles.push(stylesheet);
}

// Print preview of 10 documents together
Banana.Report.preview("Multi documents printing example", docs, styles);

Since Banana Accounting 9.0.4

 

qrCodeImage(text, qrCodeParam)

Creates a QRCode image according to the passed text. The returned object is a svg image.

  • qrCodParam.errorCorrectionLevel
    string value H (high), L (low), M (medium), Q (quartile) (default value M)
  • qrCodeParam.binaryCodingVersion
    int value from 0 to 40 (default value 40)
  • qrCodeParam.border
    int value from 0 to 100 (default value 0)
  • qrCodeParam.errorMsg
    in case of error the method returns the error message in this property

since: Banana Accounting+



var text = 'hello world';
var qrCodeParam = {};
qrCodeParam.errorCorrectionLevel = 'M';
qrCodeParam.binaryCodingVersion = 25;
qrCodeParam.border = 0;

var qrCodeSvgImage = Banana.Report.qrCodeImage(text, qrCodeParam);
if (qrCodeParam.errorMsg && qrCodeParam.errorMsg.length>0) {
   Banana.document.addMessage(qrCodeParam.errorMsg);
}
if (qrCodeSvgImage) {
   var repDocObj = Banana.Report.newReport('Printing QRCode img');
   repDocObj.addImage(qrCodeSvgImage, 'qrcode');
}

setFirstPageNumber(pageNr)

The passed argument pageNr will be used by the method Banana.Report.ReportElement.addFieldPageNr as first page number.

 

Example: Hello world



// Simple test script using Banana.Report
//
// @id = ch.banana.script.report.helloworld
// @api = 1.0
// @pubdate = 2017-01-02
// @publisher = Banana.ch SA
// @description = Report Hello world
// @task = app.command
// @doctype = *
// @inputdatasource = none
// @timeout = -1
//

function exec(string) {

   // Create the report
   var report = Banana.Report.newReport("Report title");
   
   // Add a paragraph to the report
   report.addParagraph("Hello World !!!", "helloWorldStyle");

   // Define some styles
   var stylesheet = Banana.Report.newStyleSheet();
   
   var style = stylesheet.addStyle(".helloWorldStyle");
   style.setAttribute("font-size", "96pt");
   style.setAttribute("text-align", "center");
   style.setAttribute("margin-top", "50mm");

   var style2 = stylesheet.addStyle("@page");
   style2.setAttribute("size", "landscape");

   // Open Preview
   Banana.Report.preview(report, stylesheet);
}

 

An example with tables, page breaks and differents styles

Result

 

Script



// Test script using Banana.Report
//
// @id = ch.banana.script.report.report
// @api = 1.0
// @pubdate = 2017-01-02
// @publisher = Banana.ch SA
// @description = Test report api
// @task = app.command
// @doctype = *
// @outputformat = none
// @inputdatasource = none
// @timeout = -1
//

function exec(string) {

   // Report
   var report = Banana.Report.newReport("Report title");

   var pageHeader = report.getHeader()
   pageHeader.addClass("header");
   pageHeader.addText("Page header");
   report.getFooter().addFieldPageNr();

   var watermark = report.getWatermark();
   watermark.addParagraph("Sample built with Script Report API");
 
   report.addParagraph("Report title", "titleStyle");
   report.addParagraph("1. Text", "chapterStyle").setOutline(1);

   report.addParagraph("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do " +
    "eiusmod tempor incididunt ut labore et dolore magna aliqua. " +
    "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip " +
    "ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit " +
    "esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non " +
    "proident, sunt in culpa qui officia deserunt mollit anim id est laborum.");
 
   var paragraph2 = report.addParagraph();
   paragraph2.addText("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do ");
   paragraph2.addText("eiusmod tempor incididunt ut labore et dolore magna aliqua. ", "blueStyle");
   paragraph2.addText("Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ", "boldStlyle");
   paragraph2.addText("ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit ", "underlineStyle boldStyle");
   paragraph2.addText("esse cillum dolore eu fugiat nulla pariatur.");
   paragraph2.addLineBreak();
   paragraph2.addText("Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", "italicStyle");

   report.addParagraph("2. Table", "chapterStyle").setOutline(1);

   var table = report.addTable();
   table.getCaption().addText("Table caption");
       
   var tableHeader = table.getHeader();
   var tableHeaderRow = tableHeader.addRow();
   tableHeaderRow.addCell("Description", "", 2);
   tableHeaderRow.addCell("Income");
   tableHeaderRow.addCell("Expense");
   tableHeaderRow.addCell("Balance");
 
   var tableRow = table.addRow();
   tableRow.addCell();
   tableRow.addCell("Initial balance");
   tableRow.addCell();
   tableRow.addCell();
   tableRow.addCell(Banana.Converter.toLocaleNumberFormat("157.00")).addClass("balanceStyle");

   var tableRow = table.addRow();
   tableRow.addCell(Banana.Converter.toLocaleDateFormat("2014-02-11"));
   tableRow.addCell("Transfer from post office account");
   tableRow.addCell(Banana.Converter.toLocaleNumberFormat("500.00"));
   tableRow.addCell();
   tableRow.addCell(Banana.Converter.toLocaleNumberFormat("657.00")).addClass("balanceStyle");
 
   var tableRow = table.addRow();
   tableRow.addCell(Banana.Converter.toLocaleDateFormat("2014-02-20"));
   tableRow.addCell("Various payments");
   tableRow.addCell();
   tableRow.addCell(Banana.Converter.toLocaleNumberFormat("7250.00"));
   tableRow.addCell(Banana.Converter.toLocaleNumberFormat("-6593.00")).addClass("balanceStyle negativeStyle");

   var tableRow = table.addRow("totalrowStyle");
   tableRow.addCell();
   tableRow.addCell("Total transactions");
   tableRow.addCell(Banana.Converter.toLocaleNumberFormat("500.00"));
   tableRow.addCell(Banana.Converter.toLocaleNumberFormat("7250.00"));
   tableRow.addCell(Banana.Converter.toLocaleNumberFormat("-6593.00")).addClass("balanceStyle negativeStyle");
 
   report.addParagraph("3. Bookmarks and links", "chapterStyle").setOutline(1);

   report.addParagraph("3.1 Internal links", "chapter2Style").setOutline(2);
   report.addParagraph("-> link to bookmark on page 2").setLink("bookmarkpage2");

   report.addParagraph("3.2 External links", "chapter2Style").setOutline(2);
   report.addParagraph("-> link to Banana.ch web page").setUrlLink("http://www.banana.ch");
 
   report.addPageBreak();
 
   var chapter4 = report.addParagraph("4. Pages", "chapterStyle");
   chapter4.setOutline(1);
 
   report.addParagraph("Bookmark on page 2").setBookmark("bookmarkpage2");
 

   // Styles
   var docStyles = Banana.Report.newStyleSheet();
 
   var pageStyle = docStyles.addStyle("@page");
   pageStyle.setAttribute("margin", "20mm 20mm 20mm 20mm");
 
   var headerStyle = docStyles.addStyle("phead");
   headerStyle.setAttribute("padding-bottom", "1em");
   headerStyle.setAttribute("margin-bottom", "1em");
   headerStyle.setAttribute("border-bottom", "solid black 1px");
    
   var footerStyle = docStyles.addStyle("pfoot");
   footerStyle.setAttribute("text-align", "right");
 
   var paragraphStyle = docStyles.addStyle("p");
   paragraphStyle.setAttribute("margin-top", "0.5em");

   var captionStyle = docStyles.addStyle("caption");
   captionStyle.setAttribute("margin-top", "1em");

   var titleStyle = docStyles.addStyle(".titleStyle");
   titleStyle.setAttribute("font-size", "24");
   titleStyle.setAttribute("text-align", "center");
   titleStyle.setAttribute("margin-bottom", "1.2em");

   docStyles.addStyle(".chapterStyle", "font-size:16; margin-top:2em; margin-bottom:0.2em");
   docStyles.addStyle(".chapter2Style", "font-size:12; margin-top:1.4em; margin-bottom:0.2em");
 
   var tableStyle = docStyles.addStyle("table");
   tableStyle.setAttribute("border", "2px solid red");
 
   docStyles.addStyle("td", "border: 1px dashed black; padding: 2px;");

   var tableColStyle = docStyles.addStyle(".balanceStyle");
   tableColStyle.setAttribute("background-color", "#E0EFF6");
   tableColStyle.setAttribute("text-align", "right");

   var totalRowStyle = docStyles.addStyle(".totalrowStyle");
   totalRowStyle.setAttribute("font-weight", "bold");

   var totalBalanceStyle = docStyles.addStyle(".totalrowStyle td.balanceStyle");
   totalBalanceStyle.setAttribute("text-decoration", "double-underline");

   docStyles.addStyle(".blueStyle", "color:blue");
   docStyles.addStyle(".underlineStyle", "text-decoration:underline;");
   docStyles.addStyle(".italicStyle", "font-style:italic;");
   docStyles.addStyle(".boldStyle", "font-weight:bold");

   // Open Preview
   Banana.Report.preview(report, docStyles);
}

Banana.Report.ReportElement

The class Banana.Report.ReportElement represents the report itself and every element in the report, such as sections, paragraphs, tables, texts and the report itself.

Once you create a new report through the method Banana.Report.newReport() you can start adding sections, paragraphs, texts, tables and so on. 

When you add an element with one of the add methods, you get as return value an object of type

Elements as a container of other elements

Banana.Report.ReportElement that represents the added element.  
To this object you can add further elements and by this way construct the structure of the report.

Report  
   +  Paragraph  
   +  Table  
      +  Row  
         + Cell  
         + Cell  
      +  Row  
         + Cell  
         + Cell  
      ...

Even if this interface allows you to add tables to text elements or columns to paragraphs, the result will be undefined.

Formatting text size, text color, margins, and so on are set separately through a Banana.Report.ReportStyleSheet object.

 

Methods

addAttachment(name, content)

Add an attachment to the document. 

  • The param name defines the name of the attachment inclusive extention (.png, .pdf, .xml) that will appear in print preview attachment's list on in the printed pdf.
  • The param content contains the path to the file to attach or the data to attach.
    • The path can be relative to the script's folder, the document's folder, the name of a document attacched to the file or a data uri scheme (for images imbedded in the document).
    • file:script/<relative_path_to_script_folder>/<image_name>
    • file:document/<relative_path_to_file_folder>/<image_name>
    • documents:<document_name>
    • data:[<media type>][;charset=<character set>][;base64],<data>

Example:


//Create the report
var report = Banana.Report.newReport('Report attachments');
//Add a paragraph with some text
report.addParagraph('Report with attachments');
//Attach file on computer path relative to the accounting file  
report.addAttachment('doc1.pdf', 'doc1.pdf'); 
report.addAttachment('doc2.pdf', 'documents/doc2.pdf'); 
//Attach text files created on the fly
//We use the prefix 'data:...' to tell that the string is not an url but is itself the content of the file
report.addAttachment('text file 1.txt', 'data:text/plain;utf8,This is the content of the text file 1.');
report.addAttachment('text file 2.txt', 'data:text/plain;utf8,This is the content of the text file 2.');
report.addAttachment('text file 3.txt', 'data:text/plain;utf8,This is the content of the text file 3.');
//Attach an image stored in the document table
//We use the prefix 'document:...'
report.addAttachment('logo.jpg', 'documents:logo');
//Add an xml element
//We just add the new created Banana.Xml.newDocument
var xmlDocument = Banana.Xml.newDocument("eCH-0217:VATDeclaration");
var rootNode = xmlDocument.addElement("eCH-0217:VATDeclaration");
rootNode.addElement("title").addTextNode("Vat Declaration 2018");
report.addAttachment('vat_declaration.xml', xmlDocument);
//Print the report
var stylesheet = Banana.Report.newStyleSheet();
Banana.Report.preview(report, stylesheet);

Since Banana Accounting 9.0.4

addClass(classes)

Add classes to the node. A class binds the element to the corresponding class style definend in Banana.Report.ReportStyleSheet as used in CSS Stylesheets.


var report = Banana.Report.newReport("Report title");
report.addParagraph("1250.00").addClass("balanceStyle");

addDocInfo(name, value [, description])

Add document's informations to the document. When you generate multiple documents from your script and want to export them as separated pdfs, document's informations are used by the application to build meaningful file names for the exported pdf files, like "Invoice 1234 - Joe Black.pdf". The document's information "name" contains the default file name used by the application. The user when creating the pdf files, can choose to use the default "name", or combine freely the other document's informations for the file names.

For the following names, the application add a default description. For other names, like "doc_status", you can add your own description.

  • name
  • doc_title
  • doc_number
  • doc_date
  • doc_amount
  • doc_currency
  • customer_number
  • customer_name
  • customer_city
  • customer_email
  • account
  • cur_date
  • cur_time

You can add document's informations only to a document object.

report.addDocInfo("name", "Invoice 1234 - Joe Black.pdf");
report.addDocInfo("doc_title", "Invoice 1234");
report.addDocInfo("doc_number", "1234");
report.addDocInfo("customer_name", "Joe Black");
report.addDocInfo("doc_amount", "1023.00");
report.addDocInfo("doc_status", "paid", "Document status");

addSection([classes])

Add a section and return the created section as a Banana.Report.ReportElement object.

You can add sections only to sections, cells, captions, headers or footers.


var report = Banana.Report.newReport("Report title");
//Add a section with a style
var section = report.addSection("sectionStyle");
section.addParagraph("First paragraph");
section.addParagraph("Second paragraph");

addParagraph([text, classes])

Add a paragraph and return the created paragraph as a Banana.Report.ReportElement object.

You can add paragraphs only to sections, cells, captions, headers or footers.


var report = Banana.Report.newReport("Report title");
//Add an empty paragraph
report.addParagraph(" ");
//Add a paragraph with a text
report.addParagraph("Hello World !!!");
//Add a paragraph with a text and a style
report.addParagraph("Hello World !!!", "styleHelloWorld");

addHeader1..6([text])

The methods addHeader1 to addHeader6 add an header and return the created header as a Banana.Report.ReportElement object. The corresponding outline from 1 to 6is set automatically.

You can add headers only to sections, and documents.

var report = Banana.Report.newReport("Report title");
//Add headers
report.addHeader1("Header 1");
report.addHeader2("Header 1.2");
report.addParagraph("Some text.");
report.addHeader1("Header 2"); 
report.addHeader2("Header 2.1");
report.addParagraph("Some text.");
report.addHeader2("Header 2.2");
report.addParagraph("Some text.");

addText(text [, classes])

Add a text node and return the created text node as a Banana.Report.ReportElement object.

You can add texts only to sections, paragraphs, cells, captions, headers or footers.


var report = Banana.Report.newReport("Report title");
//Add a text 
report.addText("Hello world !!!");
//Add a text with a style
report.addText("Hello world !!!", "styleHelloWorld");

addStructuredText(text, format, [, stylesheet])

Add a structured text to the document.

Supported formats are

  • 'md'  
    Structured github markdown.
  • 'html'
  • 'text'

The function returns the new section containing the structured text  as a Banana.Report.ReportElement object.

You can add structured text only to sections, paragraphs, cells, captions, headers or footers.

Open examples in browser

Example for Markdown text

// Report
var report = Banana.Report.newReport("Report title");
// Styles
var stylesheet = Banana.Report.newStyleSheet();
// Add Markdown text
let mdText = "# Header 1\n";
mdText += "## Header 2\n";
mdText += "### Header 3\n";
mdText += "Markdown text with **bold** and *italic*.  \n";
mdText += "[Markdown link](https://www.banana.ch)  \n";
mdText += "* List row 1\n";
mdText += "* List row 2\n";
mdText += "* List row 3\n";
report.addStructuredText(mdText, "md");
// Print preview
Banana.Report.preview(report, stylesheet);

Example for simple Html text

// Report
var report = Banana.Report.newReport("Report title");
// Styles
var stylesheet = Banana.Report.newStyleSheet();
// Add html text
let htmlText = "<h1 style=\"color: red\">Header 1 Red</h1>\n";
htmlText += "<p style=\"color: blue\">Paragraph blue</p>\n";
report.addStructuredText(htmlText, "html");
//Print preview 
Banana.Report.preview(report, stylesheet); 

Example for full Html text

If you add a full html (with head and style element), you should pass a stylesheet parameter. The styles defined in the html style element are added to the report stylesheet. If not the styles defined in the html style element are lost, and like in this example the paragraphs are not coloured with red and blue.

// Report
var report = Banana.Report.newReport("Report title");
// Styles
var stylesheet = Banana.Report.newStyleSheet();
// Add html text
let htmlText = "<html>\n";
htmlText += "<head>\n";
htmlText += "<style>\n";
htmlText += "p.blue {color: blue;}\n";
htmlText += ".red {color: red;}\n";
htmlText += "</style>\n";
htmlText += "</head>\n";
htmlText += "<body>\n";
htmlText += "<h1 class=\"red\">Header 1 Red</h1>\n";
htmlText += "<p class=\"blue\">Paragraph blue</p>\n";
htmlText += "</body>\n";
htmlText += "</html>\n";
report.addStructuredText(htmlText, "html", stylesheet);
//Print preview 
Banana.Report.preview(report, stylesheet); 

Example for Plain text

// Report
var report = Banana.Report.newReport("Report title");
// Styles
var stylesheet = Banana.Report.newStyleSheet();
// Plain Text
let plainText = "Testo riga 1\n";
plainText += "Testo riga 2\n";
plainText += "Testo riga 3\n";
// Add plain text
report.addStructuredText(plainText, "text");	
	
// Print preview
Banana.Report.preview(report, stylesheet);

 

addTable([classes])

Add a table and return the created table as a Banana.Report.ReportElement object.

You can add tables only to the report or sections.


var report = Banana.Report.newReport("Report title");
var myTable = report.addTable("myTable");

addColumn([classes])

Add a column and return the created column as a Banana.Report.ReportElement object.

You can add columns only to tables.


var column1 = myTable.addColumn("column1");
var column2 = myTable.addColumn("column2");
var column3 = myTable.addColumn("column3");

addRow([classes])

Add a row and return the created row as a Banana.Report.ReportElement object.

You can add rows only to tables, table headers or table footers.


var tableRow = myTable.addRow();
...

addCell([span])

Add an empty cell and return the created cell as a Banana.Report.ReportElement object.

You can add cells only to rows. You can span cells over columns but not over rows.


tableRow.addCell();      //span empty cell over 1 column (default value)
tableRow.addCell("", 3); //span empty cell over 3 columns
...

addCell(text [,classes, span])

Add a cell to the node and return the created cell as a Banana.Report.ReportElement object.

You can add cells only to rows.You can span cells over columns but not over rows.


tableRow.addCell("Bank", "firstCellStyle", 3);      //span cell over 3 columns
tableRow.addCell("1200.65", "secondCellStyle, 1);   //span cell over 1 column
...

addLineBreak()

Add a line break and return the created line break as a Banana.Report.ReportElement object.

You can add line breaks only to paragraphs or cells.


// Add a line break to a paragraph
var p = report.addParagraph(" ");
p.addLineBreak();
// Add a line break to a cell
var c = tableRow.addCell();
c.addLineBreak();

addPageBreak()

Add a page break node and return the created page beak as a Banana.Report.ReportElement object.

You can add page breaks only to the report or sections.


var report = Banana.Report.newReport("Report title");
...
report.addPageBreak();
...

addImage(path [,classes])

Add an image and return the created image as a Banana.Report.ReportElement object. Supported formats are:

  • png
  • jpg
  • svg

The path can be relative to the script's folder, the document's folder, the name of a document attacched to the file or a data uri scheme (for images imbedded in the document).  
- file:script/<relative_path_to_script_folder>/<image_name>  
- file:document/<relative_path_to_file_folder>/<image_name>  
- documents:<document_name>  
- data:[<media type>][;charset=<character set>][;base64],<data>

You can add images only to sections, paragraphs, cells, captions, headers or footers.

The parameter path can be absolute or relative to the script path.


var report = Banana.Report.newReport("Report title");
// Add an image located in the script folder
report.addImage("file:script/logo_abc.jpg");
// Add an image located in the dcoument folder
report.addImage("file:document/logo_mnp.jpg");
// Add an image saved in the table documents
report.addImage("documents:logo_xyz.jpg");
// Add an image (a red dot) included in the document
report.addImage("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO 9TXL0Y4OHwAAAABJRU5ErkJggg==");
// Add a SVG base64 image
report.addImage("data:image/svg+xml;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO 9TXL0Y4OHwAAAABJRU5ErkJggg==");

addImage(path, widht, height [,classes])

Overloaded method to add an image and return the created image as a Banana.Report.ReportElement object.

The parameters width and height have the same syntax as css length values. They can be absolute (ex.: "30px", "3cm", ... ) or relative (ex.: "50%", "3em", ...).


        var report = Banana.Report.newReport("Report title");
        report.addImage("documents:image_logo", "3cm", "5cm");
        

addFieldPageNr([classes])

Add a field containg the page number and return the created field as a Banana.Report.ReportElement object.

You can add this field only to sections, paragraphs, cells, captions, headers or footers.


var report = Banana.Report.newReport("Report title");
...
// Add the page number to the paragraph
report.addParagraph("Page ").addFieldPageNr();
// Add a page number to the footer
var footer = report.getFooter();
footer.addText("Page ");
footer.addFieldPageNr();

excludeFromTest()

Mark the field to not be tested during a test case. The value is in any case outputed to the test results, it is just ignored during the comparison of the test results.

This is useful, for example, for text fields containing the current date.


var currentDate = Banana.Converter.toLocaleDateFormat(new Date());
var textfield = report.getFooter().addText(currentDate);
textfield.excludeFromTest();

getWatermark()

Return the watermark element.

Only the report has a watermak element.


var watermark = report.getWatermark();
watermark.addParagraph("Watermark text");

getHeader()

Return the header of the element. 

Only tables and the report have an header element.


var report = Banana.Report.newReport("Report title");
//Report
var reportHeader = report.getHeader();
reportHeader.addClass("header");
reportHeader.addText("Header text");
//Table
var table = report.addTable("myTable");
var tableHeader = table.getHeader();
tableRow = tableHeader.addRow();
tableRow.addCell("Description");
tableRow.addCell("Amount");

getFooter()

Return the footer of the element. 

Only tables and the report have a footer element.

//Report
var footer = report.getFooter();
footer.addText("Footer text");

getCaption()

Return the caption of the element. 

Only tables have a caption element.

var table = report.addTable("MyTable");  
var caption = table.getCaption();
caption.addText("Table caption text", "captionStyle");

getChildren()

Return the children of the element as an array.

var report = Banana.Report.newReport("Report title");
let section = report.addSection(); 
section.addParagraph("some text 1"); 
section.addParagraph("some text 2"); 
let count = section.getChildren().length; // count == 2

This method was introduced in BananaPlus 10.0.12.151.

getParent()

Return the parent of the element, or null if the element is the root element.

var report = Banana.Report.newReport("Report title");
let section = report.addSection(); 
let paragraph = section.addParagraph("some text"); 
let root = paragraph.getRoot(); // root == report 

This method was introduced in BananaPlus 10.0.12.151.

getRoot()

Return the root element.

var report = Banana.Report.newReport("Report title");
let section = report.addSection();
let paragraph = section.addParagraph("some text");
let parent = paragraph.getParent(); // root == paragraph

This method was introduced in BananaPlus 10.0.12.151.

getTag()

Return the tag of the element, like 'body', 'p', 'table', 'td' and so on.

var report = Banana.Report.newReport("Report title");
...
report.getTag(); // returns 'body'
footer.getTag(); // returns 'pfoot'
...

getTitle()

Return the title of the element.  
Only a document element have a title.


var report = Banana.Report.newReport("My Report Title");
var title = report.getTitle(); // return 'My Report Title'

setOutline(level)

Set the outline level, this is used to create the index when exporting to pdf.


report.addParagraph("1. Text").setOutline(1);

setBookmark(bookmark)

Set a bookmark (or anchor), this is used in conjunction with setLink().


report.addParagraph("Bookmark on page 2").setBookmark("bookmarkpage2");

setLink(bookmark)

Set a link to a bookmark. See setBookmark().


report.addParagraph("-> link to bookmark on page 2").setLink("bookmarkpage2");

setPageBreakBefore()

Set to insert a page break before the element.


// Insert a page break before a paragraph
report.addParagraph("Hello world!!!").setPageBreakBefore();
// Insert a page break before a table
   /* first create a table then... */
myTable.setPageBreakBefore();

setSize(width, height)

Set the size of the element.

The parameters width and height have the same syntax as css length values. They can be absolute (ex.: "30px", "3cm", ... ) or relative (ex.: "50%", "3em", ...).

You can only set the size of an image element.


var image = report.addImage("C:/Documents/Images/img.jpg");
image.setSize("3cm", "6cm");

setStyleAttribute(attr_name, attr_value)

Set a style attribute to the element. Attributes ids and values follow the CSS specification. This attibute correspont to the inline styles in Css.


paragraph.setAttribute("font-size", "24pt");

setStyleAttributes(attributes)

Set style attributes to the element. Attributes ids and values follow the CSS specification. Those attributes correspond to the inline styles in Css.


        paragraph.setAttribute("font-size:24pt;font-weight:bold;");
        

setTitle(title)

Set the title of the element. 

Title can be only set to a document element.


        document.setTitle("Annual report");
        

setUrlLink(link)

Set a link to an external file (file://...) or a web page (http://....).

To the element the class "link" is automatically added.


report.addParagraph("Link to Banana.ch web page").setUrlLink("http://www.banana.ch");
 

Banana.Report.ReportLogo

The class Banana.Report.ReportLogo represents the format of a logo's section.

With a Banana.Report.ReportLogo object you can create and insert a logo's section in the report document. The logo format is defined through the dialog  File â†’ Logo Setup.

With this class you don't have to rewrite your scripts to change the logo's section, you can just change the format in the dialog Logo Setup, and the script will apply the new format automatically.

 

Methods

 

createDocNode(textNode, stylesheet, disambiguosClass)

Create a new Report Element that represent the logo's section as defined in the dialog File â†’ Logo Setup.

The param textNode is the text node to insert within in the logo section.

The param stylesheet is the stylesheet where the styles needed by the logo section are inserted.

The param disambiguosClass is a string used to prevent clashes with stylesheet class names.



// Get the logo format
var headerLogoSection = report.addSection("");
var logoFormat = Banana.Report.logoFormat("Logo"); 
if (logoFormat) {
    // Use the format as defined in the dialog File --> Logo Setup   
    var logoElement = logoFormat.createDocNode(headerLogoSection, repStyleObj, "logo"); 
    report.getHeader().addChild(logoElement); } 
else {
    // If the format 'logo' is not defined, insert an image   
    report.addImage("documents:logo", "logoStyle"); 
} 

 

Banana.Report.ReportStyleSheet

The class Banana.Report.ReportStyleSheet is used to set the styles to format a report.
It contains multiple Banana.Report.ReportStyle objects.

Create a report stylesheet

A report stylesheet object is created using the function Banana.Report.newStylesheet().

// Create a new stylesheet for the report
var stylesheet = Banana.Report.newStyleSheet();

Page size and orientation

At this moment the report is rendered based on the page size defined in the default printer device.
You can't define a page size, but you can set the orientation with the Style @page.

Page orientation can't be set only once per report, you can't switch from potrait to landscape. 


var stylesheet = Banana.Report.newStyleSheet();
stylesheet.addStyle("@page").setAttribute("size", "landscape");

Methods

addStyle(selector)

Create a new style with the given selector. The return object is of type Banana.Report.ReportStyle.

The syntax of selector follows the CSS specification.

  • Style name without a preceding dot are reserved predefined tags like "td", "p", "table",... ( e.g. 'addStyle("td")' )
  • Style name for a new custom class need a preceding dot "." ( e.g. 'addStyle(".myStyle")' )
    The dot name is not used when adding the class name to the element

report.addParagraph("Text to print 24pt", "myStyle");
var style = stylesheet.addStyle(".myStyle");
myStyle.setAttribute("font-size", "24pt");
myStyle.setAttribute("text-align", "center"); 

report.addCell("Text to print");
var styleTd = stylesheet.addStyle("td");
styleTd.setAttribute("font-weight", "bold");

 

addStyle(selector, attributes)

Create a new style with the given selector and attributes. The return object is of type Banana.Report.ReportStyle.

The syntax of selector and attributes follow the CSS specification.


var style2 = stylesheet.addStyle(".style2", "font.size: 24pt; text-align: center");
 

parse(text)

Load the styles from the given text. The text follow the CSS specification.


stylesheet.parse(
  "p.style1 {font-size:24pt; text-align:center;}" +
  "@page {size:A4 landscape;}"
  );

See the How to use CSS file  tutorial example.

The selector

The selector follows the css syntax.

Example of selectors:

  • .xyz
    Select all elements with class xyz. It is used with a preceding dot "." before the class name.
    When you set the class to a ReportElement you enter the name without "."
  • table
    Select all tables
  • table.xyz
    Select all tables with class xyz
  • table.xyz td
    Select all cells in tables with class xyz
Example of tag selectors:
  • @page
    Select the page
  • body
    Select the content of the report
  • phead
    Select the page header
  • pfoot
    Select the page footer
  • div
    Select the section
  • p
    Select the paragraph
  • table
    Select the table
  • caption
    Select the caption
  • thead
    Select the table header
  • tbody
    Select the table body
  • tfoot
    Select the table footer
  • tr
    Select the table row
  • td
    Select the table cell

You can get the tag of an element through the method getTag();

Function for adding styles

When you have multiple styles it would be helpful to add a function for all the styles you need. For example:

function exec() {

  // Create a new report object with the title "Report title"
  var report = Banana.Report.newReport("Report title");
  
  // Add example text for each style in the report
  report.addParagraph("Hello World", "title");                     // Example text for title style
  report.addParagraph("Subtitle Example", "subtitle");             // Example text for subtitle style
  report.addParagraph("Header Example", "header");                 // Example text for header style
  report.addParagraph("Data Example", "data");                     // Example text for data style
  report.addParagraph("Centered Text Example", "centerAlign");     // Example text for center alignment
  report.addParagraph("Right-Aligned Text Example", "rightAlign"); // Example text for right alignment
  report.addParagraph("Footer Example", "footer");                 // Example text for footer style

  // Create a new stylesheet object for the report
  var stylesheet = Banana.Report.newStyleSheet();

  // Call the function to define and apply styles to the stylesheet
  addStyles(stylesheet);

  // Display the report in a preview window with the applied stylesheet
  Banana.Report.preview(report, stylesheet);
}

// Function that defines all the CSS styles for the report elements
function addStyles(stylesheet) {

    // Style for headers: bold font and a bottom border
    stylesheet.addStyle(".header", "font-weight: bold; border-bottom: 1px solid black;");
    
    // Style for data cells: padding and a light bottom border
    stylesheet.addStyle(".data", "padding: 5px; border-bottom: 0.5px solid #ddd;");
    
    // Style to center-align text
    stylesheet.addStyle(".centerAlign", "text-align: center");
    
    // Style to right-align text
    stylesheet.addStyle(".rightAlign", "text-align: right");
    
    // Style for the main title: larger font, bold, centered, with top margin
    stylesheet.addStyle(".title", "font-size: 16px; font-weight: bold; text-align: center; margin-top: 20px;");
    
    // Style for subtitles: smaller font, centered, with bottom margin
    stylesheet.addStyle(".subtitle", "font-size: 10px; text-align: center; margin-bottom: 20px;");
    
    // Style for the footer: small font, centered, with top margin
    stylesheet.addStyle(".footer", "text-align: center; font-size: 8px; margin-top: 20px;");
}

 

 

Banana.Report.ReportStyle

The class Banana.Report.ReportStyle represents a single style in Banana.ReportStyleSheet object. 
It is used to set the style attributes.

Methods

setAttribute(attr_name, attr_value)

Set the attribute value. Attributes' ids and values follow the CSS specification.


style.setAttribute("font-size", "24pt");

setAttributes(attributes)

Set attributes values. Attributes' ids and values follow the CSS specification.


style.setAttributes("font-size:24pt;font-weight:bold;");

Supported properties

font

font-family

font-size

font-style

font-weight

margin [top, right, bottom, left]

margin-top

margin-bottom

margin-left

margin-right

padding

padding-top

padding-bottom

padding-left

padding-right

hanging-ident

text-align

text-decoration

text-ellipsis

vertical-align

color

background-color

border

border-top

border-top-style

border-top-color

border-top-width

border-bottom

border-bottom-style

border-bottom-color

border-bottom-width

border-left

border-left-style

border-left-color

border-left-width

border-right

border-right-style

border-right-color

border-right-width

display

overflow

float

text-wrap

width

max-width

min-width

height

page-break-after

column-break-after

line-break-after

page-break-before

column-break-before

line-break-before

page-break-inside

line-break-inside

size

position

left

top

right

bottom

transform

Supported transformations are: matrix, translateX, translateY, translate, rotate, scaleX, scaleY, scale, skewX, skewY and skew

transformOrigin

orphans

fill-empty-area

 

Non standard attributes and values

 

width-sym

This attribute contains a string. Columns with the same width-sym will be laid out with the same width.

layout-sym

This attribute is a string. Tables with the same layout-sym attribute will have the same layout for the width of the columns.

overflow

This attribute has the non standard value "shrink". The content of the node will be down scaled to fit given space.


style.setAttribute("overflow", "shrink");

overflow-shrink-max

This attibute set the maximal down scaling factor (like 0.6). 


style.setAttribute("overflow-shrink-max", "0.6");

text-decoration

This attribute can also contain the values "double-underline" or "double-strong-underline".


style.setAttribute("text-decoration", "underline");

border-style

This attribute can also contain the values "double" and "double-strong".


style.setAttribute("border-style", "double");

flexible-width

This attribute can contain the value "always" and is only used with columns. If, in a table, one or more columns have the attribute "flexible-widht", only those columns are enlarged to get the desired table width, untouching the others. Otherwise all columns are enlarged.

fill-empty-area

With this attribute you can fill the remaing space of your page with lines. Lines can be defined through the attribute, which is a string and contains the color, the style and the width of the line.

Style can be: solid, dash or dot.

Examples:


var style1 = stylesheet.addStyle("@page", "black solid 1");
var style2 = stylesheet.addStyle("@page", "green dash 0.5");

Report FAQ

How can I set the orientation of the page and the margins


// Set landscape orientation
styleSheet.addStyle("@page", "size: landscape");
// Page margins top, right, bottom, left
styleSheet.addStyle("@page", "margin: 20mm 20mm 20mm 25mm");

 

 

How can I set the size of the page


// Set page size
styleSheet.addStyle("@page", "size: A5");

 

How can I set the margins of page header and footer


styleSheet.addStyle("phead", "margin-bottom:2em");
styleSheet.addStyle("pfoot", "margin-top:2em");

 

How can I print the page number on the right of the page footer


document.getFooter().addFieldPageNr("alignright");
stylesheet.addStyle("pfoot", "text-align:right");

 

Can I print the total number of pages

No

 

I like a style implemented in a report of Banana Accounting, where can I get the used stylesheet?

In print preview export the report as html and look at the code. You will find the used styles.

 

Banana.SDecimal

The Banana.SDecimal is a static only class, with static method for high precision decimal calculation.

Static functions only

Banana.SDecimal is a class that provides static methods only. 

  • Instances of of Banana.SDecimal are not allowed
    • The class has not a constructor for Banana.SDecimal.
    • Using "new Banana.SDecimal(0)" is an error.
    • Calling the method using a variable for example "value.add("123") is an error.
  • Static functions take as arguments strings Numeric String (example "1234.56").
  • Most functions return a Numeric String (example "1234.56").

Numeric String (Numeric Javascript String)

A Numeric String, a normal Javascript String that contains only numeric data. 

  • Use Numeric String with the Banana.SDecimal methods to avoid the use of Javascript floating point arithmetic that is not suitable for accounting calculations due to the rounding differences. It is used instead of a Javascript Number.
  • The Banana.SDecimal method uses Numeric String as arguments and return values.
  • Numeric String are also referred as Internal Numeric Format (for example toInternalNumberFormat).

Characteristics of a Numeric String

  • Numeric Strings use only numeric characters, for example '10.00' or '-10'.
  • The point '.' is used as a decimal separator.
  • Thousand separator are not allowed
  • Negative numbers have a minus "-" sign preceding the number ("-1234.56").
  • An empty string is considered equal to zero. The following value are the same
  • Provide up to 34 digits of numeric precision.

 

Numeric String initialization examples 

If you need to instantiate a Numeric String Prior to using a variable simply assign an empty string.

var balance = ""; // empty Numeric String same as "0"
var balance = "0"; // same as ""
var balance = "1234";
var balance = "1234.00"; //same as "1234"
var balance = "1234.56"; // number with 2 decimals places
var balance = "1234.56789"; // number with 4 decimals places
var balance = "-1234"; //negative number
var balance = "-1234.00"; //negative number same as "-1234"
var balance = "1234.56789"; // negative number with 4 decimals places
// convert a string containing a numeric value in international format to a Numeric String format
var textAmount1 = Banana.Converter.toInternalNumberFormat("1'234,56", ","); 

Basic calculations

Use Banana.SDecimal methods for adding, dividing and subtracting Numeric Strings.

// sum '6.50+3.50' and use the default 2 decimal digits
var r = Banana.SDecimal.add('6.50', '3.50');   // return '10.00'

// divide '10/2' and use the default 2 decimal digits
var r = Banana.SDecimal.divide('10', '2');     // return '5.00'

// divide '10/2' and use 5 decimal digits
var r = Banana.SDecimal.divide('10', '2', {'decimals':5});     // return '5.00000'

Sum of two amounts 

Examples of Banana.SDecimal methods for adding two Numeric Strings.

// Example input text amounts
var textAmount1 = "1234.56";  // A valid number in string format
var textAmount2 = "-789.12";  // Another valid number in string format

// Perform the addition using Banana.SDecimal.add
var sum = Banana.SDecimal.add(textAmount1, textAmount2);

Convert two amounts from local number format and add

Prior to adding the amounts must be converted to a Numeric String.
Then you can use the Banana.SDecimal.add method.

// Example input text amounts
var textAmount1 = Banana.Converter.toInternalNumberFormat("1'234,56", ",");  // A valid number in local format
var textAmount2 = Banana.Converter.toInternalNumberFormat("-789,12", ",");   // Another valid number in local format

// Perform the addition using Banana.SDecimal.add
var sum = Banana.SDecimal.add(textAmount1, textAmount2);

Check if an amount is negative

if (Banana.SDecimal.sign('-789.12') < 0) {
  // amount is negative
}

Amounts values from Banana.document.table

Within the table, the value amounts and numeric columns are already in Numeric String format. 

  • You can pass the retrieved values "row.value("Opening");" to the Banana.SDecimal methods.

The example that calculates the total of debits and credits, and the balance of the account in the row "0" of the table.

function calculateBalanceTotal() {
    let accountsTable = Banana.document.table("Accounts"); // Reads from table Accounts
    let row = accountsTable.row(0); // take the first row (index 0) or the table
    let opening = row.value("Opening");  // row.value("column_name_xml") already returns the text in Banana.SDecimal format
    let debit = row.value("Debit");  // row.value("column_name_xml") already returns the text in Banana.SDecimal format
    let credit = row.value("Credit");  // row.value("column_name_xml") already returns the text in Banana.SDecimal format
    let total = Banana.SDecimal.subtract(debit, credit);
    let balance = Banana.SDecimal.add(total, opening);
    return balance;
}

Sum the balance column

Within the table, the value of the columns number and amounts are already returned in Numeric String format.
You can pass the value directly to the Banana.SDecimal methods.

The example sums all balances of normal accounts.

function calculateBalanceTotal() {

    // Get the "Accounts" table
    let accountsTable = Banana.document.table("Accounts");
    let totalBalance = ""; // instatiate a numeric string

    for (let i = 0; i < accountsTable.rowCount; i++) {
        let row = accountsTable.row(i);
        let account = row.value("Account");
        
        // Only rows with normal accounts (not cost centers or segments)
        if (account && !account.startsWith(".") && !account.startsWith(",") && !account.startsWith(";") && !account.startsWith(":")) {
           let balance = row.value("Balance"); // get the balance value already in SDecimal format
           totalBalance = Banana.SDecimal.add(totalBalance, balance); // Add the balance amounts
        }
    }
    return totalBalance;
}

 

Rounding context

Functions can be passed a rounding context that specify the rounding properties:

  • decimals is the number of decimal digits (default value is 2)
    • null returns the value unrounded.
    • '0' returns with no decimals.
    • '1' to '33' returns the value with the indicated number of decimals.
  • mode is the rounding mode (default value is HALF_UP)
    • Banana.SDecimal.HALF_UP the amount is rounded to the nearest. The 0.5 are rounded up.
    • Banana.SDecimal.HALF_EVEN the amount is rounded to the nearest. The 0.5 are rounded up or down based on the preceding digit.

If the rounding context is omitted no rounding is done.

Rounding context of the accounting file

All Banana document files have a rounding context that can be retrieved with the property Banana.document.rounding (see Banana.document).

Examples:

// no context
var r = Banana.SDecimal.divide('10', '3'); // return '3.3333333333333333333333333'

// with context
var context = {'decimals' : 4, 'mode' : Banana.SDecimal.HALF_UP};
var r = Banana.SDecimal.divide('10', '3', context);        // return '3.3333'
var r = Banana.SDecimal.divide('10', '3', {'decimals':0}); // return '3'

// use the rounding property (accounting file 2 decimals)
var r = Banana.SDecimal.divide('10', '3', Banana.document.rounding); // return '3.33'

Methods

Here are the list of all available methods of the SDecimal class. 

abs(value1, [, roundingContext])

Static method.
Returns the absolute value of value1 removing its sign. The result is optionally rounded based on the specified roundingContext.

Parameters:

  • value1 (string): The Numeric String whose absolute value is to be calculated.
  • roundingContext (optional): A rounding specification (e.g., number of decimal places). If provided, the result will be rounded accordingly.

Returns:

  • A Numeric String representing the absolute value of value1, optionally rounded.
var r = Banana.SDecimal.abs('-10') // return '10.00'

 add(value1, value2 [, roundingContext])

Static method.
Returns the sum of value1 and value2.

  • value1 and value2 are Numeric String.
  • return value is a Numeric String.
var r = Banana.SDecimal.add('6.50', '3.50'); // return '10.00'

compare(value1, value2)

Static method.
Parameters:

  • value1 and value2 are Numeric String.
  • return value is a Numeric String.

Returns an integer value:

  • 1 if value1 > value2
  • 0 if value1 = value2
  • -1 if value1 < value2
Banana.SDecimal.compare('3.50', '2'); // return '1'
Banana.SDecimal.compare('3.00', '3'); // return '0'

divide(value1, value2 [, roundingContext])

Static method.
Returns value1 divided by value2.

Parameters:

  • value1 and value2 are Numeric String.
  • return value is a Numeric String.
var r = Banana.SDecimal.divide('6', '3'); // return '2.00'

isZero(value)

Static method.
Returns a boolean

  • true if value is zero
  • false if value is not zero
var r = Banana.SDecimal.isZero('3.00'); // return 'false'

max(value1, value2 [, roundingContext])

Static method.
Returns the max between value1 and value2.

  • value1 and value2 are Numeric String.
  • return value is a Numeric String.
var r = Banana.SDecimal.max('6', '3'); // return '6.00'

min(value1, value2 [, roundingContext])

Static method.
Returns the min between value1 and value2.

  • value1 and value2 are Numeric String.
  • return value is a Numeric String.
var r = Banana.SDecimal.min('6', '3'); // return '3.00'

multiply(value1, value2 [, roundingContext])

Static method.
Returns value1 multiplied by value2.

  • value1 and value2 are Numeric String.
  • return value is a Numeric String.
var r = Banana.SDecimal.multiply('6', '3'); // return '18.00'

remainder(value1, value2 [, roundingContext])

Static method.
Divide value1 by value2 and returns the reminder.

  • value1 and value2 are Numeric String.
  • return value is a Numeric String.
var r = Banana.SDecimal.reminder('10', '3'); // return '1.00'

round(value1, [, roundingContext])

Static method.
Returns value1 round to the spcified rounding context.

  • value1 and value2 are Numeric String.
  • return value is a Numeric String.
var r = Banana.SDecimal.round('6.123456'); // no context no rounding 
r = Banana.SDecimal.round('6.123456', {'decimals':2}); // return '6.12'

roundNearest(value1, nearest, [, roundingContext])

Static method.
Returns value1 round to the specified minimal amount.

  • value1 and value2 are Numeric String.
  • return value is a Numeric String.
var r = Banana.SDecimal.roundNearest('6.17', '0.1'); // return '6.1'
r = Banana.SDecimal.roundNearest('6.17', '0.05', {'decimals':2}); // return '6.15'

invert(value, [, roundingContext])

Static method.
The invert function reverses the sign of a numeric value. If the input is positive, it returns the corresponding negative value. If the input is negative, it returns the corresponding positive value. The result is optionally rounded based on the provided roundingContext.

Parameters:

  • value (string): The Numeric string whose sign is to be inverted.
  • roundingContext (optional): A rounding specification (e.g., number of decimal places). If provided, the result will be rounded accordingly.

Returns:

  • A Numric String representing the value with its sign inverted, optionally rounded.
var a = Banana.SDecimal.invert('5'); //return '-5'
var b = Banana.SDecimal.invert('-2.50'); //return '2.50'

sign(value)

Static method.
Returns an integer value

  • 1 if value > 0
  • 0 if  value = 0
  • -1 if value < 0
var r = Banana.SDecimal.sign('-5'); // return '-1'

 subtract(value1, value2 [, roundingContext])

Static method.
Subtract value2 from value1 and returns the result.

  • value1 and value2 are Numeric String.
  • return value is a Numeric String.
var r = Banana.SDecimal.subtract('10', '3'); // return '7.00'

 

Locale conversion

To convert to and from the locale format use the Banana.Converter functions

  • Banana.Converter.toInternalNumberFormat(value [, decimals, convZero])
  • Banana.Converter.toLocaleNumberFormat(value [, decimalSeparator])
var sum = Banana.SDecimal.add('10000', '2000'); // return '12000.00'
var printValue = Banana.Converter.toLocaleNumberFormat(sum); // return "12'000.00"

 

Banana.Script

Banana.Script represents the interface to the script file and can be accessed through Banana.script. It is used to get the parameter values defined in the script. For example if you want to print out in a report the publishing date of the script.

Properties

Methods

getParamValue(paramName)

Return the value defined in the script file of the parameter paramName. Return an empty string or the internal default value if the parameter is not defined. Return the first found value, if the parameter is defined multiple times.



Banana.script.getParamValue('pubdate'); // returns for example '2016-05-11'

getParamValues(paramName)

Return all the values defined in the script file of the param paramName . Return an empty array if the parameter paramName is not defined.



// Script.js example:
// ...
// @authors = Pinco
// @authors = Pallino
// ...

Banana.script.getParamValues('authors'); // returns ['Pinco', 'Pallino']

getParamLocaleValue(paramName)

Return the localized value defined in the script file of the param paramName. Return an empty string the parameter is not defined.



// Script.js example:
// ...
// @description = English desciption
// @description.it = Descrizione italiana
// @description.de = German Beschreibung
 ...

Banana.script.getParamLocaleValue('description'); // returns 'Descrizione italiana' for a system running with the locale 'italian'.

getPath()

Return the path where the extension is located on the computer.



Banana.script.getPath(); // returns for example '/Users/banana.ch/.../ch.banana.application.invoice.default.sbaa'

Banana.Test

The Banana.Test class is used to run unit tests of Banana Extensions.

See also working with the Banana Extensions Test Framework.

Banana Extensiong TestFramework

The Banana Extensions Test Framework is like an usual Unit Test Framework.

Two methodologies are available:

  • Verify results 
    Through assert methods the user can verify some conditions, in case that a condition didn't meet the test fail and it is interrupted. 
    For example you verify that a method returns a determined value.

    Ex.: Test.assertIsEqual(totalVatAmount(), "5000.00");
     
  • Log results and compare them with previous results (expected results)
    Through the Banana.Test.Logger  methods, you can log test results. Test results are stored under the test/testresults folder. They will be compared at the end of the test with the expected results stored under the folder test/testexpected (results form previous tests), if any difference is found, the test is marked as failed and the differences showed to the user. 
    In this case you don't care about the exact value returned by a method, but you verify that the method returns the same value across different versions of the BananaApp or Banana Accounting.

    Ex.: Test.logger.addKeyValue("Total VAT amount", totalVatAmount());

Create a test case

To create a test case look at the example SampleExtensions/TestFramework.

Run a test case

You can run a test case in two ways (both available starting at Banana Accounting 9.0.4):

  • Through the Manage Apps dialog
    • Open the Manage Apps dialog
    • Select the Banana Extension to test
    • Click over 'Show details'
    • Click on the button 'Run test case'
       
  • Through the Command line
    • banana90.exe -cmd=runtestsapps -p1=path_to_testcase.js|folder
    • As parameter p1 you can specify the path to a test case file, or the path of a folder
    • In case of a folder all files in the folder and subfolders ending with test.js are run

Test case folder structure

This is the default test structure of a test case. All the files used for the test case are stored in a folder named test.

In the dialog Manage apps the button 'Run test case' button is showed only if the application find a file named test/<same_name_bananaextemsopm>.test.js.


ch.banana.script.bananaapp.js                # BananaApps
ch.banana.script.bananaapp2.js
...
test/
  ch.banana.script.bananaapp.test.js         # BananaApps Test Cases
  ch.banana.script.bananaapp2.test.js
  ...
  testcases/
    *.ac2                                    # ac2 files for the test cases
    ...
  testexpected/                              # Expected test results used for verifying the current results
    ch.banana.script.bananaapp.test/
      *.txt
    ch.banana.script.bananaapp2.test/
      *.txt
    ...  
  testresults/                               # Current test results
    ch.banana.script.bananaapp.test/
      *.txt
    ch.banana.script.bananaapp2.test/
      *.txt
    ...  

Logger output format

The results are saved in .txt with the Latex format. Yes, it means that you can convert the output files in pdf, and look at the results without the log structure commands.

Short example

For a complete example look a SampleExtensions/TestFramework.


// @id = ch.banana.script.bananaapp.test
// @api = 1.0
// @pubdate = 2018-03-30
// @publisher = Banana.ch SA
// @description = Simple test case
// @task = app.command
// @doctype = *.*
// @docproperties = 
// @outputformat = none
// @inputdataform = none
// @timeout = -1
// Register test case to be executed
Test.registerTestCase(new TestLoggerSimpleExample());
// Here we define the class, the name of the class is not important
function TestLoggerSimpleExample() {
}
// Test method, every method starting with 'test' will be automatically executed
TestLoggerSimpleExample.prototype.testOk = function() {
   Test.logger.addText("This test will pass :-)");
   Test.assert(true);
}

The Test object

When a script is run as a test case, a global object named Test is exposed to the script. This object defines properties and methods for executing the test case.


Test.logger.addKeyValue("count", 4);
Test.assert(true); 

Properties

logger

The property logger returns an object of type Banana.Test.Logger that permits to log test results. If the script is not run though the Banana Apps functionality this object is null.


var testLogger = Test.logger;
testLogger.addKeyValue("count", 4);

Methods

assert(condition, message)

This method verifies if the condition is true. If the condition is true the test continues, else an exception is thrown and the message message is inserted in the test results.


Test.assert(true, "This test will pass");

assertEndsWidth(string, endString)

This method verifies if text string ends with the text endString. If the condition is true the test continues, else an exception is thrown and a fatal error is inserted in the test results.


Test.assertEndsWith("This string ends with the text", "the text");

assertIsEqual(actual, expected)

This method verifies if actual equal to expected. If the condition is true the test continues, else an exception is thrown and a fatal error is inserted in the test results.


Test.assertIsEqual("Those strings are equal", "Those strings are equal");

assertGreaterThan(actual, expected)

This method verifies if actual is greather than expected. If the condition is true the test continues, else an exception is thrown and a fatal error is inserted in the test results.


Test.assertGreaterThan(10, 8);

assertGreaterThanOrEqual(actual, expected)

This method verifies if actual is greather than or equal to expected. If the condition is true the test continues, else an exception is thrown and a fatal error is inserted in the test results.


Test.assertGreaterThanOrEqual(8, 8);

assertLessThan(actual, expected)

This method verifies if actual less than expected. If the condition is true the test continues, else an exception is thrown and a fatal error is inserted in the test results.


Test.assertLessThan(8, 10);

assertLessThanOrEqual(actual, expected)

This method verifies if actual less than or equal to expected. If the condition is true the test continues, else an exception is thrown and a fatal error is inserted in the test results.


Test.assertLessThanOrEqual(10, 10);

assertMatchRegExp(string, pattern)

This method verifies if string math the regula expression defined by pattern. If the condition is true the test continues, else an exception is thrown and a fatal error is inserted in the test results.


Test.assertMatchRegExp("This string match the regual expression", /match/);

assertStartsWith(string, startString)

This method verifies if text string starts with the text startString. If the condition is true the test continues, else an exception is thrown and a fatal error is inserted in the test results.


Test.assertStartsWith("This string start with the text", "This string");

closeDocument(document)

Close a document previously opened for testing. Only documents opened via Banana.application.openDocument can be closed. Document opened during tests have to be closed before the test ends.


let testDoc = Banana.application.openDocument("testfile.ac2");
// Do some tests on testDoc
Test.closeDocument(testDoc);

registerTestCase(testCase)

This method register a testCase (an object) to be run as test.


// Register test case to be executed
Test.registerTestCase(new TestLoggerSimpleExample());

setDocument(document)

Set the current document returned by Banana.document.


let testDoc = Banana.application.openDocument("testfile.ac2");
// Do some tests on testDoc
Test.setDocument(testDoc);
Test.closeDocument(testDoc);

setTableValue(tableName, rowNr, columnName, value)

Set the value in table tableName, row rowNr and column columnName. The value is a string, and follow the internal format for numbers, dates, times and boolean.


let testDoc = Banana.application.openDocument("testfile.ac2");
Test.setDocument(testDoc);
Test.setTableValue("Invoices", 3, "Description", "Test Invoice 3");
Test.setTableValue("Invoices", 3, "Date", "2023-09-26");
Test.setTableValue("Items", 12, "UnitPrice", "1200.50");
Test.closeDocument(testDoc);

Banana.Test.Logger

The class Banana.Test.Logger contains methods to log test results.

Methods

addSection(key)

This method inserts a new section named key in the test results. A section is like a chapter 1. A section ends at the end of the test or when the method addSection is called again.

addSubSection(key)

This method inserts a new subsection named key in the test results. A section is like a chapter 1.1. A subsection ends at the end of the test or when the methods addSection or addSubSection are called again.

addSubSubSection(key)

This method inserts a new subsubsection named key in the test results. A section is like a chapter 1.1.1. A subsubsection ends at the end of the test or when the methods addSection, addSubSection or addSubSubSection are called again.

addComment(key)

This method inserts a comment in the test results. Test comments are discarded when comparing with the expected test results.

addCsv(key, table [, columns, separator, comment])

This method inserts the content of a csv text (comma separated values) in the test results.

The optional argument columns let you specify the subset of columns to output and in which order.
The optional argument separator if defined is used as the value's separator. If it is not defined the programm automatically determines the separator from one of '\t' (tabulator), ',' (comma) and ';' (semicolon).



// This output all columns
Test.logger.addTable("This is a table", Banana.document, columns);
// This output only the columns Date, Description and Amount 
Test.logger.addTable("This is a table", Banana.document, ["Date", "Description", "Amount"]);

addInfo(key, value)

This method inserts an information in the test results. Test informations are discarded when comparing with the expected test results. Compared to addComment' the key/value information is printed in case you publish the latex result as a pdf.



Test.logger.addInfo("Current date", new Date().toLocaleDateString());

addFatalError(key)

This method inserts a fatal error in the test. If a fatal error is inserted, event in case the results are identical to the expected results, the test fails, and the error message reported to the test differences.



Test.logger.addFatalError("This is a fatal error message");

addJson(key, jsonString [, comment])

This method inserts a json string in the test results. The json string is formatted with identation and the formatted string outputted line by line. If the jsonString contains 'carriage return' characters, then it will be outputted as it is. If the string is not a valid json, the string is outputted as it is.



var obj = {
   'count': 100,
   'color': "yellow"
};
Test.logger.addJsonValue("Param", JSON.stringify(obj));

addKeyValue(key, value [, comment])

This method inserts a test value in form of key and value. The parameter value is of type string.



Test.logger.addKeyValue("Row count", Banana.document.table("Transactions").rowCount);

addPageBreak()

This method inserts a page break. Page Breaks are discarded when comparing with the expected test results. They are just useful when the output is converted to a pdf file for inspecting visually the results.

Since Banana 9.0.4

addRawText(text [, insertEndl])

This method inserts a raw string in the test results without any modification or cleaning.

The optional parameter insertEndl defaults to true. If true an endl in inserted after the text.

addReport(key, report [, comment])

This method inserts the content of a Banana.Report object in the test results. Only the text elements are inserted, not the element's styles.



var report = Banana.Report.newReport("Report title");
report.addParagraph("Hello World !!!", "styleHelloWorld");
Test.logger.addReport("This is a report", report);

addTable(key, table [, columns, comment])

This method inserts the content of a Banana.Table object in the test results.

The optional argument columns let you specify the subset of columns to output and in whitch order.



// This output all columns
Test.logger.addTable("This is a table", Banana.document, columns);
// This output only the columns Date, Description and Amount 
Test.logger.addTable("This is a table", Banana.document, ["Date", "Description", "Amount"]);

addText(key)

This method inserts a simple string in the test results. 

addXml(key, xmlString [, comment])

This method inserts an xml string in the test results. The xml string will be formatted with identation and the formatted string outputted line by line. If the xmlString contains 'carriage return' characters, then it will be outputted as it is. If the string is not a valid xml, the string is outputted as it is.



var xml =
   "<note>" +
      "<to>Pinco</to>" +
      "<from>Pallino</from>" +
      "<heading>Reminder</heading>" +
      "<body>Don't forget me this weekend!</body>" +
   "</note>";
Test.logger.addXmlValue("This is a xml value", xml);

getElapsedTime()

This method returns the elapsed test execution time in milliseconds.

newLogger(logname)

This method returns a new logger, results are written in a separated log file named logname. With this methods you can split test results over several files.

If you have a lot of test results it is advised to split the results over more folder and files. This makes it easy to verify the differences between tests. 

As a generale rule, if you feed the test with two or more *.ac2 files, split the results in separate files.



Test.logger.addText("This test split the results over more files and folder");

// Write results in a new file called testresults 
var testLogger = Test.logger.newLogger("testresults");
testLogger.addText("This text will be written in file testresults.txt");
testLogger.close();

// Write results in a new folder called testgroup
var groupLogger = Test.logger.newGroupLogger("testgroup");

// Write results in a new file called testgroup/testresults1
var test1Logger = groupLogger.newLogger("testresults1");
test1Logger.addText("This text will be written in file testgroup/testresults1.txt");
test1Logger.close();

// Write results in a new file called testgroup/testresults2
var test2Logger = groupLogger.newLogger("testresults2");
test1Logger.addText("This text will be written in file testgroup/testresults2.txt")
test2Logger.close();

groupLogger.close();

newGoupLogger(groupname)

This method returns a new logger, results are written in a separated folder named groupname. With this methods you can split test results over several folders.

If you have a lot of test resutls it is advised to split the results over more folder and files. This makes it easy to verify the differences between tests.

close()

Close the logger for writting and free the reserved system resources (handle, ,memory, ...). This method shold be called for every new logger created with the methods newLogger and newGroupLogger.

Reserved methods

Those methods are used by the BananaApps Test Framework, and should not be directly used.

addTestInfo(key, value)

This method is called automatically by the framework to insert in a test info value like the test name, the running date and time, ...

addTestBegin(key [, comment])

This method is called automatically by the framework to insert in the log file an indication when a test method is started. 

addTestEnd()

This method is called automatically by the framework to insert in the log file an indication when a test method is finished. The framework will also automatically insert information about the elapsed time. 

addTestCaseBegin(key [, comment])

This method is called automatically by the framework to insert in the log file an indication when a test case is started.

addTestCaseEnd()

This method is called automatically by the framework to insert in the log file an indication when a test case is finished. The framework will also automatically insert an information about the elapsed time. 

Banana.Translations

The Banana.Translations class is used to access translators

Translators let you translate strings to languages other than the application's language.

For a description how to internationalise your extension see the page Extension's Translations


// Exemple for function QT_TRANSLATE_NOOP
var myReportTexts = {};
myReportTexts.account_card = QT_TRANSLATE_NOOP("MyReport", "Account card"); // Mark text for translation
// NB: The variable myReportTexts.account_card contains the source code string "Account card"
// You need a Banana.Translator object to translate it in the desired language

// Get translator for the document's language
var documentLanguage = "en"; //default
if (Banana.document) {
    documentLanguage = Banana.document.locale.substring(0,2);
}
var docTranslator = Banana.Translations.getTranslator(documentLanguage, "MyReport");

// Translate to the document's language
var myReportTranslatedText = docTranslator.tr(myReportTexts.account_card);

Methods

getTranslator(locale, context)

Returns a translator for the given local and context.

If no translation for the locale is found, the returned translator is not valid (i.e.: translator.valid returns false). A not valid translator returns the text untranslated as it is in the source code.


var myReportTexts = {};
myReportTexts.account_cards = QT_TRANSLATE_NOOP("MyReport", "Account card");
             
// Translate to Italian
var trIt = Banana.Translations.getTranslator("it", "MyReport");
var textIt = itTr.tr(myReportTexts.account_cards);

translate(context, text, disambiguation, n)

Translate a string in the language of the application in the specified context.


var myReportTexts = {};
myReportTexts.account_cards = QT_TRANSLATE_NOOP("MyReport", "Account card");
             
// Translate to the application's language
var text = Banana.Translations.translate("MyReport", myReportTexts.account_cards);

Banana.Translations.Translator

The class Banana.Translations.Translator let you translate strings.

Properties

context

Returns the context of the translator.

language

Returns the language of the translator.

valid

Returns true if the translator is valid.

An invalid translator simply returns the text untranslated as written in the source code.

Methods

tr(text [, disambiguation , n])

Translate a string in the language and context of the translator


// Get translator for the document's language
var documentLanguage = "en"; //default
if (Banana.document) {
    documentLanguage = Banana.document.locale.substring(0,2);
}
var docTranslator = Banana.Translations.getTranslator(documentLanguage, "MyReport");

// Translate to the document's language
var myReportTranslatedText = docTranslator.tr(myReportTexts.account_card);

translate(context, text [, disambiguation , n])

Translate a string in the language of the translator in the specified context.


// Get translator for the document's language
var documentLanguage = "en"; //default
if (Banana.document) {
    documentLanguage = Banana.document.locale.substring(0,2);
}
var docTranslator = Banana.Translations.getTranslator(documentLanguage, "MyReport");

// Translate to the document's language
var myReportTranslatedText = docTranslator.translate("MyReport", myReportTexts.account_card);

Banana.Ui

This class Banana.Ui contains methods to interact with user interface.

Add Message 

You can display information to the user by using the following functions:

Simple Display and Input 

For simple display and input of data from the user you can use the Banana.Ui Methods likes:

  • showText()
    Show the given text in a dialog with the given title.
  • showQuestion()
    how the user a question dialog with Yes and No buttons.
  • getText()
    Show the user a dialog asking to insert a text.
  • getDouble()
    Show the user a dialog asking to insert a double.
  • getItem()
    Show the user a combo box dialog asking to select an item from a list. 

Structured data input

The openPropertyEditor() function create a structured dialog for entering data. 

It is particularity useful for letting the user customize the extension. 

Creating Widgets

With QT Creator you can design any kind of widget and use it in the extension to visualize o get data from the user.

 

 

 

Banana.Ui Methods

This class Banana.Ui contains methods to interact with user interface.

createPropertyEditor(title, params, [dialogId])

Create a dialog to set given params. To display the dialog use the method exec(). To get the modified parameters use the method getParams(). 
It used in combination of the openPropertyEditor.

For more information on how tu use see:

Public slots:

  • void addCustomCommand(functionName, commandLabel)
    //allows to call a function of the script from a command in the dialog
  • void addImportCommand()
    //allows to import the extension's settings from other files
  • QJSValue getParams()
    //returns the params of the dialog
  • void setParams(QSJValue params)
    //allows to set the params of the dialog

 

createUi(uiFilePath)

Read the file uiFilepath and return an object representing the dialog. The uiFileName has to be in the same directory as the running script. You can also load a ui file from the table documents with the prefix 'documents:', ex.: 'documents:calculator.ui', For details and examples see Script dialogs or the tutorial JavaScript Tutorial 1.

Every widget defined in the ui file is exposed to the script environment and you can interact with them like in c++ code. You find further details under Banana.Ui.Widget.

If an error occurred undefined is returned.

Example:


@includejs = ch.banana.calculator.dialog.js;  // Define the class Calculator
                                              // that control the .ui file
...
var calculatorUi = Banana.Ui.createUi("ch.banana.calculator.dialog.ui");
var calcJs = new Calculator(calculatorUi); 
Banana.application.progressBar.pause();    // Pause wait cursor
calclatorUi.exec();                        // Show the dialog
Banana.application.progressBar.resume();   // Restart wait cursor

getDouble(title, label [, value , min, max, decimals])

Show the user a dialog asking to insert a double. Return the inserted double or undefined if the user clicked cancel.


var a = Banana.Ui.getDouble("Title text", "Label text");
var b = Banana.Ui.getDouble("Title text", "Label text", "10.0");

getInt(title, label [, value, min, max, steps])

Show the user a dialog asking to insert an integer. Return the inserted integer or undefined if the user clicked cancel.


var a = Banana.Ui.getInt("Title text", "Label text");
var b = Banana.Ui.getInt("Title text", "Label text", "5", "1", "10","1");

getItem(title, label, items [, current, editable])

Show the user a combo box dialog asking to select an item from a list. Return the selected item or undefined if the user clicked cancel.


var value = Banana.Ui.getItem("Input", "Choose a value", ["a","b","c","d","e"], 2, false);

getItems(title, label, items [, selectedItems])

Show the user a list dialog asking to select one or more items from a list. Return the selected items or undefined if the user clicked cancel.


var value = Banana.Ui.getItems("Input", "Choose one or more values", ["a","b","c","d","e"], ["b","c"]);

Since: Banana Experimental 9.1.0

getPeriod(title, startDate, endDate [, selectionStartDate, selectionEndDate, selectionChecked])

Show the user a dialog asking to select a period like the tab Period. Return an object with the atributes 'startDate', 'endDate' and 'hasSelection' or undefined if the user clicked cancel. Date values are in the format "YYYY-MM-DD".


var period = Banana.Ui.getPeriod("Title text", "2016-01-01", "2016-12-31");
if (period) {
    var selectedStartDate = period.startDate; // return the start date of the selected period
    var selectedEndDate = period.endDate; // return the end date of the selected period
}

getText(title, label [, text])

Show the user a dialog asking to insert a text. Return the inserted text or undefined if the user clicked cancel.


var text = Banana.Ui.getText("Title text","Label text");

openPropertyEditor(title, params, [dialogId])

For more information:

Show the user a dialog asking to set given params.

Return the modified params or undefined if the user clicked cancel.

 

banana setting dialog

showHelp(uiFileName)

Show the help of a dialog. The help is loaded from the Banana.ch web site.

showInformation(title, msg)

Show the user an information dialog.


Banana.Ui.showInformation("Information", 'Insert here the text of the information.');

showQuestion(title, question)

Show the user a question dialog with Yes and No buttons. Return true if the user clicked Yes, otherwise false.


var answer = Banana.Ui.showQuestion("Question title", "Insert here the text of the question");

showText(text)

Show the given text in a dialog. The text can be plain text of html and span over multiple lines. If the text is in html the title is taken form the html. The dialog enables the user to save the content in the formats html, pdf, odf and txt.
The use of pixels to set the font sizes is not supported, the text is not rendered properly.


// Normal text
Banana.Ui.showText("Insert here the text.");
// Html text
Banana.Ui.showText('<html><header><title>This is title</title></header><body>Hello world</body></html>');

showText(title, text)

This is an overloaded function.

Show the given text in a dialog with the given title. The text can be plain text of html and span over multiple lines. The dialog enables the user to save the content in the formats html, pdf, odf and txt.

showText(title, text, options)

This is an overloaded function.

Show the given text in a dialog with the given title. The text can be plain text of html and span over multiple lines. The dialog enables the user to save the content in the formats html, pdf, odf and txt.

Through the object options it is possible to set the following additional parameters:

  • codecName: the name of the codec to be used in case the content will be saved as txt file. Default is 'UTF-8'
  • outputFileName: the file name without path to be used in case the content will be saved. The path is current open document path or the user's document path.

var options = {
   'codecName' : "latin1", // Default is UTF-8
   'outputFileName' : "prova.txt"
}
Banana.Ui.showText("Title", "some text...", options);

Extension Widget Ui Example

This is an example dialog to search in the whole accounting a text.

This example is also found in the tutorial file JavaScript Tutorial 1 under the table documents at code 742.

The dialog:

All the properties and public slots of the widgets in the dialogs will be accessible from the script.

Example UI code

The script file ch.banana.scripts.find.js 

  • Display the the Ui Widget using the Banana.Ui.createUi().
  • Get the text from the user-
  • Use the function searchInTables() 
  • Notify the user when the text has been found with the table.addMessage() function

 

/**
 * This example search a text in all the tables of the document,
 * and show the matches in the messages pane.
 */
// @id = ch.banana.scripts.find
// @version = 1.3
// @date = 2019-12-06
// @publisher = Banana.ch SA
// @description = Find in whole accounting
// @description.it = Cerca in tutta la contabilità
// @description.de = Suchen in der gesamten Buchhaltung
// @description.fr = Chercher dans toute la comptabilité
// @task = app.command
// @doctype = nodocument
// @inputdatasource = none
// @timeout = -1

/**
 * param values are loaded from Banana.document, edited through dialog and saved to Banana.document
 * This array object is like a map (associative array) i.e. "key":"value", see initParam()
 * Examples of keys: searchText, wholeText, ...
 */
var param = {};

/** Dialog's functions declaration */
var dialog = Banana.Ui.createUi("ch.banana.scripts.find.ui"); // use "documents:742.ui" in template file

/** Dialog Objects declaration */
var findNextButton = dialog.findChild('findNextButton');
var helpButton = dialog.findChild('helpButton');
var closeButton = dialog.findChild('closeButton');
var searchTextLineEdit = dialog.findChild('searchTextLineEdit');
var matchCaseCheckBox = dialog.findChild('matchCaseCheckBox');
var wholeTextCheckBox = dialog.findChild('wholeTextCheckBox');


dialog.checkdata = function () {
    var valid = true;

    if (searchTextLineEdit.text.length <= 0) {
        Banana.Ui.showInformation("Error", "Search text can't be empty");
        valid = false;
    }

    if (valid) {
        dialog.accept();
    }
};

dialog.showHelp = function () {
    Banana.Ui.showHelp("ch.banana.script.find");
};

dialog.closeDialog = function () {
    dialog.close();
};

/** Dialog's events declaration */
findNextButton.clicked.connect(dialog, dialog.checkdata);
helpButton.clicked.connect(dialog, dialog.showHelp);
closeButton.clicked.connect(dialog, dialog.closeDialog);

/** Main function */
function exec(inData) {

    //calls dialog
    // var rtnDialog = true;
    var rtnDialog = dialogExec();

    //search text in the whole accounting
    if (rtnDialog && Banana.document) {
        Banana.document.clearMessages();
        searchInTables();
    }
}

/** Show the dialog and set the parameters */
function dialogExec() {
    // Read saved script settings
    initParam();
    if (Banana.document) {
        var data = Banana.document.getScriptSettings();
        if (data.length > 0) {
            param = JSON.parse(data);
        }
    }

    // Text at cursor position
    var cursor = Banana.document.cursor;
    var columnName = cursor.tableName === 'Documents' && cursor.columnName == 'Attachments' ? 'Description' : cursor.columnName;
    param["searchText"] = Banana.document.value(cursor.tableName,cursor.rowNr,columnName);
    searchTextLineEdit.text = param["searchText"];
    // Set dialog parameters
    if (param["matchCase"] == "true")
        matchCaseCheckBox.checked = true;
    else
        matchCaseCheckBox.checked = false;
    if (param["wholeText"] == "true")
        wholeTextCheckBox.checked = true;
    else
        wholeTextCheckBox.checked = false;

    Banana.application.progressBar.pause();
    var dlgResult = dialog.exec();
    Banana.application.progressBar.resume();

    if (dlgResult !== 1)
        return false;

    // Read dialog parameters
    param["searchText"] = searchTextLineEdit.text;
    if (matchCaseCheckBox.checked)
        param["matchCase"] = "true";
    else
        param["matchCase"] = "false";
    if (wholeTextCheckBox.checked)
        param["wholeText"] = "true";
    else
        param["wholeText"] = "false";

    // Save script settings
    var paramString = JSON.stringify(param);
    var value = Banana.document.setScriptSettings(paramString);

    return true;
}

/** Initialize dialog values with default values */
function initParam() {
    param = {
        "searchText": "",
        "matchCase": "false",
        "wholeText": "false"
    };
}

/** Search a text in the accounting's tables */
function searchInTables() {
    var searchText = param["searchText"];
    if (param["matchCase"] === "false")
        searchText = searchText.toLowerCase();
    var tables = Banana.document.tableNames;
    // Tables
    for (var t=0; t < tables.length; t++) {
        var table = Banana.document.table(tables[t]);
        var columns = table.columnNames;
        // Rows
        for (var r=0; r < table.rowCount; r++) {
            // Columns
            for (var c=0; c < columns.length; c++) {
                var textFound = false;
                var text = table.value(r, columns[c]);
                if (param["matchCase"] === "false")
                    text = text.toLowerCase();
                // Find text
                if (param["wholeText"] === "true") {
                    if (text === searchText)
                        textFound = true;
                } else {
                    if (text.indexOf(searchText) >= 0)
                        textFound = true;
                }
                // Show message
                if (textFound) {
                    table.addMessage("Text \"" + param["searchText"] +
                        "\" found in \"" + table.value(r, columns[c]) + "\"", r, columns[c]);
                }
            }
        }
    }
}

 

 

UI file 

The UI file has been created using QT Creator 

  • Install Qt Creator
  • Draw the dialog with Qt Creator
  • Save the dialog in a .ui file,
  • Load the .ui file in the script through the function Banana.Ui.createUi()

The .ui file: ch.banana.scripts.find.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>DlgFind</class>
 <widget class="QDialog" name="DlgFind">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>438</width>
    <height>193</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Find</string>
  </property>
  <layout class="QVBoxLayout" name="verticalLayout_2">
   <item>
    <layout class="QGridLayout" name="gridLayout">
     <property name="horizontalSpacing">
      <number>40</number>
     </property>
     <item row="0" column="0">
      <widget class="QLabel" name="searchTextLabel">
       <property name="text">
        <string>Search &amp;text</string>
       </property>
      </widget>
     </item>
     <item row="0" column="1">
      <widget class="QLineEdit" name="searchTextLineEdit"/>
     </item>
    </layout>
   </item>
   <item>
    <widget class="QGroupBox" name="groupBox">
     <property name="title">
      <string>Options</string>
     </property>
     <property name="flat">
      <bool>false</bool>
     </property>
     <property name="checkable">
      <bool>false</bool>
     </property>
     <layout class="QVBoxLayout" name="verticalLayout">
      <item>
       <widget class="QCheckBox" name="matchCaseCheckBox">
        <property name="text">
         <string>&amp;Match case</string>
        </property>
       </widget>
      </item>
      <item>
       <widget class="QCheckBox" name="wholeTextCheckBox">
        <property name="text">
         <string>&amp;Whole text</string>
        </property>
       </widget>
      </item>
     </layout>
    </widget>
   </item>
   <item>
    <spacer name="verticalSpacer">
     <property name="orientation">
      <enum>Qt::Vertical</enum>
     </property>
     <property name="sizeHint" stdset="0">
      <size>
       <width>20</width>
       <height>15</height>
      </size>
     </property>
    </spacer>
   </item>
   <item>
    <layout class="QHBoxLayout" name="horizontalLayout">
     <item>
      <spacer name="horizontalSpacer">
       <property name="orientation">
        <enum>Qt::Horizontal</enum>
       </property>
       <property name="sizeHint" stdset="0">
        <size>
         <width>80</width>
         <height>20</height>
        </size>
       </property>
      </spacer>
     </item>
     <item>
      <widget class="QPushButton" name="findNextButton">
       <property name="text">
        <string>&amp;Find</string>
       </property>
      </widget>
     </item>
     <item>
      <widget class="QPushButton" name="helpButton">
       <property name="text">
        <string>Help</string>
       </property>
      </widget>
     </item>
     <item>
      <widget class="QPushButton" name="closeButton">
       <property name="text">
        <string>Close</string>
       </property>
      </widget>
     </item>
    </layout>
   </item>
  </layout>
 </widget>
 <tabstops>
  <tabstop>matchCaseCheckBox</tabstop>
  <tabstop>findNextButton</tabstop>
 </tabstops>
 <resources/>
 <connections/>
</ui>

Banana.Ui.Widget

Every widget defined in a ui file is exposed to the script engine. 

You can get a particular widget through it's name and the method findChild:

For every widget you have access to:

  • properties
  • public slots
  • signals

If a method is not defined as public slot in c++ qt api,  it will not be available to the script engine. Some widgets are wrapped so that you have access to additional methods, see next chapter Wrapped widgets.

For complete examples see the page Script dialogs or the tutorial JavaScript Tutorial 1 (documents 740 'QTableWidget interaction' and 742 'Find dialog').

Example:



// Load ui file 
var dialog = Banana.Ui.createUi("ch.banana.scripts.find.ui"); 

// Get the label/widget through it's name
var statusLabel = dialog.findChild('statusLabel');

// Set the text of label/widget
statusLabel.setText('Hello!');

// Connect button box accepted signal to the dialog close method
var buttonBox = dialog.findChild("buttonBox");
buttonBox.accepted.connect(function() {dialog.close();});

Banana.application.progressBar.pause();  // Pause wait cursor 
dialog.exec();                           // Show the dialog 
Banana.application.progressBar.resume(); // Restart wait cursor

Signals

You have three ways to connect signals to methods.



// Method1: Connect a signal to a function
function findNext() {
   Banana.console.log('find next');
} 
findNextButton.clicked.connect(findNext);

// Method2: Connect a signal to an object method
var object = {}
object.onClicked = function() { 
   Banana.console.log('clicked');
};
findNextButton.clicked.connect(object, object. onClicked);

// Method3: Connect a signal to an inline function 
findNextButton.clicked.connect(
   function(){Banana.console.log('clicked');}
);

 

 Wrapped widgets

The widgets listed below have been wrapped to let you use additional methods that are not exposed to the script engine because they are not declared as public slots.

Hereby only the additional available methods are listed. Their usage and parameters correspond to the c++ counterpart.

QObject

Methods:



findChild(name)

QComboxBox

Methods:



addItem(text)
addItems(texts)
count()
insertItem(index, text)
insertItems(index, texts)
removeItem(index)

QTableWidget

Since: Banana Experimental 9.1.0

Properties:



currentColumn
currentRow

Methods:



currentItem()
item(row, column)
setColumnWidth(column, width)
setEditTriggers(triggerFlag)
setHorizontalHeaderLabels(labels)
setColumnCount(columns)
setCurrentCell(row, column)
setRowCount(rows)

QTableWidgetItem

Properties:



background
checkState
flags
foreground
text

Extensions Dialog PropertyEditor

The Dialog Property Editor allows to create a flexible dialog that allows the user to enter data.
The structure and content of the Dialog is defined with a JSon.

It is useful for extensions settings and in particulary in the  settingsDialog() function.

 

 

createPropertyEditor(title, params, [dialogId])

Create a dialog to set given params. To display the dialog use the method exec(). To get the modified parameters use the method getParams(). The structure of params is described in the openPropertyEditor paragraph.

Public slots:

  • void addCustomCommand(functionName, commandLabel)
    //allows to call a function of the script from a command in the dialog
  • void addImportCommand()
    //allows to import the extension's settings from other files
  • QJSValue getParams()
    //returns the params of the dialog
  • void setParams(QSJValue params)
    //allows to set the params of the dialog

function exec(inData, options) {
    let params = {};
    params.version = '1.0';
    params.data = [];
    let editor = Banana.Ui.createPropertyEditor('Dialog Title', params, 'pageAnchor');
    let param = {};
    param.name = 'header';
    param.title = 'header';
    param.type = 'string';
    param.value = 'this is an example of header';
    param.defaultvalue = 'my header';
    param.readValue = function () {
        param.header = this.value;
    }
    params.data.push(param);
    editor.setParams(params);
    editor.addImportCommand();
    editor.addCustomCommand("functionName1", "label pushbutton 1");
    editor.addCustomCommand("functionName2", "label pushbutton 2");
    let rtnValue = editor.exec();
    if (parseInt(rtnValue) === 1) {
        // Read data from dialog
        params = editor.getParams();
        Banana.console.debug(JSON.stringify(params));
    }
}
function functionName1(params) {
    Banana.console.debug("called functionName1");
    Banana.console.debug(JSON.stringify(params));
    for (var i = 0; i < params.data.length; i++) {
        if (params.data[i].name === 'header') {
            params.data[i].value = 'hello world';
        }
    }
    return params;
}
function functionName2(params) {
    Banana.console.debug("called functionName2");
    Banana.console.debug(JSON.stringify(params));
    return params;
}

 

 

openPropertyEditor(title, params, [dialogId])

 

Show the user a dialog asking to set given params.

Return the modified params or undefined if the user clicked cancel.
See Invoice Extension containing examples with this method.

Params is an object containing:

  • version
    A string with a version number. Required '1.0';
  • data
    An array containing the elements of the property editors.

Element properties of the array

  • name: param's key (unique id)
  • title: param's title, which appears in the left column "property"
  • parentObject (optional):
    • Should be the name (id) of the parent's element.
    • It let you define a tree structure, as the following one:

banana setting dialog

see the structure example on GitHub

  • type (optional):
    • string (default)
      A single line of text
    • multilinestring
      A text area with multiple lines
    • bool 
      checkbox for setting true/false value
    • date
      calendar popup for date selection
    • combobox
      Use the property items for setting a list of values
    • color
      Color dialog box for color selection
    • font
      Combobox that lets the user select a font family
       
  • value: the value, which appears in the right column "value". For type bool: true/false, for type string and multilinestring a text. For type combox the selected text.
  • defaultvalue (optional): value used by Restore Defaults button. If the param has this property the button Restore Defaults will be available.
  • items:  array of strings. Used by type combobox.
  • collapse (optional): true/false. By default the dialog expand all items. If collapse is true the item will not be expanded.
  • enabled (optional): true/false. If false the value will appears grey and the user cannot change the value (default: true)
  • editable (optional): true/false. If false the user cannot change the value, available only for string and multilinestring types (default: true)
  • tooltip (optional): text which appears over the item without clicking on the item
  • errorId (optional): error id that identify an error. The error id is used to link the error to the corresponding help page
  • errorMsg (optional): error string that describe an error. If a parameter has this property set, the label will be show in red and the error showed on the right of the name.

Validating data

Before accepting data you can validate them using the method validateParams(). If this method returns false the dialog will prevent to close.


function validateParams(params) {
   for (var i = 0; i <  params.data.length; i++) {
       if (params.data[i].value != "myValue") {
          params.data[i].errorMsg = "this object is not valid";
          return false;
       }
   }
   return true;
}

Example code openPropertyEditor


var paramList = {};
paramList.version = '1.0';
paramList.data = [];
// bool
var param = {};
param.name = 'print_header';
param.title = 'print header';
param.type = 'bool';
param.value = true;
param.readValue = function() {
  param.print_header = this.value;
}
paramList.data.push(param);
// combobox
var param = {};
param.name = 'methodId';
param.title = 'Method ID';
param.type = 'combobox';
param.value = 'item01';
param.items = ['item01', 'item02', 'item03'];
param.readValue = function () {
  param.methodId= this.value;
}
paramList.data.push(param);
var dialogTitle = 'Settings';
var pageAnchor = 'dlgSettings';
if (Banana.Ui.openPropertyEditor(dialogTitle, paramList, pageAnchor))) {
   for (var i = 0; i < paramList.data.length; i++) {
      // Read values to param (through the readValue function)
      paramList.data[i].readValue();
   }

 

 

 

Banana.Xml

The Banana.Xml class is used to parse and access xml data.​

Since: Banana Accounting 9.0.5

Introduction

The API Banana.Xml and Banana.Xml.XmlElement implement a subset of the DOM Document Object Model interface.  The most used properties and methods are implemented.

For example the list of books in the following xml file:



<Library updated="2016-10-31">
   <Book>
      <Title>Paths of colours</Title>
      <Author>Rosa Indaco</Author>
   </Book>
   <Book>
      <Title>Accounting exercises</Title>
      <Author>Su Zhang</Author>
   </Book>
</Library>

Can be retrieved with the following code:



var xmlFile = Banana.Xml.parse(xml);
var xmlRoot = xmlFile.firstChildElement('Library');
var updateDate = xmlRoot.attribute('updated');
var bookNode = xmlRoot.firstChildElement('Book'); // First book
while (bookNode) {
   // For each book in the library
   var title = bookNode.firstChildElement('Title').text;
   var authorNode = bookNode.firstChildElement('Author');
   var author = authorNode ? authorNode.text : 'unknow';
   bookNode = bookNode.nextSiblingElement('Book'); // Next book
}

 

Properties

errorString

Read only. The string of the last occured error. If no error occured it is empty.

Since Banana 9.0.4

Methods

newDocument(name)

The method newDocument(name) creates a new Xml document and returns it as a Banana.Xml.XmlElment object.

Since Banana 9.0.4

parse(xml)

The method parse(xml) parses a xml data and returns an object of type Banana.Xml.XmlElment that represents the parsed xml. If the xml data is not valid, this method returns null, the occured error can be retrieved through the property errorString.



var xmlFile = Banana.Xml.parse(xml); 
var xmlRoot = xmlFile.firstChildElement('Bookshelf'); // The root element is named 'Bookshelf' in this example

save(xmlElement)

The method newDocument(name) returns a Banana.Xml.XmlElment as a string.

Since Banana 9.0.4

validate(xmlElement, schemaFilePath)

The method validate(xmlElement, schemaFilePath) validates a Banana.Xml.XmlElment against a shema. The schema is passed as a path relative to the script path. The method returns true if the validation passed, otherwise it returns false. The occured validation error can be retrieved though the property errorString.



// Create document
var xmlDocument = Banana.Xml.newDocument("eCH-0217:VATDeclaration");
var rootNode = xmlDocument.addElement("eCH-0217:VATDeclaration");
...
 
// Validate against schema (schema is passed as a file path relative to the script)
var schemaFileName = "eCH-0217-1-0.xsd";
if (Banana.Xml.validate(xmlDocument, schemaFileName)) {
   Banana.Ui.showInformation("Validation result", "Xml document is valid against " + schemaFileName);  
} else {
   Banana.Ui.showInformation("Validation result", "Xml document is not valid againts " + schemaFileName + ": " + Banana.Xml.errorString);
}

Since Banana 9.0.4

Banana.Xml.XmlElement

The XmlElement class represents an Xml element. See Banana.Xml for an example.

Since: Banana Accounting 9.0.3

Properties

nodeName

The read only property nodeName returns the node name of the xml element.

parent

The read only property parent returns the parent of this Xml element as a Banana.Xml.XmlElment object. If this is the root element, it returns null.

text

The read only property text returns the text of this Xml element and their childs.

value

This is a synomin of the property text.

Methods

addProcessingInstruction(target, data)

Adds a new processing instruction to the document.



xmlDoc.addProcessingInstruction('xml-stylesheet', 'href="mycss.css" type="text/css"');

Since Banana 9.0.4

addElement(name)

Adds a new Banana.Xml.XmlElement with the specified name to the document and returns it.

Since Banana 9.0.4

addElementNs(ns, name)

Adds a new Banana.Xml.XmlElement with the specified name and namespace to the document and returns it.

Since Banana 9.0.4

addComment(text)

Adds a comment note to the document, and returns it as a Banana.Xml.XmlElement object.

Since Banana 9.0.4

addTextNode(text)

Adds a new Xml TextNode to the document and returns it as a Banana.Xml.XmlElement object.

Since Banana 9.0.4

attribute(name [, defaultValue])

Returns the value of the attribute with the specified name as a string. If no attibute with the specified name is found, the defaultValue or an empty string is returned.

attributeNS(ns, name [, defaultValue])

Returns the value of the attribute with the specified name and namespace as a string. If no attibute with the specified name is found, the defaultValue or an empty string is returned.

createElement(name)

Creates a new Banana.Xml.XmlElement with the specified name and returns it. It doesn't add it to the document.

Since Banana 10.1

elementsByTagName(name)

Returns an array containing all descendants of this element with the specified name.

firstChildElement([name]) 

Returns the first child element with the specified name if name is non-empty, otherwise it returns the first child element. Returns null if no such child exists.



var bookNode = xmlRoot.firstChildElement('Book');  // First book
while (bookNode) { 
   // For each book in the library
   var title = xmlFile.firstChildElement('Title').text();
   bookNode = bookNode.nextSiblingElement('Book');  // Next book
} 

hasChildElements([name])

Returns true if this element contains one or mode elemets with the specified name.

hasAttribute(name)

Returns true is the attribute with the specified name exists.

hasAttributeNS(ns, name)

Returns true if the attribute with the specified name and namespace exists.

lastChildElement([name])

Returns the last child element with the specified name if name is non-empty, otherwise it returns the last child element. Returns null if no such child exists.

namespaceURI()

Returns the namespace URI of this node or an empty string if the node has no namespace URI.

Since Banana 9.0.4

nextSiblingElement([name])

Returns the next sibling element with the specified name if name is non-empty, otherwise returns any next sibling element. Returns null if no such sibling exists.

prefix()

Returns the namespace prefix of the node or an empty string if the node has no namespace prefix.

Since Banana 9.0.4

previousSiblingElement([name])

Returns the previous sibling element with the specified name if name is non-empty, otherwise returns any previous sibling element. Returns null if no such sibling exists.

removeChild(oldChild)

Removes oldChild from the list of children. oldChild must be a direct child of this node. Returns a new reference to oldChild on success or a null node on failure.

Since Banana 10.1

replaceChild(newChild, oldChild)

Replaces oldChild with newChild. oldChild must be a direct child of this node. 

Since Banana 10.1

setAttribute(name, value)

Adds an attribute with the qualified name name with the value value.

Since Banana 9.0.4

setAttributeNs(ns, name, value)

Adds an attribute with the qualified name name and the namespace URI ns with the value value.

Since Banana 9.0.4

setPrefix(value)

If the node has a namespace prefix, this function changes the namespace prefix of the node to pre. Otherwise this function does nothing.

Since Banana 9.0.4

DocumentChange API

The DocumentChange API is allows to make changes to an open accounting file. There are two possibility to program an extension:

Logic of the change process

Contrary to other APIs that allow to directly modify the data, Banana Accounting has decided for an approach that gives the user full control of such data.

  • You cannot directly modify the content of a file.
  • You must create an Extension that return a Document Change JSON.
  • Banana Accounting use the JSON and Apply the contained change to the existing file.
  • The program shows to the user what changes will take place and will ask the permission to apply the changes. Changes are discarded if not approved.
  • If the user agrees, the changes are applied to the document.
  • The user can undo and redo the changes.

Use Cases

The DocumentChange API can be used for:

  • Add, modify and delete rows in a Table.
  • Add, modifify and remove columns in a Table.
  • Modify the File Properties
  • Importing Transactions.
  • Importing Accounts, Suppliers and Customers.
  • Importing Invoice and Estimates.
  • Create sort of "macro" that takes a user input to create one or multiple transactions.
  • Calculate and modify columns content.

Examples

 

Document Change Extension

Is a Banana Extension that return a Document Change JSON :

  1. It can be a Productivity or Import Extension.
  2. The Extensions main function exec() returns a JSON document that describes what changes will be applied to the file content.
  3. The extension must create and return a Document Change JSON that contains the change that will be applied to the existing data.

Example of an Extension returning a DocumentChange

The extension creates a DocumentChange JSON and returns it to the program.


// Creates a JSON DocumentChange which adds a row to the transaction table.
//
// @id = ch.banana.example.documentchange
// @api = 1.0
// @pubdate = 2024-03-25
// @doctype = *.*
// @description = JSON Change adding a row
// @task = app.command
// @timeout = -1
function exec() {
var strChange = ` {
  "format": "documentChange",
  "error": "",
  "data": [
    {
      "document": {
        "cursorPosition": {
          "operation": "move",
          "tableName": "Transactions",
          "columnName": "Description",
          "rowNr": -1
        },
        "dataUnits": [ {
            "nameXml": "Transactions",
            "data": {
              "rowLists": [ {
                  "rows": [ {
                      "fields": {
                        "Date": "2025-03-25",
                        "Description": "Total sales 25-03-2025",
                        "Amount": "2000"
                      },
                      "operation": {
                        "name": "add"
                      }, 
                      "style": { 
                        "fontSize": 12,
                        "bold": true,
                        "color": "red",
                        "background-color": "#00FFFF"
                      } 
                  } ]
              } ]
            } 
        } ],
        "fileVersion": "1.0.0",
        "id": ""
    }
    } ]
} `;
var jsonChange = JSON.parse(strChange);
return jsonChange;
}

DocumentChange JSON

The DocumenChange Json is a JSON object that contains the following elements.

  • format need to be "documentChange"
  • error used to return an error from the script.
  • creator information regarding the change.
    It will be automatically added by the program.
    • executionDate time stamp of the script that has created the change.
    • executionTime h.
    • name (description) comment .
    • version version of the script.
  • data is a JSON array of JSON objects (document) with the changes to be applied.

    • Each element of the array is a single change.
    • Changes are applied in sequence.
    • document is a change to be applied to the accounting file
      • id document identifier (usually empty).
        "id":"currentRow" used by JsAction::updateRow()
      • dataUnits the element to be changed (corresponds to the table in the accounting file).
      • fileVersion the version of the documentChange specification
      • cursorPosition cursor position when changes have been applied (see example code)
        • operation "move" The cursor moves to the last position of the content (the only attribute available at the moment. Future attributes: select, deselect)
        • tableName xml tablename, where to position the cursor
        • columnName xml columnname, where to position the cursor
        • rowNr index of the row, where to position the cursor (-1 move to the last row of the table)

     

Properties of DataUnits

The dataUnits array element defines the dataUnits which is going to be changed and includes also the list of changes.

  • nameXml is the xml name of the data structure.
    It can be
  • nid is the id of the data structure. It is optional and can be passed in place of the nameXml
  • rowLists Is an array containing rows
    • rows Is an array containing all the rows can be also defined as "Views" when we are working with columns
      • fields Is an Object which with the column names that are going to be modified and the value.
        (Example:   "fields": {"Date": "2019-01-05", "Description": "Sell of goods"}
      • style Is an object which define the row style
        • fontSize define the size of the font, can ben one of 8, 10, 12, 14 or 0 (use default style)
        • bold true for bold
        • italic true for italic
        • color the text color (From version 10.1.20)
          • "none" the color will be removed.
        • background-color the background color for the row. (From version 10.1.20)
          • "none" the color will be removed.
      • operation Is an object which defines the operation that has to be executes on the relative row or column.
        • name define the type of operation
          • add, add a new row
            • sequence: 1.1 to add after the row 1.
            • sequence: 1.2 to add after the 1.1
            • if no sequence is given the row is added to the end of the table.
          • delete 
            sequence indicates the row or column to be deleted from the accounting file.
          • modify 
            sequence indicates the row or column we want to modify with the previously specified fields or properties
          • move
            sequence indicates the row or column we want to move and moveTo the row or column destination;
          • replace
            sequence indicates the row or column we want to replace with the previously specified fields or properties;
      • sequence 
        Is the row or column number. The sequence is always referred to the status of the file, prior to the changes.
        • Use 1.1 to add a new row after the existing row at line 1.
  • viewList Is an object containing the array views
    • views Is an  array containing views
      • view Is an array of columns

 

Example Document Change JSON

The Document Change consists of a JSON object with a list of document changes (data). Each document change (document) contains the list of changes that must be applied to the accounting file. The basic structure is:


{
    "format": "documentChange",
    "error": "",
    "data": [{
        //First document
        "document": {
            "id": "firstChange",
            "dataUnits": [{
                "data": {
                    "rowLists": [{
                        "nameXml": "Base",
                        "rows": [{
                            "operation": {
                                "name": "modify"
                            },
                            "fields": {
                                "SectionXml": "Base",
                                "IdXml": "HeaderLeft",
                                "ValueXml": "Changed header1 with documentChange"
                            }
                        }]
                    }],
                },
                "nameXml": "FileInfo",
                "nid": ""
            }]
        }
    }, {
        //Second document
        "document": {
            "id": "secondChange",
            "dataUnits": [{
                "data": {
                    "rowLists": [{
                        "rows": [{
                            "operation": {
                                "name": "delete",
                                "sequence": "10"
                            }
                        }]
                    }]
                },
                "nameXml": "Transactions"
            }]
        }
    }, {
        //Third document
        "document": {
            "id": "secondChange",
            "dataUnits": [{
                "data": {
                    "rowLists": [{
                        "rows": [{ // remove the existing account at line 7
                            "operation": {
                                "name": "delete",
                                "sequence": "7"
                            }
                        }, { // add a new account at line 7
                            "fields": {
                                "Date": "2025-01-04",
                                "Description": "Bank Account",
                                "Account": "1001"
                            },
                            "operation": {
                                "name": "add",
                                "sequence": "7"
                            }
                        }]
                    }]
                },
                "nameXml": "Accounts"
            }]
        }
    }, {
        //Fourth document
        "document": {
            "id": "secondChange",
            "dataUnits": [{
                "data": {
                    "rowLists": [{
                        "rows": [{ //add first transaction
                                "fields": {
                                    "Date": "2025-01-04",
                                    "Description": "Purchase of goods",
                                    "AccountDebit": "4200",
                                    "AccountCredit": "2001",
                                    "Amount": "1300"
                                },
                                "operation": {
                                    "name": "add"
                                }
                            },
                            { // add second transaction, using the account added in the previous document
                                "fields": {
                                    "Date": "2025-01-05",
                                    "Description": "Sell of goods",
                                    "AccountDebit": "1001",
                                    "AccountCredit": "3000",
                                    "Amount": "1500"
                                },
                                "operation": {
                                    "name": "add"
                                }
                            }
                        ]
                    }]
                },
                "nameXml": "Transactions"
            }]
        }
    }]
}

Sequence property for rows

When modifying, deleting rows you need to specify the sequence. 

  • The sequence is the existing row number.
    • The first row is 0.
  • The number refer always to existing row number.
    • If  the row number refer to a non existing row, the single/whole ?? change is refused.
  • When deleting or inserting a new row the existing row numbers are not changed.
  • When adding use a decimal value.
    • sequence 1.1 means the row will be added after the row 1.
    • sequence 1.2 means the row will be added after the row 1.1.
    • sequence -1 means the row will be added before the 0.
  • When adding or moving you can use any sequence number, if will simply be used for sorting. 

Sequence numbers and operation: 

  • Command Modify. 
    The number of the row to be modified.
    For example sequence: 1, will change the existing row 1
  • Command Replace.
    The number of the row to be replaced. 
    The content of the row is completely replaced. It is like removing a line and adding a new one.
    For example sequence: 1, will replace the exiting row 1
  • Command Delete. 
    The number of the row to be deleted,
    For example sequence: 1, will remove the existing row 1
  • Command Move. 
    The number of the row to be moved.
    For example sequence: 1, moveTo: 5.1 will move row 1 after the existing row 5.
  • Command Add.
    The index of the row to be added.  
    Use -1 or -10 to add a row before the 0.
    For example 1.1 add a line after the row 1.
    If no sequence is indicated, the new row will be appended.

The engine applies the changes using the following logic:

  • It first process the instructions to modify the rows.
    • The existing rows sequence remains unchanged.
  • It add the new rows.
    • Therefore you cannot modify a rows that has been added.
  • It remove the rows to be deleted.
  • It sort the rows using the new sequence number. 
    For unchanged rows the existing sequence number is used.

Sequence property for columns

For columns the sequence property is used to specify the display sequence. 

Document for Multiple change steps

Within the same DocumentChange JSon you can have a series of changes that will be applied in several steps. This allows to do complex changes to the accounting file, without triggering errors.

For example s assume you need to remove and add accounts and transactions at the same time. If you add transactions that use a new account before the account is added, there will be an error. The multi-step approach allows you to submit a change that ensures system integrity. In this case the script will return a JSON object with a list of document changes,

  • First document: Change the accounting settings
  • Second document: Remove existing transactions
  • Third document: Remove and add accounts
  • Fourth document: Add the new transactions

The "data" element is an array of object of type "document" that contains the changes.

You can have multiple "document" with changes that will be applied in the specified sequence.


{ 
"format": "documentChange",
"error": "",
"data": [{
    //First document
    "document": {
        "id": "firstChange",
        "dataUnits": [{
            "data": {
                "rowLists": [{
                    "nameXml": "Base",
                    "rows": [{
                        "operation": {
                            "name": "modify"
                        },
                        "fields": {
                            "SectionXml": "Base",
                            "IdXml": "HeaderLeft",
                            "ValueXml": "Changed header1 with documentChange"
                        }
                    }]
                }],
            },
            "nameXml": "FileInfo",
            "nid": ""
        }]
    }
}, {
    //Second document
    "document": {
        "id": "secondChange",
        "dataUnits": [{
            "data": {
                "rowLists": [{
                    "rows": [{
                        "operation": {
                            "name": "delete",
                            "sequence": "10"
                        }
                    }]
                }]
            },
            "nameXml": "Transactions"
        }]
    }
}, {
    //Third document
    "document": {
        "id": "secondChange",
        "dataUnits": [{
            "data": {
                "rowLists": [{
                    "rows": [{ // remove the existing account at line 7
                        "operation": {
                            "name": "delete",
                            "sequence": "7"
                        }
                    }, { // add a new account at line 7
                        "fields": {
                            "Date": "2025-01-04",
                            "Description": "Bank Account",
                            "Account": "1001"
                        },
                        "operation": {
                            "name": "add",
                            "sequence": "7"
                        }
                    }]
                }]
            },
            "nameXml": "Accounts"
        }]
    }
}, {
    //Fourth document
    "document": {
        "id": "secondChange",
        "dataUnits": [{
            "data": {
                "rowLists": [{
                    "rows": [{ //add first transaction
                            "fields": {
                                "Date": "2025-01-04",
                                "Description": "Purchase of goods",
                                "AccountDebit": "4200",
                                "AccountCredit": "2001",
                                "Amount": "1300"
                            },
                            "operation": {
                                "name": "add"
                            }
                        },
                        { // add second transaction, using the account added in the previous document
                            "fields": {
                                "Date": "2025-01-05",
                                "Description": "Sell of goods",
                                "AccountDebit": "1001",
                                "AccountCredit": "3000",
                                "Amount": "1500"
                            },
                            "operation": {
                                "name": "add"
                            }
                        }
                    ]
                }]
            },
            "nameXml": "Transactions"
        }]
    }
 }]
}

 

Convenience class for Document change

The InvoiceApp is an Invoice Dialog Extension that internally use a DocumentChange class that provide a convenient way to create a Document change JSON.
It should be ported to be used to simplify the creation of DocumentChange JSON programmatically.
 

 

 

Basic Examples DocumentChange operations on rows

Example adding a row

The following example shows how to append a row to the Transactions table. If you indicate the sequence, the row will be inserted at the given position. Try this operation


{
   "format":"documentChange",
   "error":"",
   "data":[
      {
         "document":{
            "dataUnits":[
               {
                  "data":{
                     "rowLists":[
                        {
                           "rows":[
                              {
                                 "fields":{
                                    "Date":"2019-01-04",
                                    "Description":"Invoice 304"
                                 },
                                 "operation":{
                                    "name":"add"
                                 },
                                 "style": {
                                    "fontSize":12,
                                    "bold":"true",
                                    "italic":"false"
                                 }
                              }
                           ]
                        }
                     ]
                  },
                  "nameXml":"Transactions"
               }
            ]
         }
      }
   ]
}

Example modifying a row

The following example shows how to modify the existing row at line 2 in the Transactions table.


{
   "format":"documentChange",
   "error":"",
   "data":[
      {
         "document":{
            "dataUnits":[
               {
                  "data":{
                     "rowLists":[
                        {
                           "rows":[
                              {
                                 "fields":{
                                    "Description":"Invoice Hello World"
                                 },
                                 "operation":{
                                    "name":"modify",
                                    "sequence":"1"
                                 }
                              }
                           ]
                        }
                     ]
                  },
                  "nameXml":"Transactions"
               }
            ]
         }
      }
   ]
}

Example replacing a row

The following example shows how to replace the existing row at line 2 in the Transactions table.


{
   "format":"documentChange",
   "error":"",
   "data":[
      {
         "document":{
            "dataUnits":[
               {
                  "data":{
                     "rowLists":[
                        {
                           "rows":[
                              {
                                 "fields":{
                                    "Date":"2020-01-05",
                                    "Description":"Invoice 304",
                                    "Amount":"300.00"
                                 },
                                 "operation":{
                                    "name":"replace", 
				    "sequence":"1"
                                 }
                              }
                           ]
                        }
                     ]
                  },
                  "nameXml":"Transactions"
               }
            ]
         }
      }
   ]
}

Example deleting a row

The following example shows how to delete the existing row at line 2 in the Transactions table.


{
   "format":"documentChange",
   "error":"",
   "data":[
      {
         "document":{
            "dataUnits":[
               {
                  "data":{
                     "rowLists":[
                        {
                           "rows":[
                              {
                              "operation": {
                              "name": "delete",
                              "sequence": "1"
                                 }
                              }
                           ]
                        }
                     ]
                  },
                  "nameXml":"Transactions"
               }
            ]
         }
      }
   ]
}

Example moving a row

The following example shows how to move the existing row at line 2 to line 5 in the Transactions table.


{
   "format":"documentChange",
   "error":"",
   "data":[
      {
         "document":{
            "dataUnits":[
               {
                  "data":{
                     "rowLists":[
                        {
                           "rows":[
                              {
                                 "operation":{
                                    "name":"move",
                                    "sequence":"1",
                                    "moveTo":"4"
                                 }
                              }
                           ]
                        }
                     ]
                  },
                  "nameXml":"Transactions"
               }
            ]
         }
      }
   ]
}

Example adding rows to recurring transactions table

The following example shows how to add rows to the table Recurring transactions.


{
  "format": "documentChange",
  "error": "",
  "data": [
    {
      "document": {
        "dataUnits": [
          {
            "data": {
              "rowLists": [
                {
                  "nameXml": "Templates",
                  "rows": [
                    {
                      "fields": {
                        "Date": "20200705",
                        "Description": "compleanno Anna",
                        "Doc": "r1"
                      },
                      "operation": {
                        "name": "add"
                      }
                    }
                  ]
                }
              ]
            },
            "nameXml": "Transactions"
          }
        ]
      }
    }
  ]
}

Example adding JSON content in a custom column in the Transactions table

DocumentChange allows you to update a MIME field of type text/json. In this field it is possible to insert several json objects identified by a key.

  • The contents of the field must be passed as a string
  • Other types of MIME fields (text/html, image/jpg, ...) are currently not supported.
  • In Banana you can create a column of type MIME using the menu command: Data - Columns setup, Add new column and choosing Data type Mime

{
  "format":"documentChange", 
  "error":"",
  "data": [
    {
      "document": {
        "dataUnits": [
	  {
	    "data": {
               "rowLists": [
                  {
                     "rows": [
                        {
                           "fields": {
                              "Date": "2020-08-07",
                              "Description":"Writing data to json/text field",
			      "MyMimeColumn":{
                                "Object1Key":"{\"amount\":\"100.00\",\"currency\":\"CHF\"}",
                                "Object2Key":"{\"amount\":\"200.00\",\"currency\":\"EUR\"}"
                              }
                           },
                           "operation": {
                              "name": "add"
                           }
                        }
                     ]
                  }
               ]
            },
            "nameXml": "Transactions"
          }
        ]
      },
      "fileVersion": "1.0.0"
    }
  ]
}

 

Example adding attachments (text/plain) to the table Documents

DocumentChange allows you to insert a text in the Attachments Column available in the Documents table. The MIME type is text/plain and cannot be changed. 

  • The contents of the field must be passed as a string
  • Other types of MIME fields (image, HTML text, Markdown code, CSS stylesheet, Javascript code) are currently not supported.

This property has been introduced in BananaPlus 10.1.20


// Creates a JSON DocumentChange which adds a row with an attachment to the Documents table.
//
// @id = ch.banana.example.documentpatchMime
// @api = 1.0
// @pubdate = 2024-04-17
// @doctype = *.*
// @description = Add attachments to Documents Table
// @task = app.command
// @timeout = -1
function exec() {

var jsonContent = {
    "billing_info": {
        "total_amount_vat_exclusive": "51.00",
        "total_amount_vat_exclusive_before_discount": "51.00"
    }
};

var jsonChange = {
  "format": "documentChange",
  "error": "",
  "data": [
    {
      "document": {
        "dataUnits": [ {
            "nameXml": "Documents",
            "data": {
              "rowLists": [ {
                  "rows": [ {
                    "fields": {
                        "RowId": "MyDocument 1",
                        "Description":"Writing data to the attachmnents field",
                        "Attachments": JSON.stringify(jsonContent, null, 3)
                     },
                     "operation": {
                        "name": "add"
                     } } ]
              } ]
        } } ]
    } } ]
};

return jsonChange;
}

 

Examples DocumentChange operations on columns

With the DocumentChange it is also possible to perform operations on columns, in case you want to modify, add or replace a column.

Columns properties 

  • alignement
    • type: text
    • values: left|right|center
  • description
    • type: text
  • header1
    • type: text
  • header2
    • type: text
  • name
    • type: text
  • nameXml
    • type: text
  • width
    • type: number
    • values: in mm, max value 10000
  • definition
    • type: object
    • values: text, number, amount, date, time, bool, timestamp, timecounter, links,textmultiline, markdown, mime, textencrypted, Default value: text
    • decimals
      Number of decimals for types amount and number. Default value: 2
  • operation
    • values: add|delete|modify|move|replace

 

{
   "name": "MyColumn",
   "nameXml": "MyColumn",
   "description": "This is my column with an amount",
   "header1": "MyColumn",
   "definition" : {
      "type": "amount",
      "decimals": "4"
   },
   "operation": {
      "name": "add"
   }
}

Example adding a column

The following example shows how to append a column to the Accounts table. If you indicate the sequence, the column will be inserted at the given position. try this operation

{
    "format": "documentChange",
    "error": "",
    "data": [{
        "document": {
            "dataUnits": [{
                "data": {
                    "viewList": {
                        "views": [{
                            "columns": [{
                                    "alignement": "center",
                                    "description": "center column",
                                    "nameXml": "CenteredColumn",
                                    "header1": "My Header 1",
                                    "header2": "My Header 2",
                                    "width": 200,
                                    "operation": {
                                        "name": "add",
                                        "sequence": 0
                                    }
                                }],
                            "id": "Base",
                            "nameXml": "Base",
                            "nid": 1
                        }]
                    }
                },
                "id": "Accounts",
                "nameXml": "Accounts",
                "nid": 100
            }]
        }
    }]
}

Example modifying a column

The following example shows how to modify the existing column at line 2 in the Transactions table.

{
    "format": "documentChange",
    "error": "",
    "data": [{
        "document": {
            "dataUnits": [{
                "data": {
                    "viewList": {
                        "views": [{
                            "columns": [{
                                "header1": "NewDescription XXXX",
                                "nameXml": "Description",
                                "operation": {
                                    "name": "modify",
                                    "sequence": "1"
                                }
                            }],
                            "id": "Base",
                            "nameXml": "Base",
                            "nid": 1
                        }]
                    }
                },
                "id": "Transactions",
                "nameXml": "Transactions",
                "nid": 103
            }]
        }
    }]
}

Example replacing a column

The following example shows how to replace the existing column at line 24 in the Transactions table.

{
    "format": "documentChange",
    "error": "",
    "data": [{
        "document": {
            "dataUnits": [{
                "data": {
                    "viewList": {
                        "views": [{
                            "columns": [{
                                "nameXml": "Amount",
                                "header1": "AmountAsText",
                                "definition": {
                                    "type": "text"
                                },
                                "operation": {
                                    "name": "replace",
                                    "sequence": "23"
                                }
                            }],
                            "id": "Base",
                            "nameXml": "Base",
                            "nid": 1
                        }]
                    }
                },
                "id": "Transactions",
                "nameXml": "Transactions",
                "nid": 103
            }]
        }
    }]
}

Example deleting a column

The following example shows how to delete the existing column at line 2 in the Accounts table.

{
    "format": "documentChange",
    "error": "",
    "data": [{
        "document": {
            "dataUnits": [{
                "data": {
                    "viewList": {
                        "views": [{
                            "columns": [{
                                "nameXml": "Description",
                                "operation": {
                                    "name": "delete"
                                    "sequence": "1"
                                }
                            }],
                            "id": "Base",
                            "nameXml": "Base",
                            "nid": 1
                        }]
                    }
                },
                "id": "Accounts",
                "nameXml": "Accounts",
                "nid": 100
            }]
        }
    }]
}

Example moving a column

The following example shows how to move the existing column to line 2 in the Transactions table. To know the number of a column, double-click on the header of one of them, in the dialog that opens you can see all the available columns, they are represented in ascending order. values start from 0.

{
    "format": "documentChange",
    "error": "",
    "data": [{
        "document": {
            "dataUnits": [{
                "data": {
                    "viewList": {
                        "views": [{
                            "columns": [{
                                "nameXml": "Description",
                                "operation": {
                                    "name": "move",
                                    "sequence": "2"
                                }
                            }]
                        }]
                    }
                },
                "nameXml": "Transactions"
            }]
        }
    }]
}

 

Example DocumentChange FileProperties

When changing data to the File Properties (Header, date begin, date end) the change is structured like a change to the table, but using a special table FileInfo

See: Menu > Tools > File info for the list of elements.

Structure of the DocumentChange:

  • You can only use the operation "modify".
  • The extension can change only the elements that the user can change.
  • The element to be changed
    • SectionXml
      The name of the section, for example "SectionXml":"Base"
    • IdXml
      The identification, for example "IdXml":"HeaderLeft"
  • The value to be changed
    • ValueXml
      The contents of the field in Xml format, for example "ValueXml":"Changed header1 with documentChange"

 

Example changing file properties

The following example shows how to change accounting data properties as accounting header.



{
   "format":"documentChange",
   "error":"",
   "data":[
      {
         "document":{
            "dataUnits":[
               {
                  "nameXml":"FileInfo",
                  "data":{
                     "rowLists":[
                        {
                           "rows":[
                              {
                                 "fields":{
                                    "SectionXml":"Base",
                                    "IdXml":"HeaderLeft",
                                    "ValueXml":"Changed header1 with documentChange"
                                 },
                                 "operation":{
                                    "name":"modify"
                                 }
                              },
                              {
                                 "fields":{
                                    "SectionXml":"Base",
                                    "IdXml":"HeaderRight",
                                    "ValueXml":"Changed header2 with documentChange"
                                 },
                                 "operation":{
                                    "name":"modify"
                                 }
                              }
                           ]
                        }
                     ]
                  }
               }
            ]
         }
      }
   ]
}

 

Generale Examples Document Change API

 

Complete example creating and running a DocumentChange

The following extension creates a DocumentChange, which adds and changes some rows in the Transactions table.

To try this extension, you can copy and paste the code into a text file and save it in ".js" format.
To install it in Banana you have to click on the Menu Extensions (command Manage extensions...) and then add the file you just created using "Add from file" button.
After this procedure, the file can be run from the Menu Extensions under the new command "Modify ac2 file using documentChange".

// @id = ch.banana.test.create.documentchange.ac2
// @api = 1.0
// @pubdate = 2019-10-09
// @publisher = Banana.ch SA
// @description = Modify ac2 file using documentChange
// @task = app.command
// @doctype = 100.*;110.*;130.*
// @timeout = -1

function exec(inData) {

   if (!Banana.document)
      return "@Cancel";

   var documentChange = {
      "format": "documentChange",
      "error": "",
      "data": []
   };

   //1. Appends a row to the transaction table
   var jsonDoc = transactionRowAppend();
   documentChange["data"].push(jsonDoc);


   //2. Insert a row to the transaction table at the beginning of the rows
   jsonDoc = transactionRowInsert();
   documentChange["data"].push(jsonDoc);

   //3. Modify all rows in the transaction table
   jsonDoc = transactionRowEdit();
   documentChange["data"].push(jsonDoc);

   // Banana.Ui.showText("json object: " + JSON.stringify(documentChange, null, 3));

   return documentChange;

}

function getCurrentDate() {
   var d = new Date();
   var datestring = d.getFullYear() + ("0" + (d.getMonth() + 1)).slice(-2) + ("0" + d.getDate()).slice(-2);
   return Banana.Converter.toInternalDateFormat(datestring, "yyyymmdd");
}

function getCurrentTime() {
   var d = new Date();
   var timestring = ("0" + d.getHours()).slice(-2) + ":" + ("0" + d.getMinutes()).slice(-2);
   return Banana.Converter.toInternalTimeFormat(timestring, "hh:mm");
}

function initDocument() {
   var jsonDoc = {};
   jsonDoc.document = {};
   jsonDoc.document.fileVersion = "1.0.0";
   jsonDoc.document.dataUnits = [];
   jsonDoc.creator = {};
   jsonDoc.creator.executionDate = getCurrentDate();
   jsonDoc.creator.executionTime = getCurrentTime();
   jsonDoc.creator.name = Banana.script.getParamValue('id');
   jsonDoc.creator.version = "1.0";
   return jsonDoc;
}

function transactionRowAppend() {

   //row operation
   var row = {};
   row.operation = {};
   row.operation.name = "add";

   //row fields
   row.fields = {};
   row.fields["Date"] = getCurrentDate();
   row.fields["Description"] = "Executed transactionRowAppend()";

   //rows
   var rows = [];
   rows.push(row);

   //table
   var dataUnitTransactions = {};
   dataUnitTransactions.nameXml = "Transactions";
   dataUnitTransactions.data = {};
   dataUnitTransactions.data.rowLists = [];
   dataUnitTransactions.data.rowLists.push({
      "rows": rows
   });

   //document
   var jsonDoc = initDocument();
   jsonDoc.document.dataUnits.push(dataUnitTransactions);

   return jsonDoc;

}

function transactionRowEdit() {

   // Read the table row by row and save some values
   var rows = [];
   var table = Banana.document.table('Transactions');
   for (var i = 0; i < table.rowCount; i++) {
      var tRow = table.row(i);
      var description = tRow.value('Description');
      if (description.length <= 0)
         continue;

      //row operation
      var row = {};
      row.operation = {};
      row.operation.name = "modify";
      var sequence = i.toString();
      if (sequence.length <= 0)
         sequence = "0";
      row.operation.sequence = sequence;

      //row fields
      row.fields = {};
      row.fields["Date"] = getCurrentDate();
      row.fields["Description"] = description + " + transactionRowEdit()";
      rows.push(row);
   }

   //table
   var dataUnitTransactions = {};
   dataUnitTransactions.nameXml = "Transactions";
   dataUnitTransactions.data = {};
   dataUnitTransactions.data.rowLists = [];
   dataUnitTransactions.data.rowLists.push({
      "rows": rows
   });

   //document
   var jsonDoc = initDocument();
   jsonDoc.document.dataUnits.push(dataUnitTransactions);

   return jsonDoc;

}

function transactionRowInsert() {

   //row operation
   var row = {};
   row.operation = {};
   row.operation.name = "add";
   row.operation.sequence = "0";

   //row fields
   row.fields = {};
   row.fields["Date"] = getCurrentDate();
   row.fields["Description"] = "Executed transactionRowInsert()";

   //rows
   var rows = [];
   rows.push(row);

   //table
   var dataUnitTransactions = {};
   dataUnitTransactions.nameXml = "Transactions";
   dataUnitTransactions.data = {};
   dataUnitTransactions.data.rowLists = [];
   dataUnitTransactions.data.rowLists.push({
      "rows": rows
   });

   //document
   var jsonDoc = initDocument();
   jsonDoc.document.dataUnits.push(dataUnitTransactions);

   return jsonDoc;
}

Complete example loading and running an existing DocumentChange

The following code will ask for a DocumentChange file as input, after which it will process the operations present in the document and modify the accounting file accordingly.

To try this extension, you can copy and paste the code into a text file and save it in ".js" format.
To install it in Banana you have to click on the Menu Extensions (command Manage extensions...) and then add the file you just created using "Add from file" button.
After this procedure, the file can be run from the Menu Extensions under the new command "Read document change files (task: app.command)".

// @id = ch.banana.test.read.documentchange
// @api = 1.0
// @pubdate = 2019-12-19
// @publisher = Banana.ch SA
// @description = Read document change files (task: app.command)
// @task = app.command
// @doctype = *
// @docproperties =
// @timeout = -1

function exec(inData) {
   if (!Banana.document)
      return "@Cancel";

   var fileContent = '';
   var fileName = Banana.IO.getOpenFileName("Select open file", "", "Json file (*.json);;All files (*)")
   if (fileName.length) {
      var file = Banana.IO.getLocalFile(fileName)
      //file.codecName = "latin1";  // Default is UTF-8
      fileContent = file.read();
      if (file.errorString) {
         Banana.Ui.showInformation("Read error", file.errorString);
         return "@Cancel";
      }
   } else {
      Banana.Ui.showInformation("Info", "no file selected");
      return "@Cancel";
   }

   var jsonData = {
      "format": "documentChange",
      "error": "",
      "data": []
   };
   try {
      jsonData = JSON.parse(fileContent);
   } catch (e) {
      Banana.Ui.showInformation("Info", "error parsing documentChange");
      Banana.Ui.showText(fileContent);
      return "@Cancel";
   }

   if (!jsonData)
      return "@Cancel";

   //Banana.Ui.showText("json object: " + JSON.stringify(jsonData, null, 3));

   return jsonData;
}

 

Invoice Examples Document Change API

Example adding an Invoice

the following example shows how to use document change to create invoices with Document Change in Banana. These rows can only be inserted in the Invoices table using the Estimates and Invoices application. The Invoice JSON object represents the data structure through which a new invoice can be created.


{
  "format": "documentChange",
  "error": "",
  "data": [
    {
      "document": {
        "dataUnits": [
          {
            "nameXml": "Invoices",
            "data": {
              "rowLists": [
                {
                  "rows": [
                    {//Invoice 1
                      "operation": {
                        "name": "add"
                      },
                      "fields": {
                         (Invoice JSON Object)
                     },
                     {//Invoice 2
                       "operation": { 
                         "name": "add" 
                      }, 
                      "fields": { 
                         (Invoice JSON Object)
                    }
                  ]
                }
              ]
            }
          }
        ]
      },
      "creator": {
        "executionDate": "2021-09-13",
        "name": "extension_name.js",
        "version": "1.0"
      }
    }
  ]
}


Assure that the JSon Invoice Object is valid

It is advisable to check that the JSon Invoice Object is valid. Therefore:

  • Create a Json Invoice Object.
  • Pass the object to the function Calculate invoice.
  • Add the object to the document change

 

Example Change the Date with the Document Change API

Introduction

This page explains how to update the file properties, accounting dates with Banana Accounting Javascript Extension  using DocumentChange API .

Before start, to understand part of the code it's useful to read all the documentation about the DocumentChange API  functionalities .

It is very important to have all the dates that match in the accounting document, otherwise the script may not work properly.

This script allows you to change the file dates with the current year. for setting the current year has been created a Date type object,  we use his method  getFullYear() to recover the year of the current date.

The current date value can be changed in the  in the method: initParam();.

In an Accounting file we can find three main places with references to the dates:

  • OpeningDate/ClosureDate, which indicate the opening and closing dates of the accounts
  • HeaderLeft/HeaderRight, that are the two opposite side headers of a page, where a user could decide to put the dates for example for print a report
  • Date, referring to the date field in the table

the internal format is always composed as follows 'YYYYMMDD'.

References

 

Function Exec()

The exec() function is the main function, which is called when the extension is executed. This function does the following:

  • creates the initial command structure part which is the same for all documents
  • calls the methods used to define the rest of the structure and parameters of the documents we want to change
  • for every function called, checks that the parameters are not empty
  • returns an object containing the whole commands structure 


function exec(inData, options) {

    var param = initParam();
    Banana.console.debug(JSON.stringify(param));
    var ischange = false;

    var documentChange = { "format": "documentChange", "error": "", "data": [] };

    if (param.newaccountingopeningdate.length > 0) {
        var jsonDoc = setfileInfo("AccountingDataBase", "OpeningDate", param.newaccountingopeningdate);
        documentChange["data"].push(jsonDoc);
        ischange = true;
    }

    if (param.newaccountingclosuredate.length > 0) {
        jsonDoc = setfileInfo("AccountingDataBase", "ClosureDate", param.newaccountingclosuredate);
        documentChange["data"].push(jsonDoc);
        ischange = true;
    }

    if (param.newaccountingheaderleft.length > 0) {
        jsonDoc = setfileInfo("Base", "HeaderLeft", param.newaccountingheaderleft);
        documentChange["data"].push(jsonDoc);
        ischange = true;
    }

    if (param.newaccountingheaderright.length > 0) {
        jsonDoc = setfileInfo("Base", "HeaderRight", param.newaccountingheaderright);
        documentChange["data"].push(jsonDoc);
        ischange = true;
    }

    jsonDoc = setTransactionsDate(param);
    if (typeof(jsonDoc) == "object") {
        documentChange["data"].push(jsonDoc);
        ischange = true;
    }


    jsonDoc = setBudgetDate(param);
    if (typeof(jsonDoc) == "object") {
        documentChange["data"].push(jsonDoc);
        ischange = true;
    }
    if (ischange) {

        return documentChange;
    }
}

Function initParam()

  • This method initializes the  parameters, which are dates taken from the file informations, and the crurrent date.
  • checks if there is a date in the headers taking as reference the opening date of the file, if there is it updates it with the current one
  • check that the year of opening and closing have the current year, if not, will update them with the current year
  • return an object with al the parameters wee need.


function initParam() {
    var param = {};
    param.differenceyear = 0;
    param.accountingyear = "";
    param.newaccountingyear = new Date().getFullYear();
    param.newaccountingopeningdate = "";
    param.newaccountingclosuredate = "";
    param.newaccountingheaderleft = "";
    param.newaccountingheaderright = "";


    var OpeningDate = Banana.document.info("AccountingDataBase", "OpeningDate");
    if (OpeningDate && OpeningDate.length > 4) {
        param.accountingyear = OpeningDate.toString().substr(0, 4);
        var Headerleft = Banana.document.info("Base", "HeaderLeft");
        if (Headerleft && Headerleft.indexOf(param.accountingyear) >= 0) {
            Headerleft = Headerleft.replace(param.accountingyear, param.newaccountingyear);
            param.newaccountingheaderleft = Headerleft;

        }
        var Headerright = Banana.document.info("Base", "HeaderRight");
        if (Headerright && Headerright.indexOf(param.accountingyear) >= 0) {
            Headerright = Headerright.replace(param.accountingyear, param.newaccountingyear);
            param.newaccountingheaderright = Headerright;
        }

        var currentYearint = parseInt(param.newaccountingyear);
        var fileYearint = parseInt(param.accountingyear);

        param.differenceyear = Banana.SDecimal.subtract(currentYearint, fileYearint);

        if (parseInt(param.differenceyear) != 0) {
            param.newaccountingopeningdate = param.newaccountingyear.toString() + OpeningDate.toString().substr(4);
            param.newaccountingopeningdate = param.newaccountingopeningdate.replace(/-/g, "");
            var closureDate = Banana.document.info("AccountingDataBase", "ClosureDate");
            if (closureDate && closureDate.length > 4) {
                var year = closureDate.toString().substr(0, 4);
                var newyear = parseInt(year) + parseInt(param.differenceyear);
                param.newaccountingclosuredate = newyear.toString() + closureDate.toString().substr(4);
                param.newaccountingclosuredate = param.newaccountingclosuredate.replace(/-/g, "");

            }

        }
    }
    return param;
}

Function changeYearInDate()

Calculate the new date for the opening date and the closure date taking as parameters the current opening and closure date and the difference between the current effective date and the current opening date  reported in the file information.

conditions:

the opening and the closure date should not be empty.

return the date changed.



function changeYearInDate(differenceyear, OpeningClosureDate) {
    if (OpeningClosureDate && OpeningClosureDate.length > 4) {
        var Year = OpeningClosureDate.toString().substr(0, 4);
        var newyear = Banana.SDecimal.add(parseInt(Year), parseInt(differenceyear));
        var changedDate = newyear.toString() + OpeningClosureDate.toString().substr(4);
        changedDate = changedDate.replace(/-/g, "");

        return changedDate;

    }
    return "";

}

Function getNewRowDate()

Calculate the new date for the table rows taking as parameters the current date in the table and the difference between the current effective date and the current opening date  reported in the file information.

Conditions:

  • the current date must be longer than four characters, and should exist
  • it must be a difference between the current effective date and the current opening date  reported in the file information

 

Returns the new date.



function getNewRowDate(currentDate, param) {
    if (!currentDate || currentDate.length < 4)
        return "";
    if (param.differenceyear == 0)
        return "";
    var currentyear = currentDate.substr(0, 4);
    var newyear = parseInt(currentyear) + parseInt(param.differenceyear);
    var newDate = newyear.toString() + currentDate.substr(4);

    return newDate;
}

function setfileInfo()

  • this function set the structure of the document wich modify the dates into the files information table
  • requires three parameters which represent the identification values of the fields who can containing dates in the file information table
  • returns an object with the document structure


function setfileInfo(key1, key2, value) {

    //row operation
    var row = {};
    row.operation = {};
    row.operation.name = "modify";

    row.fields = {};
    row.fields["SectionXml"] = key1;
    row.fields["IdXml"] = key2;
    row.fields["ValueXml"] = value;

    var rows = [];
    rows.push(row);

    //table
    var dataUnitTransactions = {};
    dataUnitTransactions.nameXml = "FileInfo";
    dataUnitTransactions.data = {};
    dataUnitTransactions.data.rowLists = [];
    dataUnitTransactions.data.rowLists.push({ "rows": rows });

    //document
    var jsonDoc = initDocument();
    jsonDoc.document.dataUnits.push(dataUnitTransactions);

    return jsonDoc;

}

functions setTransactionsDate()/setBudgetDate()

 

these two functions are very similar, they have the same code and the same document structure, which modifies the rows of the record tables, the only difference  is that they are pointing to two different kind of tables:

  • transactions
  • budget

both call the function getNewRowDate(), wich change the current date founded in the row with the effectvie current one.

 

Returns an object with the document structure.

setTransactionsDate()



function setTransactionsDate(param) {
    var table = Banana.document.table("Transactions");
    if (!table) {
        return;
    }
    var rows = [];

    for (var i = 0; i < table.rowCount; i++) {
        var tRow = table.row(i)
        var TransDate = tRow.value('Date');
        TransDate = getNewRowDate(TransDate, param);
        if (TransDate.length <= 0) {

            continue;
        }

        //row operation
        var row = {};
        row.operation = {};
        row.operation.name = "modify";
        row.operation.sequence = i.toString();

        row.fields = {};
        row.fields["Date"] = TransDate;


        rows.push(row);
    }
    if (rows.length <= 0)
        return;



    //table
    var dataUnitTransactions = {};
    dataUnitTransactions.nameXml = "Transactions";
    dataUnitTransactions.data = {};
    dataUnitTransactions.data.rowLists = [];
    dataUnitTransactions.data.rowLists.push({ "rows": rows });

    //document
    var jsonDoc = initDocument();
    jsonDoc.document.dataUnits.push(dataUnitTransactions);

    return jsonDoc;

}

setBudgetDate()



function setBudgetDate(param) {

    var table = Banana.document.table("Budget");
    if (!table) {
        return;
    }
    var rows = [];

    for (var i = 0; i < table.rowCount; i++) {
        var tRow1 = table.row(i)
        var TransDate = tRow1.value('Date');
        var TransDateEnd = tRow1.value('DateEnd');
        TransDate = getNewRowDate(TransDate, param);
        TransDateEnd = getNewRowDate(TransDateEnd, param);
        if (TransDate.length <= 0) {

            continue;
        }

        //row operation
        var row = {};
        row.operation = {};
        row.operation.name = "modify";
        row.operation.sequence = i.toString();

        row.fields = {};
        row.fields["Date"] = TransDate;
        row.fields["DateEnd"] = TransDateEnd;


        rows.push(row);
    }
    if (rows.length <= 0)
        return;


    //table
    var dataUnitTransactions = {};
    dataUnitTransactions.nameXml = "Budget";
    dataUnitTransactions.data = {};
    dataUnitTransactions.data.rowLists = [];
    dataUnitTransactions.data.rowLists.push({ "rows": rows });

    //document
    var jsonDoc = initDocument();
    jsonDoc.document.dataUnits.push(dataUnitTransactions);

    return jsonDoc;

}

Changelog

DateBananaPlusBananaPlus DevAPI VersionChangeNotes
2022-03-3010.1.810.0.12.0891.2.0New class Banana.Document.Column 
    New method Banana.Document.Table.column 
    New method Banana.Document.Table.viewName 
    New method Banana.Document.Row.style 
    New methods Banana.ReportElement.addHeader1..6 
    New method Banana.ReportElement.addStructuredText 
2022-05-3110.1.810.0.12.1511.2.1New method Banana.ReportElement.GetChildren 
    New method Banana.ReportElement.GetParent 
    New method Banana.ReportElement.GetRoot 
    Fixes Banana.ReportElement.addStructuredText 
2022-12-02

10.1.8

10.0.13.3401.2.2New property Banana.application.qtVersion 
    New property Banana.application.apiVersion 
    Fixes Banana.Document.Table.progressiveNumber for alphanumeric or composite numbers. 
2023-02-2210.1.810.1.0.230531.2.3New method Banana.application.getMessages
New method Banana.document.getMessages
 
    New property Banana.document.uuid 
2023-08-22n/a10.1.0.232281.2.3New method Banana.document.addDocInfo 
2023-08-25n/an/a1.2.4Search paths for include scripts via the attribute @includejs or via the method Banana.include has be extended:
1) Relative to the same directory as the file that contains the @include attribute.
2) New: relative to the directories of the currently opened include files, in the reverse order in which they were opened. 
 
2023-09-26n/an/a1.2.5New method Test.closeDocument
New method Test.setDocument
New method Test.setTableValue