App Design
Extension File
Javascript compliant script
Extensions are essentially javascript compliant script files (ECMA-262). People knowing javascript can easily write an Extension.
Am Extension file contains the following two sections:
- Extension's attributes
The apps's attributes give information about the script, like it purpose, description and so on.
They are inserted at the beginning of the file through tags in comment's lines. - The exec([inData, options]) function
The function exec() is the function that is called every time an Extension is executed.
It has some optional arguments:
- inData: the requested input data as a string or a Banana.Document object;
This parameters is only used for import scripts, for all other tasks this parameter is just null;
- options: options as an object that can contains those parameters;
- useLastSettings: if true the script executes with the last used setttings and doesn't show a setting's dialog;
The script return a string formatted according the tag @outputformat.
Errors are notified through exceptions (clause throw), or just by returning a string beginning with "@Error:"
- [Optional] The settingsDialog() function
If the script has a dialog for settings some parameters it is advised to put the code for the dialog in this function. In this way the application can call this function just for showing or editing the parameters without executing the whole script.
This method should return null if the user click on cancel button, or a value different of null if the user click on ok button.
For a list of supported javascript functions, objects and properties see: Qt ECMAScript Reference.
Extensions interact with Banana Accounting through some global objects made available by Banana Accounting, like for example 'Banana.document'. Those objects are described under the Banana Script API.
Extension "Hello World" example
Here an example that open a print preview windows, and show a document with the text "Hello world!!!". Other examples are found in the Extensions tutorial.
// @id = ch.banana.report.helloworld // @version = 1.0 // @doctype = nodocument // @publisher = Banana.ch SA // @description = Hello world // @task = app.command // @timeout = -1 function exec() { //Create the report var report = Banana.Report.newReport('Report title'); //Add a paragraph with some text report.addParagraph('Hello World!!!'); //Preview the report var stylesheet = Banana.Report.newStyleSheet(); Banana.Report.preview(report, stylesheet); }
Extension with a setting's dialog example
Here an example that use a dialog to input a text. Other examples are found in the Extensions tutorial.
// @id = ch.banana.report.settingsdialog // @version = 1.0 // @doctype = * // @publisher = Banana.ch SA // @description = Example for settings dialog // @task = app.command // @timeout = -1 function exec(inData, options) { // Show dialog if options.useLastSettings is not set or is false if (!options || !options.useLastSettings) { if (!settingsDialog()) return; // return if user pressed cancel } // Get the settings var text = Banana.document.getScriptSettings(); //Create the report var report = Banana.Report.newReport('Report title'); report.addParagraph('You entered: "' + text + '"'); report.addParagraph(new Date().toString()); //Stylesheet var stylesheet = Banana.Report.newStyleSheet(); //Preview the report Banana.Report.preview(report, stylesheet); } function settingsDialog() { // Ask the user to enter a text that will be printed in the report var text = Banana.document.getScriptSettings(); text = Banana.Ui.getText("Enter a text", "The text will be printed in the report", text); if (typeof(text) === 'string') { Banana.document.setScriptSettings(text); return true; } return false; // cancel pressed }
Extensions have a strong Security model
Extensions are secure for the fact that are confined within Banana.
Extensions are NOT ALLOWED to directly write or read file, web resource, change computer setting or execute programs.
Extensions , contrary to Excel Macro, can be run with the confidence, they will not change any data and modify any file or computer settings.
To access or write to file you need to use the Banana Api that display a dialog box to the user.
- To write file you need to use the export functionality, that display a dialog where the user indicate the file name where to save.
- To import file you need to use the import functionality that display a dialog where the user specify the file name.
Best way to distribute the Extensions
- Single App file (javascript file)
- Easier to edit (external text editors), move and update.
- Can be included in the menu Apps.
- Can be used by different accounting file.
- Embedded apps
- Not available in the menu Apps.
- Only relative to the file where it is included.
- More difficult to edit and update.
- Packaged App file
- Cannot be easily changed.
- Can be included in the menu Apps.
- Can be used by different accounting file.
- Protected from user modification.
Extensions as a single javascript file
A single javascript (.js) file that includes all the code of the app.
This is how it works:
- Extensions are saved in UTF-8 file without BOOM.
- The Extension needs to be installed through the Manage Apps command.
- Once the Extension is installed, it appears in the menu Apps.
- The Extension can be run from the menu Apps.
Embedded Extension in documents
Banana allows to have Extensions that are embedded within a Banana File. Embedded apps run only for the specific file, but don't need to be installed.
To create embedded Extensions you can add script files in the table Documents.
On the Embedded Extensions JavaScript Tutorial you will find the documentation and different basic examples embedded in a document that you can run and edit.
Extensions as packaged file
It is possible to package one or more apps composed by one or more files (.js, .qml and other files) in one single .sbaa Extensions file (see documentation below).
It's very practical for distributing Apps composed by two or more files, or packages with two or more Extensions.
This is how it works:
- The .sbaa Extension needs to be installed through the Manage Apps command.
- Once the Extensions is installed, it appears in the menu Apps.
- The Extension can be run from the menu Apps.
Extensions file extention '.sbaa'
A .sbaa file can be either a text file containing javascript code (.js files) or a packaged qt resource file (.sbaa). The application determine automatically the type of the file.
When Banana loads a packaged .sbaa file, it looks for all .js files contained in the package that have an attribute section. Those files are readen and a corresponding entry is inserted in the menu Apps.
Javascript files in packages can include other javascript files in the same package using the directive @includejs or the method Banana.include(fileName). It is not possibile to include files outside the package.
// Include a script via @includejs attribute // @includejs = somescript.js" // Include a script via Banana.include() method Banana.include(somescript.js);
Here is how to create a packaged .sbaa file:
- Create a manifest.json file with the information regarding the package
- Create a .qrc file with the list of the files to be included.
- It is also possibile to create package files with the 'rcc' tool from the QT (see below)
- Open Banana Accounting
- Drag the .qrc file in Banana Accounting.
- It will ask you if you want to compile the file and will generate a .sbaa file.
Qrc resource file (.qrc)
For more information see the Qt Resource system.
Example: ch.banana.script.report.jaml.qrc
<!DOCTYPE RCC><RCC version="1.0"> <qresource> <file>ch.banana.script.report.jaml.js</file> <file>lib/jaml-all.js</file> <file>manifest.json</file> </qresource> </RCC>
Qrc file file can also be compiled with the QT
rcc -binary ch.banana.script.report.jaml.qrc -o ch.banana.script.report.jaml.rcc
Manifest file
If you create a .sbaa file, also include a manifest file. The manifest.json file is a JSON-formatted file, which you can include in the .sbaa file through the .qrc file.
Using manifest.json, you specify basic metadata about your package such as the title, description and version.
The file name must end with the extension 'manifest.json'
Example: ch.banana.script.report.vat-ch.qrc
<!DOCTYPE RCC><RCC version="1.0"> <qresource> <file alias="manifest.json">ch.banana.script.report.vat-ch.manifest.json</file> <file>ch.banana.script.report.vat-ch.js</file> </qresource> </RCC>
Example: ch.banana.script.report.vat-ch.manifest.json
{ "category": "productivity", "country":"switzerland", "countryCode":"ch", "description": "Postfinance Schweiz (Bewegungen importieren): ISO20022 und CSV Format", "description.en": "Swiss Postfinance (Import transactions): ISO20022 and CSV File Format", "language":"de", "publisher": "Banana.ch", "title": "Postfinance Schweiz (Bewegungen importieren)", "title.en": "Swiss Postfinance (Import transactions)", "version": "1.0" }
- Available categories: export, import, invoice, invoice reminder, invoice statement, productivity.
If you don't specify the category ("category": ""), the program will take the category from the first app included in the package. If you don't specify country or language, the app will be shown for any country or language. - All tags are optional
Extension's Attributes
At the beginning at the script there should be a part that define the Extension's Attribute.
// @api = 1.0 // @id = ch.banana.apps.example.docfilepath // @description = Hello world // @task = app.command // @doctype = nodocument // @publisher = Banana.ch SA // @pubdate = 2015-05-12 // @inputdatasource = none // @timeout = -1
The attribute is a commented text line
- Sart with //
- Followed by the attribute that start with @
- Fossowed by the " = " and the value
Tags defines the purpose (import, export, extract, ...), the name displayed in the dialogs, the kind of data it expect to receive, the kind of data it returns, and other information of the script. Tags are inserted at the beginning of the script in comment's lines though the following syntax: "// @tag-name = tag-value".
Attribute list
Attribute name | Required |
Value 1) |
Description |
@api | Required |
The required API version. Available API versions: |
Define the required API to be executed in the form of MAIN_VERSION.SUB_VERSION The implemented API in the application have to be equal or newer. |
@contributors | List of contributors separated by ';' | This attribute contains the list of people that contribute to the developping of the BananaApp. | |
@description[.lang] | Required | The name or description of the script |
This text will be displayed in the dialogs. This tag is localisable. |
@docproperties | any text | Define a property the script is writen for. With this attribute you can manually select for what document the script is visbile in the menu Add-ons and can be run. The property can be added to the document though the dialog Add-Ons. The property can be any text (ex.: "datev", "realestate", ...). Mulitple properties can be defined wiht a ';' as separator (ex.: "datev;skr03"). |
|
@doctype | Required | nodocument * XXX.* XXX.YYY !XXX.YYY ... |
Define the type of document the script is writen for. nodocument = doesn't require an open document, the add-on is always visible The sign ! is used to invert the definition. The above codes can be combined togheter like the following examples: 100.130 = for double entries with VAT and with foreign currencies100.120;100.130 = for double entry with foreign currencies 100.*;110.*;130.* = for all accounting files !130.* = for any filesexcept cash books |
@exportfilename | A string defining the name of the file where to export the data. | If the string contains the text <Date>, it will be replaced by the current date in the format of yyyyMMdd-hhmm. | |
@exportfiletype |
A string defining the type of data exported txt... |
This parameter is used for export scripts, it defines the type of exported data and it is used for the extension in the save file dialog. | |
@id | Required | An identification of the script | It is used when setting and reading the preferences. In order to avoid duplicate banana.ch use the following scheme. country.developper.app.domain.name for example: ch.banana.app.patriziato.consuntivopersubtotali |
@includejs | Relative path to a javascript .js file to load before the execution of the script. | Include the javascript file. Every function and object defined in the file are then available to the current script. | |
@inputdatasource | One of the following values: none openfiledialog fixedfilepath 2) |
With this attribute you can specify if you don't need to input data, if you want the user to select a file to import (openfiledialog), or if you want to get a file which path is defined in @inputfilepath. If you set fixedfilepath the program will ask the user the permission to open this file, the user's answer will be saved for the next execution. | |
@inputencoding |
The encoding of the input data. One of the following values: |
The encoding used to read the input file (for import apps). If the attribute is empty or not defined, the application try to decode the input data with utf-8, if it fails, the application decode the input data with latin1. For a complete list see QTextCodec |
|
@inputfilefilter[.lang] |
The file filter for the open file dialog Ex.: Text files (*.txt *.csv);;All files (*.*) |
This value describes the file filters you want to show in the input file dialog. If you need multiple filters, separate them with ';;' for instance. This tag is localizable. |
|
@inputfilepath | The file to read for the input data | If the script has the value fixedfilepath as @inputdatasource, you can define here the path of the file to load. | |
@inputformat | One of the following values: text ac2 |
If "text" the filter receive the selected file in inData as a text. If "ac2" the filter receive the selected file in inData as a Banana.Document object. | |
@outputencoding |
The encoding of the input data. One of the following values: |
The encoding used to write the output file (for export apps). For a complete list see QTextCodec |
|
@outputformat | One of the follwing values: tablewithheaders transactions.simple |
If the script has an import tasks this value define the format of the returned value. The format transaction.simple contains the transaction as income / expenses. For details of the formats see Import data from a txt file. | |
@pubdate | Required | The publication date in the format YYYY-MM-DD | This publication date is also used for scripts published by Banana.ch to check if newer version exist. |
@publisher | The publisher of the script | ||
@task | Required |
One of following values: |
This value define the purpouse of the script, and determine in which dialog or menu the script is visible.
|
@testapp | Path and name of the test app. Default is './test/<bananaapp_name>.test.js |
This can be used if there is a test app and the path to the test app is different to the default path. Since Banana 9.0.4 |
|
@testappversionmin @testappversionmax |
Only for test cases. Minimum and mximum application's version to whitch the test is applicable. | ||
@timeout | The timeout for the script in milliseconds, default is 2000 (2 seconds). If you set -1 the timeout is disabled and the application allow you to abort it though a progress bar. | If the script takes longer than this value to finish, it will be aborted and a message showed. If you have a script with a very long run time, you can increase the timeout or set it to -1. |
1) Default values are listed in bold.
2) Function not yet available
Example:
// @api = 1.0 // @id = ch.banana.apps.example.docfilepath // @description = Hello world // @task = app.command // @doctype = nodocument // @publisher = Banana.ch SA // @pubdate = 2015-05-12 // @inputdatasource = none // @timeout = -1 /** * Hello world example for Banana Accounting. */ function exec(inData) { Banana.Ui.showInformation("", "Hello World"); if (Banana.document) { var fileName = Banana.document.info("Base","FileName"); Banana.Ui.showInformation("Current document", fileName); } }
Extension's Parameters
Extensions parameters allow to initialize and set parameters that are relative to an Extension, for example:
- Parameters for the printing.
- Header of a report that are set once only.
The script should provide a function settingDialog() that is called when the user click on the Set Parameters on the Manage Apps dialog.
The function settinDialog() should:
- Read the existing setting with the Banana.document.getScriptSettings();
- Request user to enter the information
- Set the modified values with the function Banana.document.setScriptSettings(paramToString);
The JSon text will be saved within the accounting file.
function settingsDialog() { var param = initParam(); var savedParam = Banana.document.getScriptSettings(); if (savedParam.length > 0) { param = JSON.parse(savedParam); } param = verifyParam(param); param.isr_bank_name = Banana.Ui.getText('Settings', texts.param_isr_bank_name, param.isr_bank_name); if (param.isr_bank_name === undefined) return; var paramToString = JSON.stringify(param); Banana.document.setScriptSettings(paramToString); }
the function Exec() should then read the setting.
It is a good practice to check and verify if the setting are valid.
function printDocument(jsonInvoice, repDocObj, repStyleObj) { var param = initParam(); var savedParam = Banana.document.getScriptSettings(); if (savedParam.length > 0) { param = JSON.parse(savedParam); param = verifyParam(param); } printInvoice(jsonInvoice, repDocObj, repStyleObj, param); }
Import Extensions
Import Extensions read a custom format and convert in an import format suitable for using with the command "Import to accounting".
- For details of the formats see Import data from a txt file.
- For examples see the Github.com template page.
Import Extensions
Imports Extensions are JavaScript program that read the data to import and transform and return them as text, in a format compatible with Banana.
Import BananaApps have:
- the attribute @task defined as one of the import for example //@task = import.transactions (for more information, see Apps attributes documentation)
- The parameter in the function exec contains the import data (the content of the file specified in the input box)
- You can specify that the data is read from the file specified on the input box or that the user can select the file with "// @inputdatasource = openfiledialog"
- The import text is returned as a String in the function exec with the return statement
// @api = 1.0 // @id = ch.banana.scripts.import.creditsuisse // @description = Credit Suisse bank (*.csv) // @task = import.transactions // @doctype = nodocument // @publisher = Banana.ch SA // @pubdate = 2015-06-21 // @outputformat = transactions.simple // @inputdatasource = openfiledialog // @inputfilefilter = Text files (*.txt *.csv);;All files (*.*) // @inputfilefilter.de = Text (*.txt *.csv);;Alle Dateien (*.*) // @inputfilefilter.fr = Texte (*.txt *.csv);;Tous (*.*) // @inputfilefilter.it = Testo (*.txt *.csv);;Tutti i files (*.*) /** * Parse the data and return the data to be imported as a tab separated file. */ function exec(inText) { // parse the inText and set to outText // in the return text the data is tab separated var outText = ""; outText += "Date\tDescription\tIncome\tExpenses\n"; outText += "2015-01-01\tIncome text\t100.25\t\n"; outText += "2015-01-02\tExpense text\t\t73.50\n"; return outText; }
Export Extensions
Export apps are used to export data in a custom format.
-
Define attribute @task as export.file
// @task = export.file -
Define the extension of the file to be exported.
// @exportfiletype = xml -
The text to be written to the export file is the return value of the exec function and must be a return.
return "exported text". -
When the script terminate and if the return text is not null and does not start with "@Cancel ", the user will be promped with a dialog to choose a file name where to export.
Example
Export all the accounting with description and balance in a xml file.
// @id = ch.banana.apps.export // @api = 1.0 // @pubdate = 2016-04-08 // @doctype = *.* // @description = Export into a text file (.txt) // @task = export.file // @exportfiletype = txt // @timeout = -1 function exec() { var exportResult = '<accounts>'; var tableAccounts = Banana.document.table('Accounts'); if ( !tableAccounts) { return; } for (i=0;i<tableAccounts.rowCount;i++) { if (tableAccounts.row(i).value('Account')) { exportResult += '<account>'; exportResult += '<accountnr>' + tableAccounts.row(i).value('Account') + '</accountnr>'; exportResult += '<description>' + tableAccounts.row(i).value('Description') + '</description>'; exportResult += '<balance>' + tableAccounts.row(i).value('Balance') + '</balance>'; exportResult += '</account>'; } } exportResult += '</accounts>'; //return the string return exportResult; }
Report Extensions
Report apps are java-script programs that are used to customize printouts like invoice documents. The main function printDocument() receives the json object from Banana, writes the document and lunches the result in a print preview window.
Copies of some report apps that you can use as starting point are available at the following address: github.com/BananaAccounting
Important notes
- Banana Accounting uses Qt script engine to execute report apps.
- Mandatory functions: printDocument(jsonInvoice, repDocObj, repStyleObj) which is the main function and settingsDialog() which is called from user to set up parameters like colour or additional text.
- Available json objects: invoice json object, statement json object, reminder json object
- The extension of custom report apps should be .js and the script must contains the main attributes, see Apps Attributes.
- The attribute @id of the script should correspond to the file name.
- System report apps are downloaded to the folder /User/.../AppData/Local/Banana.ch/.../Apps
(Mac Users: /Users/.../Library/Application Support/Banana.ch/.../Apps) - Do not overwrite system report apps because updates will overwrite your changes.
- You can save your report app anywhere, Banana Accounting saves the path to your app in the configuration file /AppData/Local/Banana.ch/.../Apps/apps.cfg
Invoice Extensions
Create personalized invoice report apps
We have published our templates on:
- How to create your own invoice
- github.com/BananaAccounting/Universal: in this section you will find different basic examples that works for every country.
- github.com/BananaAccounting/Switzerland: in this section you will find different basic examples made for Switzerland (with the Swiss ISR payment slip).
You can save a copy of one template in your computer and make the changes you wish. In order to use your custom template in Banana you have to:
- select the command Account2 - Customers - Print invoices...
- In the Print invoices dialog select Manage apps...
- In the Manage apps dialog select Add from file... and choose your invoice report file you just created
Extensions attributes
// @id = scriptfilename.js // @api = 1.0 // @pubdate = yyyy-mm-dd // @publisher = yourName // @description = script description // @task = report.customer.invoice
Report code
The main function is printDocument(jsonInvoice, repDocObj, repStyleObj). The parameter jsonInvoice object contains the data, repDocObj is the document object and repStyleObj is the stylesheet object where you can add styles.
function printDocument(jsonInvoice, repDocObj, repStyleObj) { var param = initParam(); var savedParam = Banana.document.getScriptSettings(); if (savedParam.length > 0) { param = JSON.parse(savedParam); param = verifyParam(param); } printInvoice(jsonInvoice, repDocObj, repStyleObj, param); }
The function settingsDialog() is called from Banana when you select the button Params... from dialog Manage apps. You can write any code you need for your script.
/*Update script's parameters*/ function settingsDialog() { var param = initParam(); var savedParam = Banana.document.getScriptSettings(); if (savedParam.length > 0) { param = JSON.parse(savedParam); } param = verifyParam(param); ... var paramToString = JSON.stringify(param); var value = Banana.document.setScriptSettings(paramToString); }
Printing custom data
You can add your own parameters in order to print specific data. For instance printing a reference order number or removing payments information if the invoice has already been paid.
if (invoiceObj.parameters.orderNo) { cell1.addParagraph("Reference order: " + invoiceObj.parameters.orderNo); }
Printing images
With the command addImage it is possible to add images into the document. For instance
var reportObj = Banana.Report; var repDocObj = reportObj.newReport(); repDocObj.addImage("documents:logo", "logoStyle"); var logoStyle = repStyleObj.addStyle(".logoStyle"); logoStyle.setAttribute("position", "absolute"); logoStyle.setAttribute("margin-top", "5mm"); logoStyle.setAttribute("margin-left", "20mm"); logoStyle.setAttribute("width", "120px");
If you set the width, the image will be resized to the given width. If the width is not specified the image will be printed with a 72dpi resolution.
Statement Extension
Create personalized statement report extension
We have published our templates on github.com/BananaAccounting. In this section you will find different basic examples.
You can save a copy of one template in your computer and make the changes you wish. In order to use your custom template in Banana you have to:
- select the command Account2 - Customers - Print statements...
- In the Print statements dialog select Manage apps...
- In the Manage apps dialog select Add from file... and choose your statement report file you just created
Extension attributes
// @id = scriptfilename.js // @api = 1.0 // @pubdate = yyyy-mm-dd // @publisher = yourName // @description = script description // @task = report.customer.statement
Report code
The main function is printDocument(jsonStatement, repDocObj, repStyleObj). The parameter jsonStatement object contains the data, repDocObj is the document object and repStyleObj is the stylesheet object where you can add styles.
function printDocument(jsonStatement, repDocObj, repStyleObj) { var param = initParam(); var savedParam = Banana.document.getScriptSettings(); if (savedParam.length > 0) { param = JSON.parse(savedParam); param = verifyParam(param); } printInvoice(jsonInvoice, repDocObj, repStyleObj, param); }
The function settingsDialog() is called from Banana when you select the button Params... from dialog Manage apps. You can write any code you need for your script.
/*Update script's parameters*/ function settingsDialog() { var param = initParam(); var savedParam = Banana.document.getScriptSettings(); if (savedParam.length > 0) { param = JSON.parse(savedParam); } param = verifyParam(param); ... var paramToString = JSON.stringify(param); var value = Banana.document.scriptSaveSettings(paramToString); }
Json Object
Statement Json Object
Data structure you can access through the report:
{ "customer_info": { "address1": "Viale Stazione 11", "business_name": "Rossi SA", "city": "Bellinzona", "first_name": "Andrea", "last_name": "Rossi", "number": "1100", "origin_row": "26", "origin_table": "Accounts", "postal_code": "6500" }, "document_info": { "date": "20160927", "decimals_amounts": 2, "description": "", "locale": "it", "number": "", "type": "statement" }, "items": [ { "balance": "540.00", "credit": "", "currency": "CHF", "date": "20160101", "debit": "540.00", "due_date": "20160131", "due_days": "240", "item_type": "invoice", "last_reminder": "", "last_reminder_date": "", "number": "10", "payment_date": "", "status": "", "total_amount_vat_exclusive": "", "total_amount_vat_inclusive": "", "total_vat_amount": "", "unit_price": { } }, { "balance": "540.00", "credit": "", "currency": "", "date": "", "debit": "540.00", "item_type": "total", "number": "", "status": "", "total_amount_vat_exclusive": "", "total_amount_vat_inclusive": "", "total_vat_amount": "", "unit_price": { } } ], "supplier_info": { "address1": "Indirizzo 1", "address2": "Indirizzo 2", "business_name": "Società", "city": "Loc", "email": "info@myweb", "first_name": "Nome", "fiscal_number": "numerofiscale", "last_name": "Cognome", "postal_code": "CAP", "web": "http://www.myweb" } }
Reminder Extensions Layout
Create personalized reminder report extensions
We have published our templates on github.com/BananaAccounting. In this section you will find different basic examples.
You can save a copy of one template in your computer and make the changes you wish. In order to use your custom template in Banana you have to:
- select the command Account2 - Customers - Print reminders...
- In the Print payment reminders dialog select Manage apps...
- In the Manage apps dialog select Add from file... and choose your reminder report file you just created
Extensions attributes
// @id = scriptfilename.js // @api = 1.0 // @pubdate = yyyy-mm-dd // @publisher = yourName // @description = script description // @task = report.customer.reminder
Report code
The main function is printDocument(jsonReminder, repDocObj, repStyleObj). The parameter jsonReminder object contains the data, repDocObj is the document object and repStyleObj is the stylesheet object where you can add styles.
function printDocument(jsonReminder, repDocObj, repStyleObj) { var param = initParam(); var savedParam = Banana.document.getScriptSettings(); if (savedParam.length > 0) { param = JSON.parse(savedParam); param = verifyParam(param); } printReminder(jsonReminder, repDocObj, repStyleObj, param); }
The function settingsDialog() is called from Banana when you select the button Params... from dialog Manage apps. You can write any code you need for your script.
/*Update script's parameters*/ function settingsDialog() { var param = initParam(); var savedParam = Banana.document.getScriptSettings(); if (savedParam.length > 0) { param = JSON.parse(savedParam); } param = verifyParam(param); ... var paramString = JSON.stringify(param); var value = Banana.document.setScriptSettings(paramString); }
Json Object
Reminder Json Object
Data structure you can access through the report:
{ "customer_info": { "address1": "Viale Stazione 11", "business_name": "Rossi SA", "city": "Bellinzona", "first_name": "Andrea", "last_name": "Rossi", "number": "1100", "origin_row": "26", "origin_table": "Accounts", "postal_code": "6500" }, "document_info": { "date": "20160927", "decimals_amounts": 2, "description": "", "locale": "it", "number": "", "type": "reminder" }, "items": [ { "balance": "540.00", "balance_base_currency": "540.00", "base_currency": "CHF", "credit": "", "credit_base_currency": "", "currency": "CHF", "date": "20160101", "debit": "540.00", "debit_base_currency": "540.00", "item_type": "invoice", "number": "10", "status": "1. reminder", "total_amount_vat_exclusive": "", "total_amount_vat_inclusive": "", "total_vat_amount": "", "unit_price": { } }, { "balance": "540.00", "balance_base_currency": "540.00", "base_currency": "", "credit": "", "credit_base_currency": "", "currency": "", "date": "", "debit": "540.00", "debit_base_currency": "540.00", "item_type": "total", "number": "", "status": "", "total_amount_vat_exclusive": "", "total_amount_vat_inclusive": "", "total_vat_amount": "", "unit_price": { } } ], "supplier_info": { "address1": "Indirizzo 1", "address2": "Indirizzo 2", "business_name": "Società", "city": "Loc", "email": "info@myweb", "first_name": "Nome", "fiscal_number": "numerofiscale", "last_name": "Cognome", "postal_code": "CAP", "web": "http://www.myweb" } }
Dialogs in Extensions
For simple interactions with the user you can use the predefined dialogs of the class Banana.Ui. With those dialogs you can ask the user to insert a value, answer a question, or show to the user an information.
For a more complex dialog:
- 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()
All the properties and public slots of the widgets in the dialogs will be accessible from the script.
Example: a script 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:
The script file ch.banana.scripts.find.js:
/** * 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]); } } } } }
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>