Invoice Layout Extension
The Invoice Layout Extension is a report extension for printing invoices.
It is used on the
- Accounting file
- Menu Reports > Customers > Print invoices...
- In the Estimate & Invoice
- Menu Invoices > Print invoice...
- Menu Invoices > Print estimate...
Structure of the extensions
The Invoice Layout Extension need to contains the following elements:
- The extension attribute with
@task = report.customer.invoice. - printDocument(jsonContent, repDocObj, repStyleObj [, prefSelected])
the main function that is called by the program
Is use the content of the invoice json object to add element to the reportDocObj. - settingsDialog() (optional)
called from user to set up parameters like colour or additional text. - getPrintPreferences() (optional)
returns a JSON object with the available print options.
Invoice Json Properties.
Extension attributes
// @id = scriptfilename.js // @api = 1.0 // @pubdate = yyyy-mm-dd // @publisher = yourName // @description = script description // @task = report.customer.statement
Function printDocument
The main function is printDocument(jsonStatement, repDocObj, repStyleObj [, format]). 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); }
Function settingsDialog
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); }
Invoice Json Object
Data structure used by the Invoice Layout Extension to print an invoice.
{
"billing_info": {
"discount": {
"amount_vat_exclusive": "2.20"
},
"due_date": "2020-06-17",
"total_advance_payment": "",
"total_amount_vat_exclusive": "122.15",
"total_amount_vat_exclusive_before_discount": "124.35",
"total_amount_vat_inclusive": "131.56",
"total_amount_vat_inclusive_before_discount": "133.93",
"total_categories": [],
"total_discount_percent": "1.8",
"total_discount_vat_exclusive": "2.20",
"total_discount_vat_inclusive": "2.37",
"total_rounding_difference": "",
"total_to_pay": "131.56",
"total_vat_amount": "9.41",
"total_vat_amount_before_discount": "9.58",
"total_vat_codes": [
{
"total_amount_vat_exclusive": "122.15",
"total_amount_vat_inclusive": "131.56",
"total_vat_amount": "9.41",
"vat_code": "V77"
}
],
"total_vat_rates": [
{
"total_amount_vat_exclusive": "122.15",
"total_amount_vat_inclusive": "131.56",
"total_vat_amount": "9.41",
"vat_rate": "7.70"
}
]
},
"creator_info": {
"name": "ch.banana.application.invoice.default",
"pubdate": "2021-09-24",
"publisher": "Banana.ch SA",
"version": ""
},
"customer_info": {
"address1": "Via ai Salici 12",
"address2": "",
"address3": "",
"business_name": "La stanza del Te SA",
"city": "Lugano",
"country": "",
"country_code": "CH",
"courtesy": "",
"email": "",
"first_name": "pinco",
"iban": "",
"last_name": "",
"mobile": "",
"number": "1",
"phone": "",
"postal_code": "6900",
"web": ""
},
"document_info": {
"currency": "CHF",
"customer_reference": "asdf",
"date": "2020-06-17",
"decimals_amounts": 2,
"description": "Fornitura merce (esempio iva esclusa)",
"doc_type": "10",
"locale": "it",
"number": "3",
"rounding_totals": "0.05",
"text_begin": "",
"title": "Fornitura merce (esempio iva esclusa)",
"vat_mode": "vat_excl"
"custom_info": [
{
"id": "custom_field_1",
"title": "Weight",
"value": "45 kg"
},
{
"id": "custom_field_2",
"title": "Packages",
"value": "3"
}
]
},
"items": [
{
"description": "Te\n1\n2\n3",
"item_type": "item",
"mesure_unit": "pz",
"number": "1000",
"price": "",
"quantity": "4.00",
"total": "",
"total_amount_vat_exclusive": "19.68",
"total_amount_vat_inclusive": "21.20",
"total_vat_amount": "1.52",
"unit_price": {
"amount_vat_exclusive": null,
"amount_vat_inclusive": "5.30",
"calculated_amount_vat_exclusive": "4.92",
"calculated_amount_vat_inclusive": "5.30",
"calculated_vat_amount": "0.38",
"vat_code": "V77",
"vat_rate": "7.70"
},
"vat_code": "",
"vat_rate": ""
},
{
"description": "Te",
"discount": {
"percent": "30."
},
"item_type": "item",
"mesure_unit": "pz",
"number": "1000",
"quantity": "4.00",
"total": "",
"total_amount_vat_exclusive": "13.78",
"total_amount_vat_inclusive": "14.84",
"total_vat_amount": "1.06",
"unit_price": {
"amount_vat_exclusive": null,
"amount_vat_inclusive": "5.30",
"calculated_amount_vat_exclusive": "4.92",
"calculated_amount_vat_inclusive": "5.30",
"calculated_vat_amount": "0.38",
"discounted_amount_vat_exclusive": "3.44",
"discounted_amount_vat_inclusive": "3.71",
"discounted_vat_amount": "0.27",
"vat_code": "V77",
"vat_rate": "7.70"
}
},
{
"description": "Te",
"discount": {
"amount": "1.60"
},
"item_type": "item",
"mesure_unit": "pz",
"number": "1000",
"quantity": "4.00",
"total": "",
"total_amount_vat_exclusive": "13.74",
"total_amount_vat_inclusive": "14.80",
"total_vat_amount": "1.06",
"unit_price": {
"amount_vat_exclusive": null,
"amount_vat_inclusive": "5.30",
"calculated_amount_vat_exclusive": "4.92",
"calculated_amount_vat_inclusive": "5.30",
"calculated_vat_amount": "0.38",
"discounted_amount_vat_exclusive": "3.44",
"discounted_amount_vat_inclusive": "3.70",
"discounted_vat_amount": "0.26",
"vat_code": "V77",
"vat_rate": "7.70"
}
},
{
"description": "Te",
"item_type": "item",
"mesure_unit": "pz",
"number": "",
"quantity": "10000",
"total_amount_vat_exclusive": "17.18",
"total_amount_vat_inclusive": "18.50",
"total_vat_amount": "1.32",
"unit_price": {
"amount_vat_exclusive": null,
"amount_vat_inclusive": "0.00185",
"calculated_amount_vat_exclusive": "0.00172",
"calculated_amount_vat_inclusive": "0.00185",
"calculated_vat_amount": "0.00013",
"vat_code": "V77",
"vat_rate": "7.70"
}
},
{
"description": "Te",
"discount": {
"amount": "0.00035"
},
"item_type": "item",
"mesure_unit": "pz",
"number": "1000",
"quantity": "10000",
"total": "",
"total_amount_vat_exclusive": "13.93",
"total_amount_vat_inclusive": "15.00",
"total_vat_amount": "1.07",
"unit_price": {
"amount_vat_exclusive": null,
"amount_vat_inclusive": "0.00185",
"calculated_amount_vat_exclusive": "0.00172",
"calculated_amount_vat_inclusive": "0.00185",
"calculated_vat_amount": "0.00013",
"discounted_amount_vat_exclusive": "0.00139",
"discounted_amount_vat_inclusive": "0.00150",
"discounted_vat_amount": "0.00011",
"vat_code": "V77",
"vat_rate": "7.70"
}
},
{
"description": "Te",
"discount": {
"percent": "3."
},
"item_type": "item",
"mesure_unit": "pz",
"number": "1000",
"quantity": "10000",
"total": "",
"total_amount_vat_exclusive": "16.67",
"total_amount_vat_inclusive": "17.95",
"total_vat_amount": "1.28",
"unit_price": {
"amount_vat_exclusive": null,
"amount_vat_inclusive": "0.00185",
"calculated_amount_vat_exclusive": "0.00172",
"calculated_amount_vat_inclusive": "0.00185",
"calculated_vat_amount": "0.00013",
"discounted_amount_vat_exclusive": "0.00167",
"discounted_amount_vat_inclusive": "0.00179",
"discounted_vat_amount": "0.00013",
"vat_code": "V77",
"vat_rate": "7.70"
}
},
{
"description": "Te",
"item_type": "item",
"mesure_unit": "pz",
"number": "",
"quantity": "0.00025",
"total_amount_vat_exclusive": "9.33",
"total_amount_vat_inclusive": "10.05",
"total_vat_amount": "0.72",
"unit_price": {
"amount_vat_exclusive": null,
"amount_vat_inclusive": "40200.00",
"calculated_amount_vat_exclusive": "37325.91",
"calculated_amount_vat_inclusive": "40200.00",
"calculated_vat_amount": "2874.09",
"vat_code": "V77",
"vat_rate": "7.70"
}
},
{
"description": "Te",
"discount": {
"amount": "8000"
},
"item_type": "item",
"mesure_unit": "pz",
"number": "1000",
"quantity": "0.00025",
"total": "",
"total_amount_vat_exclusive": "7.47",
"total_amount_vat_inclusive": "8.05",
"total_vat_amount": "0.58",
"unit_price": {
"amount_vat_exclusive": null,
"amount_vat_inclusive": "40200.00",
"calculated_amount_vat_exclusive": "37325.91",
"calculated_amount_vat_inclusive": "40200.00",
"calculated_vat_amount": "2874.09",
"discounted_amount_vat_exclusive": "29897.86",
"discounted_amount_vat_inclusive": "32200.00",
"discounted_vat_amount": "2302.14",
"vat_code": "V77",
"vat_rate": "7.70"
}
},
{
"description": "Te",
"discount": {
"percent": "25."
},
"item_type": "item",
"mesure_unit": "pz",
"number": "1000",
"quantity": "0.00025",
"total": "",
"total_amount_vat_exclusive": "7.00",
"total_amount_vat_inclusive": "7.54",
"total_vat_amount": "0.54",
"unit_price": {
"amount_vat_exclusive": null,
"amount_vat_inclusive": "40200.00",
"calculated_amount_vat_exclusive": "37325.91",
"calculated_amount_vat_inclusive": "40200.00",
"calculated_vat_amount": "2874.09",
"discounted_amount_vat_exclusive": "27994.43",
"discounted_amount_vat_inclusive": "30150.00",
"discounted_vat_amount": "2155.57",
"vat_code": "V77",
"vat_rate": "7.70"
}
},
{
"description": "Spese di spedizione",
"item_type": "item",
"mesure_unit": "",
"number": "4000",
"price": "",
"quantity": "1.00",
"total": "",
"total_amount_vat_exclusive": "5.57",
"total_amount_vat_inclusive": "6.00",
"total_vat_amount": "0.43",
"unit_price": {
"amount_vat_exclusive": null,
"amount_vat_inclusive": "6.00",
"calculated_amount_vat_exclusive": "5.57",
"calculated_amount_vat_inclusive": "6.00",
"calculated_vat_amount": "0.43",
"vat_code": "V77",
"vat_rate": "7.70"
},
"vat_code": "",
"vat_rate": ""
}
],
"note": [
{
"date": null,
"description": "aFASD\nF AS\nDF\n AS\nDF ASDF"
}
],
"payment_info": {
"due_date": "2020-07-17"
},
"supplier_info": {
"address1": "VIa alle colline 12",
"address2": "",
"address3": "",
"business_name": "My Company",
"city": "Lugano",
"country": "Svizzera",
"country_code": "CH",
"courtesy": "",
"email": "info@mycompany.zz",
"first_name": "",
"fiscal_number": "",
"iban_number": "CH93 0076 2011 6238 5295 7",
"last_name": "",
"mobile": "",
"phone": "+41 56 777 999",
"postal_code": "600",
"vat_number": "CHE-111.333.999 IVA",
"web": "https://www.mycompany.zz"
},
"type": "invoice",
"version": "1.0"
}
Invoice Json Properties Explanation
The Json has the following main elements:
- type
"invoice" - version
"1.0" - document_info
- Information relative to the invoice or estimate (currency, doctype,...)
- Initial texts, before Items
- payment_info
Invoice due date. - supplier_info
Address of the company that issue/send the invoice.customer_info - Address of one receiving the invoice.
- shipping_info
Shipping Address - items
The list of items - billing_info
Total of the invoices.note - note
Array that contains the notes, to be printed at the end. - parameters
Not used - template_parameters
- Texts that are defined in the Invoice Dialogs
- transactions
Payment information (not used in transactions)
Source of data
This list explains where the actual information on your invoice json object is coming from
Invoice Object Property | Source |
---|---|
customer_info.address1 | Table: Accounts, View: Address, Column: Street |
customer_info.address2 | Table: Accounts, View: Address, Column: AddressExtra |
customer_info.address3 | Table: Accounts, View: Address, Column: POBox |
customer_info.balance | Table: Accounts, View: Address, Column: Balance |
customer_info.balance_base_currency | Table: Accounts, View: Address, Column: BalanceCurrency |
customer_info.bank_account | Table: Accounts, View: Address, Column: BankAccount |
customer_info.bank_clearing | Table: Accounts, View: Address, Column: BankClearing |
customer_info.bank_name | Table: Accounts, View: Address, Column: BankName |
customer_info.business_name | Table: Accounts, View: Address, Column: OrganisationName |
customer_info.city | Table: Accounts, View: Address, Column: Locality |
customer_info.country | Table: Accounts, View: Address, Column: Country |
customer_info.country_code | Table: Accounts, View: Address, Column: CountryCode |
customer_info.courtesy | Table: Accounts, View: Address, Column: NamePrefix |
customer_info.credit_limit | Table: Accounts, View: Address, Column: CreditLimit |
customer_info.currency | Table: Accounts, View: Address, Column: Currency |
customer_info.date_birth | Table: Accounts, View: Address, Column: DateOfBirth |
customer_info.email | Table: Accounts, View: Address, Column: EmailWork |
customer_info.fax | Table: Accounts, View: Address, Column: Fax |
customer_info.first_name | Table: Accounts, View: Address, Column: FirstName |
customer_info.fiscal_number | Table: Accounts, View: Address, Column: FiscalNumber |
customer_info.iban_number | Table: Accounts, View: Address, Column: BankIban |
customer_info.lang | Table: Accounts, View: Address, Column: Language |
customer_info.last_name | Table: Accounts, View: Address, Column: FamilyName |
customer_info.member_fee | Table: Accounts, View: Address, Column: MemberFee |
customer_info.mobile | Table: Accounts, View: Address, Column: PhoneMobile |
customer_info.number | Table: Accounts, View: Address, Column: Account |
customer_info.payment_term_days | Table: Accounts, View: Address, Column: PaymentTermInDays |
customer_info.phone | Table: Accounts, View: Address, Column: PhoneMain |
customer_info.postal_code | Table: Accounts, View: Address, Column: PostalCode |
customer_info.state | Table: Accounts, View: Address, Column: Region |
customer_info.vat_number | Table: Accounts, View: Address, Column: VatNumber |
customer_info.web | Table: Accounts, View: Address, Column: Website |
document_info.currency | Invoice currency which usually corresponds to the customer account currency |
document_info.date | Table: Transactions, Column: DateDocument or Date |
document_info.decimals_amounts | Decimals are the same as the decimals used in the accounting file |
document_info.description | Not used |
document_info.doc_type | Table: Transactions, Column: DocType |
document_info.greetings | Table: Transactions, Column: DocType Transactions with DocType=10:gre If there are many rows with 10:gre the texts are joined with ','. More info... |
document_info.locale | Menu: File-File and accounting properties, Other, current Language |
document_info.number | Table: Transactions, Column: DocInvoice |
document_info.order_date | Table: Transactions, Column: DocType Transactions with DocType=10:ordd More info... |
document_info.order_number | Table: Transactions, Column: DocType Transactions with DocType=10:ordn More info... |
document_info.origin_row | Row index of source transaction |
document_info.origin_table | Table name of source transaction |
document_info.rounding_total | Default value for CHF: 0.05 You can overwrite this value with the menu command: Account2 - Customers - Settings - Advanced - Invoice rounding For multicurrency accounting: you can setup the rounding value for each currency in the table ExchangeRates, column DecimalPoints |
document_info.text_begin | Table: Transactions, Column: DocType Transactions with DocType=10:beg More info... |
document_info.type | invoice |
items | Table: Transactions All rows with the same invoice number and transaction date are invoice's items (lines) |
note | Table: Transactions, Column: DocType Transactions with DocType=10:not. More info... |
parameters | Table: Transactions, Column: DocType Transactions with DocType=10:par:key Key: any key text you wish Value: is taken from column Description More info... |
payment_info | Calculated from journal |
shipping_info | Delivery address if different from the invoice address (customer_info) Table: Transactions, Column: DocType Transactions with DocType=10:sadr More info... |
supplier_info.address1 | Menu: File-File and accounting properties, Address, Address 1 |
supplier_info.address2 | Menu: File-File and accounting properties, Address, Address 2 |
supplier_info.business_name | Menu: File-File and accounting properties, Address, Company |
supplier_info.city | Menu: File-File and accounting properties, Address, City |
supplier_info.country | Menu: File-File and accounting properties, Address, Country |
supplier_info.courtesy | Menu: File-File and accounting properties, Address, Courtesy |
supplier_info.email | Menu: File-File and accounting properties, Address, Email |
supplier_info.fax | Menu: File-File and accounting properties, Address, Fax |
supplier_info.first_name | Menu: File-File and accounting properties, Address, Name |
supplier_info.fiscal_number | Menu: File-File and accounting properties, Address, Fiscal Number |
supplier_info.last_name | Menu: FilevFile and accounting properties, Address, Family Name |
supplier_info.mobile | Menu: File-File and accounting properties, Address, Mobile |
supplier_info.phone | Menu: File-File and accounting properties, Address, Phone |
supplier_info.postal_code | Menu: File-File and accounting properties, Address, Zip |
supplier_info.state | Menu: File-File and accounting properties, Address, Region |
supplier_info.vat_number | Menu: File-File and accounting properties, Address, Vat Number |
supplier_info.web | Menu: File-File and accounting properties, Address, Web |
transactions | Table: Transactions All rows with the same invoice number and different transaction date, which are not considered invoice items, like payments transactions |
Layout Preferences Json Object
The function getPrintPreferences() returns a list of user-selectable preferences for printing an invoice in Json format.
Banana takes care of checking whether the getPrintPreferences() function exists in the script and whether it returns the available choices. If found, the layout preferences are displayed within the dialogue for printing invoices, if not, no choices are displayed.
Layout preferences depend on the selected layout type, currently, the returning layouts of the preferences are:
This feature is available only with the Advanced plan, those who own another plan still see the layout preference box but the choices are disabled.
The layout preferences the user can choose from are:
- Print as: The user can decide the type of document to print:
- Automatic (default, depends on invoice status).
- Invoice.
- Delivery note.
- Delivery note without amounts.
- Reminder (number 1,2 or 3).
Complete Json structure
This is the layout preferences structure with multiple elements, that serve as a reference for future implementation:
- version: JSON structure version
- id: Id of the structure.
- text: Name of the structure.
- base_options: Array of objects, each object represents a basic customization option, like the 'print as' options.
- advanced_options_function: Object that contains advanced customization options.
The script defines the language in which to return the Json object, the structure remains the same, only the texts in the 'text' fields change.
The Json code include comments that should not be present in the code.
{
"version" : "1.0",
"id": "invoice_available_layout_preferences",
"text":"Layout Preferences",
"base_options" : [
{
// first combo box
"id": "invoice_available_print_as",
"text": "Print as",
"print_as": [
{
"id":"automatic",
"text":"Automatic"
},
{
"id":"invoice",
"text": "Invoice"
},
{
"id":"delivery_note" ,
"text": "Delivery Note"
},
{
"id":"reminder_1",
"text": "Reminder 1"
},
{
"id":"reminder_2",
"text":"Reminder 2"
},
{
"id":"reminder_3",
"text": "Reminder 3"
}
],
"default": "automatic"
},
],
// button.
// When clicked the "function_name" is called
// Not yet implemented
"advanced_options_function" :{
"text": "Print options",
"function_name": "dialog_print_options"
}
}
Base preferences JSON structure example
The basic layout preferences concern more basic customisations, such as the document type (invoice status). The Json for the basic options is structured as follows:
- id: Id of the structure.
- text: Name of the structure.
- print_as: Array of objects, each object represents an available document type (or invoice status). Each element has an id and a text that is displayed in the combo box.
{
"version" : "1.0",
"id": "invoice_available_layout_preferences",
"text":"Layout Preferences",
"base_options" : [
{
"id": "invoice_available_print_as",
"text": "Print as",
"print_as": [
{
"id":"automatic",
"text":"Automatic"
},
{
"id":"invoice",
"text": "Invoice"
},
{
"id":"delivery_note" ,
"text": "Delivery Note"
},
{
"id":"reminder_1",
"text": "Reminder 1"
},
{
"id":"reminder_2",
"text":"Reminder 2"
},
{
"id":"reminder_3",
"text": "Reminder 3"
}
],
"default": "automatic"
}],
}
Advanced preferences JSON structure example
The advanced print options concern more detailed customisations. (to define)
{
"version" : "1.0",
"id": "invoice_available_print_preferences",
"text":"Layout Preferences",
"base_options" : [{/*Base options*/}],
"advanced_options_function" :{
"text": "Print options",
"function_name": "dialog_print_options"
}
Returned JSON structure example
Banana returns a Json with user-selected layout preferences to the invoice layout script.
This structure is passed to the script through printDocument function.
- version: JSON structure version
- id: Id of the structure.
- print_choices: Object that contains the print choices selected by the user. We send to the script the id of the preference choosed by the user.
In the following example, the user chose to print the third reminder, the value returned to the script, in this case 'reminder_3'.
{
"version" : "1.0",
"id": "invoice_available_layout_preferences",
"print_choices" : {
"print_as":"reminder_3",
//other preferences
},
}
Adapt Existing Invoice Layouts
In Banana Accounting Plus (Advanced plan only) you can take an existing invoice layout, modify it and use it as a new custom layout.
A layout is an Extension that is specific for printing an invoice.
The following steps describe how to adapt to your needs the existing [CH10] Layout with Swiss QR Code and [UNI11] Layout 11 Programmable Invoice layouts.
- Choose the layout to start from
- Save the layout files
- Modify the layout
- Add your layout to the Banana Extensions
- View an invoice with the custom template
Choose the layout to start from
On GitHub you can find the following layouts:
These layouts extensions are packed into .sbaa files that include all the required files needed to run the extensions.
- CH10 Swiss layout, ch.banana.ch.invoice.ch10.sbaa:
- ch.banana.ch.invoice.ch10.js
The javascript code of the layout. - ch.banana.ch.invoice.ch10.texts.js
The javascript code of the layout texts. - ch.banana.ch.invoice.ch10.parameters.js
The javascript code of the layout parameters. - ch.banana.ch.invoice.ch10.printpreferences.js
The javascript code of the layout preferences. - invoice.css
The css stylesheet code. - swissqrcode.js
The javascript code of the QR Code part. - checkfunctions.js
The javascript code of some check functions.
- ch.banana.ch.invoice.ch10.js
- UNI11 Universal layout, ch.banana.uni.invoice.uni11.sbaa:
- ch.banana.uni.invoice.uni11.js
The javascript code of the layout. - ch.banana.uni.invoice.uni11.texts.js
The javascript code of the layout texts. - ch.banana.uni.invoice.uni11.parameters.js
The javascript code of the layout parameters. - ch.banana.uni.invoice.uni11.printpreferences.js
The javascript code of the layout preferences. - invoice.css
The css stylesheet code.
- ch.banana.uni.invoice.uni11.js
Save the layout files
Choose the layout you want to start from and download all the files included in the .sbaa package on your computer.
- Open the links above.
- Right click on the page.
- Select Save page.
All the files must be saved in the same directory.
Modify the layout
- Open the local file ch.banana.ch.invoice.ch10.js or ch.banana.uni.invoice.uni11.js with a text editor program.
- Right click on the file.
- Open with and select the text editor program.
- Change the @id with a new one.
Each new invoice layout must have a different @id text. - Change the @description with a new one.
The description will appear in the print dialog window when selecting the invoice layout. - Modify then the script as you want.
Find more information about the content of the Json Object of the invoice. - Save the file.
Add your layout to the Banana Extensions
At this point you can choose the way you want to add the layout to the Banana Extensions.
You have two options:
- Install the layout without recreating a new package.
- This can be useful if you don't need to share the layout with someone else, and also if you want to test your changes faster.
- From Banana, menu Extensions → Manage Extensions.
- Click on the button Add from file... and choose the file you just downloaded and modified (ch.banana.ch.invoice.ch10.js or ch.banana.uni.invoice.uni11.js).
- Create a new Extension Package (.sbaa file).
- This can be useful if you need to share the layout with someone else.
- Use the following manifest and QRC files and adapt them as you need:
- ch.banana.ch.invoice.ch10.manifest.json
- Open the link, right click on the page, select Save page.
- Open the file using a text editor program and change description and title.
- ch.banana.ch.invoice.ch10.qrc.
- ch.banana.ch.invoice.ch10.manifest.json
- From Banana, menu Extensions → Manage Extensions.
- Click on the button Add from file... and choose the file .sbaa you just created.
Important: Do not delete the extension file from your pc or move it to another directory after the installation, otherwise the extension will no longer work. If you want to move the extension to another directory, you must reinstall it from the new location.
View an invoice with the custom layout
- From Banana, menu Reports → Customers → Print Invoices select the layout you just added.
- Confirm with Ok to see the preview.
Customize Invoice Layout
With the Advanced plan of Banana Accounting Plus, you can create your own Invoice Layout.
A Layout is an Extension that is specific for printing an Invoice.
The following steps describe how to create an invoice template starting from an existing one and adapting it to your needs.
Choose your print style
- From the Banana program, select menu Extensions > Manage Extensions...
- Select Online > Invoice.
- Choose one of the existing templates (i.e. [UNI01] Layout 1)
- Click on Show details.
- Click on URL.
Save the layout's script
A page with the JavaScript code opens. Save the script file to your documents folder (menu File > Save Page As) or right click somewhere on the page > Save As.
Modify the template
- Open the local file with a text editor program
- Right click on the file.
- Open with .... and select the text editor program.
- Change the @description and the @id.
- Save the file.
Add your layout to the Banana extensions
- From the Banana program, menu Extensions > Manage Extensions....
- Click on the button Add from file... and choose the file you just downloaded and modified.
View an invoice with the custom template.
- In menu Reports > Customers > Print Invoices select the layout Smith & Co. Invoice.
- Click Ok.
Preview:
Additional changes
The images below illustrates how to carry out the following changes to your layout.
- How to change the header position to the right:
- Modify the lines as described here (see from row 683 to 686). Save changes.
- How to change the text "Customer No" to "Customer"
See your changes
Simply click on the refresh button
Exporting Invoices to XML
This page explains how to create a Banana Accounting Javascript Extension, that creates the invoice in a specific format. The explanation takes as example the extension Fattura Elettronica , which exports electronic invoices according to Italian B2B standards in XML format.
The Extension has the following steps:
- Use the Banana API, to retrieve the list invoicesCustomers in Json format.
- InvoiceCustomers includes the Invoice objects.
- For the Italian export it is necessary to have also information regarding the Tax code. This supplementary information is calculated by the VAT Extension. That is why the Extensions includes different files.
- The user is given the ability to enter data. So a dialog is displayed with the information required.
See Extension documentation in Italian. - The Extension can also have parameters that can be set with the settings dialog.
- Once you have all the information, you need to convert the data in the format that you need. In the Italian case, the invoice is in the XML format that follows the specific requirements.
- At the end, the Extension calls a function that prompts the user to specify the file where he wants to save the XML data.
- The Extension for Italy also includes a possibility to have a preview of the invoice and export it in PDF.
References:
- Information on creating invoices in Banana is available in our Invoicing documentation.
- All the code reported can be found in the following folder: Italia/Fatture elettroniche/B2B/
- Build you first Extension.
Attributes list
Each extension must declare some attributes in order to run in Banana environment. For more info see Extension's Attributes page
- @id: this is the script ID. It will be used by getScriptSettings() and setScriptSettings() to save params values for this script
- @includejs: ch.banana.it.invoice.it05.js this is the invoice template used to print out the invoice in preview and PDF format.
- @includejs: ch.banana.script.italy_vat_2017.journal.js this file contains the class Journal, used to retrieve transactions and customer info such as adresses. Other includes are dependencies of ch.banana.script.italy_vat_2017.journal.js
// @id = ch.banana.it.efattura.b2b // @api = 1.0 // @pubdate = 2019-04-25 // @publisher = Banana.ch SA // @description = [BETA] Fattura elettronica (XML, PDF)... // @description.it = [BETA] Fattura elettronica (XML, PDF)... // @doctype = * // @task = app.command // @inputdatasource = none // @timeout = -1 // @includejs = ch.banana.it.invoice.it05.js // @includejs = ch.banana.script.italy_vat_2017.errors.js // @includejs = ch.banana.script.italy_vat_2017.journal.js // @includejs = ch.banana.script.italy_vat.daticontribuente.js // @includejs = ch.banana.script.italy_vat_2017.xml.js
Function exec()
The exec() function is the main function, which is called when the extension is executed. This function does the following:
- loads user parameters
- creates an EFattura-class object
- the EFattura object loads data according to user parameters
- the EFattura object issues invoices in xml format or in print preview
function exec(inData, options) {
...
// creates the EFattura object that contains the logic to load the invoices
// and transform them into the required formats
var eFattura = new EFattura(Banana.document);
if (!eFattura.verifyBananaVersion())
return "@Cancel";
// user params can be retrieved using the method Banana.document.getScriptSettings()
// they are saved in the system table syskey using the method Banana.document.setScriptSettings()
var param = {};
...
param = JSON.parse(Banana.document.getScriptSettings());
...
eFattura.setParam(param);
//loadData() retrieves data from table invoicesCustomers() and returns an array of json invoices grouped by customer
var jsonCustomerList = eFattura.loadData();
...
//output the data according to user param (xml or pdf)
if (eFattura.param.output == 0) {
var docs = [];
var styles = [];
for (var i in jsonCustomerList) {
var jsonInvoices = jsonCustomerList[i];
for (var j = 0; j < jsonInvoices.length; j++) {
var jsonInvoice = jsonInvoices[j];
if (jsonInvoice.customer_info) {
var repDocObj = Banana.Report.newReport('');
var repStyleObj = Banana.Report.newStyleSheet();
eFattura.createReport(jsonInvoice, repDocObj, repStyleObj);
docs.push(repDocObj);
styles.push(repStyleObj);
}
}
}
if (docs.length) {
Banana.Report.preview("", docs, styles);
}
}
else {
//output xml
for (var i in jsonCustomerList) {
var jsonInvoices = jsonCustomerList[i];
var xmlDocument = Banana.Xml.newDocument("root");
var output = eFattura.createXml(jsonInvoices, xmlDocument, true);
if (output != "@Cancel") {
var xslt = "";
var outputStyled = output.slice(0, 39) + xslt + output.slice(39);
eFattura.saveFile(outputStyled);
}
}
}
}
Class EFattura()
This class contains all the logic of the application in order to print out the invoices. The costructor initializes some variables.
function EFattura(banDocument) {
this.banDocument = banDocument;
...
this.name = "Banana Accounting EFattura";
this.version = "V1.0";
this.helpId = "ch.banana.it.efattura.b2b.js";
this.errorList = [];
/* errors id*/
this.ID_ERR_ACCOUNTING_TYPE_NOTVALID = "ID_ERR_ACCOUNTING_TYPE_NOTVALID";
...
this.initParam();
this.initNamespaces();
this.initSchemarefs();
}
EFattura.initParam()
This method initializes the class parameters, which will resume user-set values using the setParam() method and the settingsDialog() function.
EFattura.prototype.initParam = function () {
this.param = {};
/*output format 0=pdf, 1=xml*/
this.param.output = 0;
/*selection 0=single invoice, 1=single customer 2=all*/
this.param.selection = 0;
/*invoice number*/
this.param.selection_invoice = '';
/*customer number*/
this.param.selection_customer = '';
/* periodSelected 0=none, 1=1.Q, 2=2.Q, 3=3Q, 4=4Q, 10=1.S, 12=2.S, 30=Year */
this.param.periodAll = true;
this.param.periodSelected = 1;
this.param.periodStartDate = '';
this.param.periodEndDate = '';
/*params for xml format*/
this.param.xml = {};
this.param.xml.progressive = '1';
this.param.xml.open_file = false;
this.param.xml.destination_folder = '';
/*params for pdf format*/
this.param.report = {};
this.param.report.print_header = true;
this.param.report.print_logo = true;
this.param.report.print_quantity = false;
this.param.report.font_family = '';
this.param.report.color_1 = '#337ab7';
this.param.report.color_2 = '#ffffff';
this.param.report.header_row_1 = '';
this.param.report.header_row_2 = '';
this.param.report.header_row_3 = '';
this.param.report.header_row_4 = '';
this.param.report.header_row_5 = '';
this.param.report.footer = '';
}
EFattura.loadData()
The loadData() declares the following objects:
- this.journal: this is an object available from the script Iva Italia. The journal contains all the accounting transactions and the list of customers, including their addresses.
In order to use this object you need to include the file ch.banana.script.italy_vat_2017.journal.js using the statement @includejs = ch.banana.script.italy_vat_2017.journal.js in the attribute list of the script.
- this.journalInvoices: this can be loaded directly from Banana.document.invoicesCustomers and contains all invoices.
EFattura.prototype.loadData = function () {
//loads transactions, the journal is declared in script /iva/2017/ch.banana.script.italy_vat_2017.journal.js
//the journal is used for retrieving the following data: "IT_TipoDoc" (type of document), "IT_Natura" (nature of the transaction)
//see @includes at the beginning of this script
if (!this.journal) {
this.journal = new Journal(this.banDocument);
this.journal.excludeVatTransactions = true;
this.journal.load();
}
//loads list of invoices using the Banana.document object
if (!this.journalInvoices) {
this.journalInvoices = this.banDocument.invoicesCustomers();
}
var jsonInvoiceList = [];
//if invoice filter is defined and invoice number is empty, no invoice is returned
if (this.param.selection == 0 && this.param.selection_invoice.length <= 0)
return jsonInvoiceList;
//if customer filter is defined and customer number is empty, no invoice is returned
if (this.param.selection == 1 && this.param.selection_customer.length <= 0)
return jsonInvoiceList;
//if tax payer data is not defined, no invoiced is returned
if (!this.initDatiContribuente())
return jsonInvoiceList;
//set period of the transactions to be loaded
var periodAll = this.param.periodAll;
var startDate = this.param.periodStartDate;
var endDate = this.param.periodEndDate;
for (var i = 0; i < this.journalInvoices.rowCount; i++) {
var tRow = this.journalInvoices.row(i);
//the column 'ObjectJSonData', in the table journalInvoices, contains the invoice object
if (tRow.value('ObjectJSonData') && tRow.value('ObjectType') === 'InvoiceDocument') {
var jsonData = {};
jsonData = JSON.parse(tRow.value('ObjectJSonData'));
var addInvoice = true;
if (parseInt(this.param.selection) === 0 && jsonData.InvoiceDocument.document_info.number !== this.param.selection_invoice) {
addInvoice = false;
}
if (parseInt(this.param.selection) === 1 && jsonData.InvoiceDocument.customer_info.number !== this.param.selection_customer) {
addInvoice = false;
}
if (addInvoice && !periodAll) {
if (jsonData.InvoiceDocument.document_info.date < startDate || jsonData.InvoiceDocument.document_info.date > endDate) {
addInvoice = false;
}
}
if (addInvoice) {
jsonInvoiceList.push(jsonData.InvoiceDocument);
}
}
}
if (jsonInvoiceList.length<=0) {
var msg = this.getErrorMessage(this.ID_ERR_NOINVOICE);
this.addMessage(msg, this.ID_ERR_NOINVOICE);
}
//data is grouped by customer because the xml file can contain only one customer per file
//if many customers are printed, these will be splitted into many files
var jsonCustomerList = {};
for (var i = 0; i < jsonInvoiceList.length; i++) {
var jsonInvoice = jsonInvoiceList[i];
if (jsonInvoice.customer_info) {
var accountId = jsonInvoice.customer_info.number;
if (!jsonCustomerList[accountId])
jsonCustomerList[accountId] = [];
jsonCustomerList[accountId].push(jsonInvoice);
}
}
return jsonCustomerList;
}
EFattura.createReport(jsonInvoice, report, stylesheet)
The createReport() generates the preview of the invoice. If you wish to change the layout of the invoice you can modify or replace the script ch.banana.it.invoice.it05.js
@jsonInvoice: this is the json invoice object which contains all data to print out
@report: this is the Banana.Report.ReportElement object which permits you to preview and print out the data
@stylesheet: this is the Banana.Report.ReportStyleSheet object which contains all css information for printing out the report.
//print the single invoice to the object report,
//the methods printInvoice and setInvoiceStyle are declared in the file ch.banana.it.invoice.it05.js
if (jsonInvoice && jsonInvoice.customer_info) {
printInvoice(jsonInvoice, report, stylesheet, this.param.report);
...
setInvoiceStyle(report, stylesheet, this.param.report);
stylesheet.addStyle("@page").setAttribute("margin", "0");
}
EFattura.createXml(jsonInvoiceList, xmlDocument, indent)
The createXml() generates the xml code of the invoice. The XML file will contains one or more invoices of a single customer.
@jsonInvoiceList: this is an array with the list of invoices which belong to a single customer
@xmlDocument: this is a Banana.Xml.XmlElement which contains all XML data
@indent: if true the string xml will be indented and formatted with spaces
if (!xmlDocument || jsonInvoiceList.length<=0)
return "@Cancel";
var nodeRoot = this.createXmlHeader(jsonInvoiceList[0], xmlDocument);
if (!nodeRoot || this.isEmpty(nodeRoot))
return "@Cancel";
for (var i = 0; i < jsonInvoiceList.length; i++) {
this.createXmlBody(jsonInvoiceList[i], nodeRoot);
}
return Banana.Xml.save(xmlDocument, indent);