How to add an algorithm to level pricing infrastructure
Introduction
As explained in the module documentation, level pricing infrastructure needs algorithms in order to work. These algorithms indicates which way will be followed to set prices. These prices are set based on the information stored in the level pricing infrastructure. Normally, each algorithm will correspond with a module which will contain the algorithm for ERP and (optionally) for Openbravo Web POS.
Module dependencies
If your algorithm will be used just in the ERP side (sales order window) the module will depend on Level pricing infrastructure module. However if your module will work also in Openbravo Web POS, it will depend on Retail level pricing module. It happens because is needed to move level pricing information to Web POS side.
In this how to we are going to implement an algorithm to be used in Openbravo ERP and in Openbravo Web POS, so it will depend on Retail level pricing module.
Step 1: Create the module to store the algorithm
Step 2: Register the algorithm into the list of available algorithms
Step 3: Configure a product to use the new algorithm
Step 4: Develop the algorithm for ERP Side
To develop the algorithm for ERP we will take advantage of the hook called "OrderLineQtyChangedHook". This hook is executed when some events happens in an order line.
In the implementation we should select the price and then return it to the main flow.
package org.openbravo.pricing.averagelevelpricing.hooks; import java.math.BigDecimal; import java.util.Date; import java.util.List; import javax.enterprise.context.ApplicationScoped; import org.hibernate.criterion.Restrictions; import org.openbravo.common.hooks.OrderLineQtyChangedHook; import org.openbravo.common.hooks.OrderLineQtyChangedHookObject; @ApplicationScoped public class OrderLineQtyChangedHookImplementation implements OrderLineQtyChangedHook { @Override public void exec(OrderLineQtyChangedHookObject hookObj) throws Exception { BigDecimal newPrice = null; //Check if the changed field is the quantity if (hookObj.getChanged().equals("inpqtyordered")) { //TODO //Here goes the code to select the price newPrice =BigDecimal.TEN; //The new price is returned through hookObj if (newPrice != null) { hookObj.setPrice(newPrice.equals("") ? BigDecimal.ZERO : newPrice.setScale( hookObj.getPricePrecision(), BigDecimal.ROUND_HALF_UP)); } else { hookObj.setPrice(hookObj.getPrice()); } } } }
Step 5: Develop the algorithm for Openbravo Web POS
Create a component provider to serve JS files
We need a server side component to serve our JS files to Openbravo Web POS. This component is called component provider.
package org.openbravo.pricing.averagelevelpricing; import java.util.ArrayList; import java.util.List; import java.util.Map; import javax.enterprise.context.ApplicationScoped; import org.openbravo.client.kernel.BaseComponentProvider; import org.openbravo.client.kernel.BaseComponentProvider.ComponentResource.ComponentResourceType; import org.openbravo.client.kernel.Component; import org.openbravo.client.kernel.ComponentProvider; import org.openbravo.retail.posterminal.POSUtils; /** * @author guilleaer */ @ApplicationScoped @ComponentProvider.Qualifier(AVLP_ComponentProvider.QUALIFIER) public class SLP_ComponentProvider extends BaseComponentProvider { public static final String QUALIFIER = "AVLP_Main"; public static final String MODULE_JAVA_PACKAGE = "org.openbravo.pricing.averagelevelpricing"; @Override public Component getComponent(String componentId, Map<String, Object> parameters) { throw new IllegalArgumentException("Component id " + componentId + " not supported."); } @Override public List<ComponentResource> getGlobalComponentResources() { final List<ComponentResource> globalResources = new ArrayList<ComponentResource>(); final String prefix = "web/" + MODULE_JAVA_PACKAGE + "/js/"; String[] resourceList = { "addalgorithm" }; for (String resource : resourceList) { globalResources.add(createComponentResource(ComponentResourceType.Static, prefix + resource + ".js", POSUtils.APP_NAME)); } return globalResources; } }
Create the algorithm
Finally we are going to develop the algorithm in the client side. To do it we will use:
- properties loader
- [hook (LVLPR_addProduct) http://wiki.openbravo.com/wiki/How_to_Add_Hooks]
See comments in the source code to understand what is happening
//Add a properrty to indicate that a module is available OB.MobileApp.model.addPropertiesLoader({ properties: ['AVLP_algorithm'], loadFunction: function (terminalModel) { var algorithms = terminalModel.get('pricingAlgorithms'); console.log('loading...', this.properties); if (!algorithms) { algorithms = {}; } algorithms['AVLP_algorithm'] = true; //Register the algorithm in the hook OB.MobileApp.model.hookManager.registerHook('LVLPR_addProduct', function (args, callbacks) { var linesToModify = []; var affectedLines = args.receipt.getLinesByProduct(args.originalArgs.productToAdd.id); if (args.algorithm === 'AVLP_algorithm' && args.originalArgs.productToAdd.get('groupProduct') && affectedLines && affectedLines.length > 0) { var memo = 0; var totalQty = 0; //Get total qty totalQty = _.reduce(affectedLines, function (memo, line) { return memo + line.get('qty'); }, memo); //Add to the total qty the qty of the new product if (_.isNaN(args.originalArgs.qtyToAdd) || _.isUndefined(args.originalArgs.qtyToAdd) || _.isNull(args.originalArgs.qtyToAdd)) { totalQty += 1; } else { totalQty += args.originalArgs.qtyToAdd; } //HERE GOES THE CODE TO SELECT THE PRICE //If lines which exists in the ticket are modified if (linesToModify.length > 0) { // linesToModify.push({ // lineCid: line.cid, // newQty: totalQty, // newPrice: finalResult.price, // productProperties: [{ // name: 'AVLP_usedRange', // value: finalResult.minQtyToUse // }], // lineProperties: [] // }); args.originalArgs.linesToModify = linesToModify; //Use lines to modify args.originalArgs.useLines = true; } else { //Use the product args.originalArgs.productToAdd.set('standardPrice', 10); args.originalArgs.useLines = false; } } else { //Don't do nothing args.originalArgs.useLines = false; } OB.MobileApp.model.hookManager.callbackExecutor(args.originalArgs, callbacks); }); terminalModel.set('pricingAlgorithms', algorithms); terminalModel.propertiesReady(this.properties); } });