Retail:Developers Guide/How-to/IndexedDBMigrationGuide
Contents
|
Introduction
As of 20Q4 release, the WebPOS is no longer using WebSQL to store any information, and instead uses IndexedDB across the whole application. All usage of WebSQL is no longer supported, our WebSQL-based API is deprecated and will be removed in some future release.
Therefore, all developers are encouraged to migrate all their WebSQL-based code to the newer IndexedDB APIs.
On top of this, even in 20Q4 some existing APIs and hooks have been either deprecated or removed, so all developers that need their custom code to work in 20Q4 will need to make adjustments to it.
This document is a general guide that walks developers through the process of updating their code so that it works correctly in 20Q4 and newer releases, using our new IndexedDB-based APIs.
Usage of WebSQL and IndexedDB
WebSQL and IndexedDB are used essentially with the same purpose in Openbravo. Both technologies allow the application to store data that is required for it to work correctly in offline. This includes:
- Masterdata information (like products, prices or discounts)
- Transactional information (like draft tickets, cashup information, or document sequences)
- Offline login required information
- Synchronisation information (data that needs to be synchronised to the server)
All this information was stored in WebSQL in previous versions of Openbravo. Starting 20Q4, all this information is now stored in IndexedDB
However, Openbravo does not exactly use IndexedDB in the same way that WebSQL was used before. Instead, there are significant differences that developers need to take into account
Databases
Previously, only one WebSQL database was created per application. Data of all types (masterdata, transactional, offline login-related) was stored in this database.
Instead, now a separate IndexedDB database is created per each data type. So currently four IndexedDB databases exist per application:
- Masterdata
- Application state (transactional information)
- Offline login
- Synchronization buffer (for data pending to be synchronised with the backend server).
APIs
Previously, we had a single, combined API that was used for every database operation. This API was used across the board to do any database-related operation, from reading products, to saving the ticket.
This was a source of several problems, like unwillingly exposing to developers the ability to modify models that should in general not be modifiable by normal means (like masterdata records that might later on be overwritten by the incremental refresh process).
On IndexedDB, each type of data that can be either read or modified has its own specialised APIs and components. There are two main APIs:
- MasterdataController: This component allows developers to define Masterdata models, and query the Masterdata database.
- StateController: This API allows developers to define State models and actions, extend actions via hooks, and dispatch actions on the application state.
These APIs are also very different from the previous OB.Dal API that was used to do operations in WebSQL:
- They are based on Javascript promises instead of callbacks
- They no longer use Backbone anymore, and instead use plain Javascript objects
- They are specialised, and each provide developers the right functionality instead of exposing the whole database implementation.
As an example of this last statement, the MasterdataController allows developers to define models, and to query the database in several different ways, but does not allow developers to modify the database records directly, because the Masterdata refresh process in general has the responsibility of updating this data correctly.
Similarly, the StateController API allows developers to define models and actions, and dispatch actions on the state, but the details about the persistence of the data in the database is handled internally by the controller, and is not exposed to the developer.
It is very important that all developers know well both main APIs before any migration process is attempted.
We have separate documents that describe the MasterdataController and the StateController APIs, and developers should read them before continuing with the next sections.
Migration Process
This section will describe the main steps that should be followed when approaching the migration of custom code to IndexedDB and the newer APIs.
The general idea is that for any custom piece of code, module or modules for a particular customer, all individual functionality must be reviewed to understand the current usage of WebSQL, and then specific migration steps need to be followed for each component.
Identification of WebSQL usage
The first step in the migration process is to identify which parts of the code are using WebSQL or our old business logic components or hooks, and what they are using them for.
As a general rule, the following code will need to be adjusted:
Masterdata models
Any code creating Backbone models that are registered later as Masterdata models by doing some code similar to:
OB.Data.Registry.registerModel(OBCOMBO_Product); OB.OBPOSPointOfSale.Model.PointOfSale.prototype.models.push(OBCOMBO_Product);
will need to be updated to use the MasterdataController infrastructure
Synchronised models
Any code creating Backbone models that are registered later as a 'synchronised model' by registering it in the synchronised models array:
OB.MobileApp.model.get('dataSyncModels').push({ model: OB.Model.TerminalMonitor, className: 'org.openbravo.certification.france.terminalmonitor.ProcessTerminalMonitor', criteria: {} });
will need to be refactored into an action dispatched on the new StateController.
Transactional models saved in WebSQL
Sometimes Backbone models were persisted into the WebSQL database by using the initCache function and then saving it in the table:
OB.Dal.initCache(OB.Model.MyModel); OB.Dal.save(OB.Model.MyModel);
In general if a model was saved by using the OB.Dal.save function, it will have to be refactored into a State Model, and some actions to save/update it in the state will also have to be created using the StateController API.
Deprecated/removed hooks
As part of the transition to IndexedDB state, some very central parts of the business logic of the application has been completely reimplemented. This includes all basic Ticket functionality like:
- Ticket creation
- Ticket deletion
- Adding products/removing lines
- Adding/removing payments
- Completing tickets
As part of this reimplementation, some hooks have been deprecated (and lost some functionality in the process), and others have been deleted.
In the coming section we will provide a list of all affected hooks. You should review your code to see if any of them is being used. If that's the case, the code will need to be refactored using some combination of ActionPreparation/ActionHooks, provided by the StateController.
Migration of Masterdata code
For the topic of masterdata migration, we have a separate document that explains the necessary steps to migrate any masterdata-related code to IndexedDB.
Migration of synchronised models
Synchronised models were a mechanism that was used to synchronise data to the backend using a WebSQL-based model. The main idea was:
- There is a WebSQL table (defined through a Backbone model) that contains records that might or might not be ready to be persisted yet.
- The model is then registered as a synchronisedModel, specifying the Java class that should handle the data in the backend, and a criteria to know if a record is ready to be synchronised or not.
- When data needs to be synchronised code had to call the runSyncProcess function. This function transformed records ready to be synchronised into "messages", that later on were saved into the backend as ImportEntries
- These ImportEntries were then processed asynchronously by calling the Java class specified in the dataSyncModel definition.
Some of these principles still remain in our new layer, but if code is using a synchronisedModel to synchronise data to the backend, some parts need to be refactored.
The following steps must be followed:
- A StateModel can be created to save the information that needs to be synchronised in the state, if it needs to be persisted to be manipulated later. This is not mandatory, and in fact it is not recommended if information just needs to be synchronised to the backend
- Regardless of this, a new action must be implemented using the StateController. This action must create a new "Message" in the Messages array in the state. The following code can be used as an example:
OB.App.StateAPI.Global.registerAction( 'synchronizeLoyaltyEarnedPoints', (state, payload) => { const newState = { ...state }; const newObject = { id: OB.App.UUID.generate(), ...payload }; const data = { modelName: 'LoyaltyEarnedPoints', service: 'org.openbravo.retail.loyalty.programs.process.LoyaltyEarnedPointsLoader', newObject: payload, }; const backendMsg = OB.App.State.Messages.Utils.createNewMessage( data.modelName, data.service, newObject, { type: 'backend' } ); newState.Messages = [...newState.Messages, backendMsg]; return newState; } );
This is, in fact, the only required step. This action will create a new message and add it to the array of messages currently in the system. This message contains essentially the same information the dataSyncModels previously contained: the modelName, and the service (the class that will be used in the backend to process the data).
Once the message is added to the state, it will automatically be persisted in the IndexedDB state database. Then, a separate component called Synchronisation Buffer will pick the message and ensure it is synchronised. The rest of the process doesn't change: an ImportEntry will be created and the data will be processed asynchronously, as before.
In order to actually synchronise data, the action must be dispatched, by doing:
OB.App.State.Global.synchronizeLoyaltyEarnedPoints({ loyaltyProgram: 'MyLoyaltyProgram', points: 100 });
Migration of Transactional state persisted models
Transactional models might be persisted in WebSQL, by creating a Backbone model and then using the OB.Dal API to save records in the corresponding table.
The equivalent to this in the new IndexedDB API is the StateModels, that can be registered using the StateController API. By registering a StateModel, you reserve a property in the state, which you can set using actions defined on this model. You need to define actions to set the value of the model, or process it the way you want.
There is no need to actually persist anything explicitly, because any StateModel will be automatically persisted in IndexedDB after any action is dispatched for it.
You can find clear examples on how to define these models in the StateController main document.
As part of the IndexedDB project, a very large part of the WebPOS business logic was refactored to use the new StateController API.
This refactor in many cases meant that functionality that previously was divided in parts and worked non-transactionally was transformed into a transactional action. Because of this, some intermediate hooks had to be removed.
On top of this, some hooks were also removed because the actions themselves already provide a new infrastructure of ActionPreparations and ActionHooks that have great advantages compared to the old ones.
Some of the hooks were not fully removed though, but all of the hooks related to refactored logic should be considered deprecated, and we strongly encourage all developers to refactor all their functionality based on old hooks as ActionPreparations or ActionHooks whenever possible.
The following is a list of all hooks affected by the changes, with their current status:
Functionality | Hook | Status | Notes |
Ticket completion | OBPOS_PreOrderSave | Deprecated | Still basically functional, but recommended not to be used. Payment rounding and adjustment now happens inside the action, which means that the hook will receive the original payments instead of the final ones. |
Ticket completion | OBPOS_PostSyncReceipt | Deprecated | Still functional, but should only be used for visualisation purposes. All related business logic/state changes should be done in a PostActionHook of the ticket completion action instead. |
Ticket completion | OBPOS_PostPaymentDone | Removed | |
Ticket completion | OBPOS_preAddPayment | Deprecated | Still exists in main payment actions (payment addition/deletion). However, keep in mind that it was removed from the ticket completion flows. |
Ticket completion | OBPOS_postAddPayment | Deprecated | Still exists in main payment actions (payment addition/deletion). However, keep in mind that it was removed from the ticket completion flows. |
Ticket completion | OBPOS_PreSyncReceipt | Removed | Should be replaced by a combination of ActionPreparation/ActionHooks for the related ticket completion actions |
Ticket deletion | OBPOS_PreDeleteCurrentOrder | Removed | Should be replaced by a combination of ActionPreparation/ActionHooks for the related 'deleteTicket' action |
Ticket payments | OBPOS_preRemovePayment | Removed | |
Pay Open Tickets | OBPOS_MultiOrders_PreSetPaymentsToReceipt | Removed | |
Pay Open Tickets | OBPOS_MultiOrderAddPaymentLine | Removed | |
Ticket creation | OBPOS_NewReceipt | Removed | Should be replaced by a combination of ActionPreparation/ActionHooks for the related 'addNewTicket' action |
Ticket price modification | OBPOS_PreSetPrice | Removed | Should be replaced by a combination of ActionPreparation/ActionHooks for the related 'setLinePrice' action |
Ticket line deletion | OBPOS_CheckStockDeleteLine | Removed | |
Ticket line deletion | OBPOS_PreDeleteLine | Removed | Should be replaced by a combination of ActionPreparation/ActionHooks for the related 'deleteLine' action |
Ticket line deletion | OBPOS_PostDeleteRelatedServices | Removed | |
Ticket line deletion | OBPOS_PreDeleteSingleLine | Removed | |
Ticket line deletion | OBPOS_PostDeleteLine | Removed | |
Adding products to ticket | OBPOS_CheckStockAddProduct | Removed | Although the code is still there because the old flow is still executed in some cases, the hook itself will not be executed for the main flows |
Adding products to ticket | OBPOS_GroupedProductPreCreateLine | Removed | |
Adding products to ticket | OBPOS_AddProductToOrder | Removed | Should be replaced by a combination of ActionPreparation/ActionHooks for the related 'addProduct' action |
Adding products to ticket | OBPOS_PostAddProductToOrderHook | Removed | |
Ticket payments | OBPOS_preRemovePayment | Removed | Should be replaced by a combination of ActionPreparation/ActionHooks for the related 'removePayment' action |
Ticket list manipulation | OBPOS_PostAddPaidReceipt | Removed |