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 Version | API Version |
7.0.6 | 1.0 |
8.0.7 or more recent | 1.0 |
9.0.0 or more recent | 1.0 |
Plus | 1.2.4 |
Plus Insider | 1.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:
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).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:
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:
- Methods, that apply to all documents, see Banana.Document (Base),
- Method specific to the Accounting class.
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 :
- explanations of the function currentBalance.
- Vat Extension Example
- Example files are available on github/General/CaseStudies.
- Solutions making use of the VAT api.
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 :
- explanations of the function currentBalances.
- Example files are available on github/General/CaseStudies.
- Solutions making use of the VAT api.
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.AddMessage, Document.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
- Rows of type Banana.Document.Row.
- Columns of type Banana.Document.Column.
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.AddMessage, Row.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:
- 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
- Create a StyleSheet using the Banana.Report.newStyleSheet() function.
- Add syle elements to the stylesheet.
- A stylesheet is composed of StyleElements.
- 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.
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:
- Banana.document.addMessage()
- Banana.document.clearMessages()
- table.addMessage()
- row.AddMessage()
- Banana.application.addMessage()
- Banana.application.getMessages()
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.
- See Invoice Extension containing examples with this method.
- see the structure example on GitHub

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 &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>&Match case</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="wholeTextCheckBox">
<property name="text">
<string>&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>&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:

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:
- Create a DocumentChange JSON (documentChange) and use the Banana.document.applyDocumentChange(documentChange)
- Create a DocumentChange JSON (documentChange) and return it in the exec() function.
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
- Examples Rows
- Examples Columns
- Example FileProperties
- Examples General
- Examples Invoices
- Example Change Date
Document Change Extension
Is a Banana Extension that return a Document Change JSON :
- It can be a Productivity or Import Extension.
- The Extensions main function exec() returns a JSON document that describes what changes will be applied to the file content.
- 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- A name of an existing Table ("Account, Transactions, ...)
- FileInfo for the file properties (Menu > Tools > File Info).
See Example DocumentChange FileProperties.
- 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
- DocumentChange API
- Script's source: ch.banana.apps.documentchange.dates.js
- Build you first Extension
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
Date BananaPlus BananaPlus Dev API Version Change Notes 2022-03-30 10.1.8 10.0.12.089 1.2.0 New 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-31 10.1.8 10.0.12.151 1.2.1 New 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.340 1.2.2 New property Banana.application.qtVersion New property Banana.application.apiVersion Fixes Banana.Document.Table.progressiveNumber for alphanumeric or composite numbers. 2023-02-22 10.1.8 10.1.0.23053 1.2.3 New method Banana.application.getMessages
New method Banana.document.getMessages New property Banana.document.uuid 2023-08-22 n/a 10.1.0.23228 1.2.3 New method Banana.document.addDocInfo 2023-08-25 n/a n/a 1.2.4 Search 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-26 n/a n/a 1.2.5 New method Test.closeDocument
New method Test.setDocument
New method Test.setTableValue