In this article
The DocumentChange API allows extensions to change the content or any open Banana Accounting file.
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
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.
The user can preview the changes and approve or discard:
- Create 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 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.
Document Change Json
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 using a DocumentChange
The extension create a DocumentChange and return to the program.
// Creates a JSON DocumentChange which adds a row to the transaction table.
//
// @id = ch.banana.example.documentpatch
// @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": "20240325",
"Description": "Total sales 25-03-2024",
"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;
}
Structure of DocumentChange
The documentChange 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": "2019-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": "2019-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": "2019-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.
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": "2019-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": "2019-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": "2019-01-05",
"Description": "Sell of goods",
"AccountDebit": "1001",
"AccountCredit": "3000",
"Amount": "1500"
},
"operation": {
"name": "add"
}
}
]
}]
},
"nameXml": "Transactions"
}]
}
}]
}
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)
- id document identifier (usually empty).
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;
- add, add a new row
- name define the type of operation
- 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.
- fields Is an Object which with the column names that are going to be modified and the value.
- rows Is an array containing all the rows can be also defined as "Views" when we are working with columns
- viewList Is an object containing the array views
- views Is an array containing views
- view Is an array of columns
- views Is an array containing views
Convenience class for Document change
The DocumentChange class provide a convenient way to create a Document change JSon.