Modules:Advanced Warehouse Operations/ Deviation Developers Documentation
Contents |
Developers Guide
This section describes how the Deviations logic has been implemented and how it should be extended to include new type of Deviations or to modify the logic of the existing ones
How To Create a New Deviation
The Deviations logic is managed by the DeviationManager class. This class is called by the TaskGenerator class when the TaskRequirements have been calculated and it is necessary to calculate the Tasks based on them.
All the Deviations must extend the DeviationsForInternalRoutings interface and implement the mandatory methods
- getPriority(). Returns the Priority of the Deviation implementation. When executing the Deviation implementations, only the ones with higher priority (100 higher than 10) will be executed. However, it is possible to execute several implementations at the same time if they have the same priority
- getOrder(). This method is only used when two deviation implementations have the same priority. It is used to determine the execution order in that specific scenario
- init(). Method to initialize the required class variables
- isValidDeviation(). Returns true if the Deviation is valid for the given TaskRequirement, false otherwise
- run(). Executes the logic of the Deviation implementation
All the Deviations that extend this class must use the DeviationsForInternalRoutings qualifier so that the DeviationManager recognizes that they must be injected to be executed. Also, it is recommended that the life cycle of this classes is defined as Dependant.
@Dependent @Qualifier(DeviationsForInternalRoutings.QUALIFIER)
All the instances that extend DeviationsForInternalRoutings and have the proper qualifier will be injected in DeviationManager. This Deviations will be ordered based on priority first and order second.
A loop will iterate over the Deviations and will execute the ones that are valid and have the higher priority. It is possible to execute more than one Deviation in the same iteration, but only if they have the same priority (in this case they will be ordered by the getOrder() method)
The current Deviation implementations include Deviation To Quality Inspection, which has the higher priority actually, and Deviations To Cross Docking, which have lower priority than the Deviation To Quality Inspection, but all Deviations To Cross Docking have the same priority, allowing the system to execute all of them in the same iteration.
In this case, Deviation To Cross Docking For Sales Order is executed before Deviation To Cross Docking For Distribution Order, which means that the Sales Orders have priority to take the stock over the Distribution Orders.
How To Create a New Cross Docking Deviation
Deviations To Cross Docking are an specific class of Deviations. Since this type of Deviation can be generated by different Document Types, i.e., Sales Orders or Distribution Orders, it is necessary to have an implementation that can be extended by external modules.
The relation between the classes can be better understood by checking the Class Diagram
Deviation Class
In order to create a new Deviation To Cross Docking it is necessary to extend the DeviationToCrossDocking class that holds all the logic, but can be extended to implement methods specific to the related Document Type:
- getActionForCentralBroker(). This method returns the Action that should be used for this Deviation in the Call to the Central Broker and it will be used to search for the Inventory Transaction Type that must be used. An example would be OBAWO_Constants.ACTION_PICKING
- getPropertyInReservation(). This method returns the name of the Property in the Reservation Table that links the Reservation with the current Document. For example Reservation.PROPERTY_SALESORDERLINE
- initializeExtraParamsIdentifier(). This method allows to initialize the value of the extraParamsIdentifier variable, which will be used by the Inventory Transaction Algorithm to perform operations against the related Document Line. For example "C_OrderLine_ID"
- getEntityNameForQueryImplementationHook(). This method returns the Name of the Entity that will be used by the Query Hooks to retrieve the Order Lines that should be Deviated. For example, to retrieve data from Sales Orders this method should return Order.ENTITY_NAME
- getorderLineIdOfReservationFromTaskRequirement(). Since the relationship between Reservations and Documents depend on the specific document methods, this method is necessary to be implemented to return the Id of the Document Line that is related with the Reservation, if any. In case of a Sales Order, it will be the Sales Order Id of the Reservation header
All the Deviations that extend this class must use the DeviationsForInternalRoutings qualifier so that the DeviationManager recognizes that they must be injected to be executed. Also, it is recommended that the life cycle of this classes is defined as Dependant.
@Dependent @Qualifier(DeviationsForInternalRoutings.QUALIFIER)
In general, this classes can be extended either to add support to a new Document Type besides Sales Orders or Distribution Orders, or to change some of the existing logic, like changing the action used to call the Central Broker, in case it is necessary to use a different Inventory Transaction Type.
In case of adding support to a new Document Type, it will be necessary also to add a hook for the DeviationToCrossDockingOrderLinesHook, which is explained below in the Hooks section.
Inventory Transaction Type
There is a new Inventory Transaction Type used for Deviation To Cross Docking. This ITT has also a related implementation DeviationToCrossDocking_ITTAlgorithm.
In case it is necessary to create a new ITT and it's corresponding implementation for a new Deviation To Cross Docking, this existing class can be extended to reuse most of it's internal logic
Since there is some logic that is dependent on the Document Type used, there are hooks that are injected. The implementation of this hooks is explained in the section below.
Deviation To Cross Docking Hooks
In order to allow external modules to modify the current behavior of the Deviation To Cross Docking, or to extend the current functionality to support other Document Types for Deviation To Cross Docking, two types of hooks can be implemented.
Modify Data retrieved
This hook allows to modify the data that is retrieved for the Deviation To Cross Docking. This data are the Order Lines, i.e. Sales Order Lines or Distribution Order Lines, that can be deviated to Cross Docking.
By implementing a new instance of this hook, it is possible to modify the lines that will be used for this Deviation To Cross Docking.
To implement a new instance of this hook it is necessary to extend the DeviationToCrossDockingOrderLinesHook class and implement the mandatory methods:
- getPriority(). Returns the priority of the hook implementation
- isValid(). Returns true if the hook implementation is valid for the given parameters, false otherwise
- retrieveOrderLinesThatCanBeDelivered(). This method returns a ScrollableResults of DeviationToCrossDockingData that contains information about the Order Lines that should be deviated and the quantity to deviate for each of them.
All the instance of this hook must use the OrderLinesHookQualifier so that the ITT recognizes that they must be injected to be executed. Also, it is recommended that the life cycle of this classes is defined as Dependant.
@Dependent @Qualifier(DeviationToCrossDocking.ORDERLINES_HOOK_QUALIFIER)
The ITT will inject all the valid instances of the hooks, however, only one will be executed. That will be the valid one with the higher priority. As a developer, it is important to manage both the isValid method and the priority to achieve the desired results.
Also, the retrieveOrderLinesThatCanBeDelivered method must return a ScrollableResults of DeviationToCrossDockingData objects, an example can be found below.
An example of a code that overrides that overrides the default behavior to retrieve only Sales Order Lines for the Business Partner with Id: A2F636984974499288ABCAB4EC75F7F6 is the following one:
@Dependent @Qualifier(DeviationToCrossDocking.ORDERLINES_HOOK_QUALIFIER) public class DeviationToXDockSalesOrderPickingQueryHookImplementation extends DeviationToCrossDockingForSalesOrderQueryHookImplementation { @Override public int getPriority() { return super.getPriority() + 100; } @Override public boolean isValid(final String entityName, final TaskRequirement taskRequirement, final String invokedFromClassName) { return StringUtils.equals(entityName, Order.ENTITY_NAME) && StringUtils .contains(invokedFromClassName, DeviationToCrossDockingForSalesOrder.class.getName()); } @Override public ScrollableResults retrieveOrderLinesThatCanBeDelivered( final TaskRequirement taskRequirement) { //@formatter:off final String hql = " select new org.openbravo.warehouse.advancedwarehouseoperations.task.DeviationToCrossDockingData(ol.id, obawo_orderline_pendingpicking(ol.id)) " + " from OrderLine ol " + " join ol.salesOrder o " + " where o.salesTransaction = true " + " and o.documentStatus = 'CO' " + " and o.delivered = false " + " and o.warehouse.id = :warehouseId " + " and o.scheduledDeliveryDate > :yesterday " + " and o.scheduledDeliveryDate < :tomorrow " + " and ol.product.id = :productId " + " and ol.deliveredQuantity < ol.orderedQuantity " + " and obawo_orderline_pendingpicking(ol.id) > 0 " + " and o.businessPartner.id = 'A2F636984974499288ABCAB4EC75F7F6' " + " order by o.documentNo "; //@formatter:on return OBDal.getInstance().getSession().createQuery(hql, DeviationToCrossDockingData.class) .setParameter("warehouseId", taskRequirement.getWarehouseId()) .setParameter("yesterday", Utilities.getDateForYesterday()) .setParameter("tomorrow", Utilities.getDateForTomorrow()) .setParameter("productId", taskRequirement.getProductId()).setFetchSize(1000).scroll(); }
Add support for new Document Types
This hook allows to add support to extra Document Types besides Sales Orders and Distribution Orders.
If it is required to add support to extra Document Types, this hook must be implemented to allow to the ITT to manage properly some of the specific functionality of the Document itself.
To implement this hook it is necessary to implement the DeviationToCrossDockingITTAlgorithmDocumentHook class and all the mandatory methods:
- init(). Initializes any class variables if needed
- isValidInstance(). Returns true if the instance of the implementation of this class is valid given the parameters send
- lintTaskTodocumentLine(). Links the Task created with the Document Line that generated the Deviation ToCross-Docking
- getDocumentNumber(). Returns the Document Number that generated the Deviation To Cross-Docking
- getDocumentLine(). Returns the Object related to the Document Line that generated the Deviation to Cross-Docking
- hasReservations(). Returns true if the OrderLine has any Reservation related to it, false otherwise. This is used to improve performance by not looking for Reservations when the Orderline has none related to it.
- getPropertyInReservation(). Returns the Hibernate Property name used in a Reservation header to link to an specific Document. For example Reservation.PROPERTY_SALESORDERLINE
All the instance of this hook must use the CrossDockingDocumentHookQualifier so that the ITT recognizes that they must be injected to be executed. Also, it is recommended that the life cycle of this classes is defined as Dependant.
@Dependent @Qualifier(DeviationToCrossDockingITTAlgorithmDocumentHook.CROSSDOCKING_DOCUMENT_HOOK_QUALIFIER)
Performance
While implementing the development, some performance testing were executed with several scenarios to ensure proper performance of the functionality.
1. Test with 10 Sales Orders with 1 line each. All of the lines are deviated.
- 2,095 ms
- 1,633 ms
- 1,058 ms
2. Test with 100 Sales Orders with 1 line each. All of the lines are deviated.
- 17,019 ms
- 10,591 ms
- 9,931 ms
3. Test with 1000 Sales Orders with 1 line each. All of the lines are deviated.
- 129,999 ms
- 117,500 ms
- 112,573 ms
Most of the time was taken to process the Reservations
4. Test with 1000 Sales Orders with 1 line each and an existing reservation for each line. All of the lines are deviated.
- 309,188 ms
- 330,239 ms
- 337,852 ms
Most of the time was taken in the query to retrieve the Order Lines, in the PL to retrieve the pending quantity to Pick. This scenario was designed to test the limits of the performance, but it should not happen usually in real life cases, as having 1000 lines pending to be picked for the same day, and each one of them with an already existing reservation in the Reception Area should not be a common scenario.
5. Test with 1000 Sales Orders with 1 line each for Product A. 1 Order with one line with Product B. Only the line for Product B should be deviated
- Time take was similar to the first scenario. Having more data in the OrderLine table does not affect the performance, it is only affected by the number of records that need to be deviated.