Author: adrianc
Date: Fri Dec 5 07:35:12 2008 New Revision: 723764 URL: http://svn.apache.org/viewvc?rev=723764&view=rev Log: BalanceInventoryItems performance improvement. Inventory receipts or returns in an installation that has thousands of backorders was running unacceptably slow. This commit fixes that. Modified: ofbiz/trunk/applications/product/entitydef/entitymodel.xml ofbiz/trunk/applications/product/script/org/ofbiz/product/inventory/InventoryReserveServices.xml ofbiz/trunk/applications/product/script/org/ofbiz/product/inventory/InventoryServices.xml Modified: ofbiz/trunk/applications/product/entitydef/entitymodel.xml URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/product/entitydef/entitymodel.xml?rev=723764&r1=723763&r2=723764&view=diff ============================================================================== --- ofbiz/trunk/applications/product/entitydef/entitymodel.xml (original) +++ ofbiz/trunk/applications/product/entitydef/entitymodel.xml Fri Dec 5 07:35:12 2008 @@ -1606,6 +1606,29 @@ <!-- org.ofbiz.product.inventory --> <!-- ========================================================= --> + <view-entity entity-name="BalanceInventoryItemsView" + package-name="org.ofbiz.product.inventory" + title="Balance Inventory Items View Entity"> + <member-entity entity-alias="INV" entity-name="InventoryItem"/> + <member-entity entity-alias="RES" entity-name="OrderItemShipGrpInvRes"/> + <alias entity-alias="INV" name="inventoryItemId"/> + <alias entity-alias="INV" name="productId"/> + <alias entity-alias="INV" name="facilityId"/> + <alias entity-alias="INV" name="inventoryItemTypeId"/> + <alias entity-alias="INV" name="availableToPromiseTotal"/> + <alias entity-alias="INV" name="quantityOnHandTotal"/> + <alias entity-alias="RES" name="orderId"/> + <alias entity-alias="RES" name="shipGroupSeqId"/> + <alias entity-alias="RES" name="orderItemSeqId"/> + <alias entity-alias="RES" name="quantity"/> + <alias entity-alias="RES" name="quantityNotAvailable"/> + <alias entity-alias="RES" name="reserveOrderEnumId"/> + <alias entity-alias="RES" name="reservedDatetime"/> + <alias entity-alias="RES" name="sequenceId"/> + <view-link entity-alias="INV" rel-entity-alias="RES"> + <key-map field-name="inventoryItemId"/> + </view-link> + </view-entity> <entity entity-name="InventoryItem" package-name="org.ofbiz.product.inventory" title="Inventory Item Entity"> Modified: ofbiz/trunk/applications/product/script/org/ofbiz/product/inventory/InventoryReserveServices.xml URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/product/script/org/ofbiz/product/inventory/InventoryReserveServices.xml?rev=723764&r1=723763&r2=723764&view=diff ============================================================================== --- ofbiz/trunk/applications/product/script/org/ofbiz/product/inventory/InventoryReserveServices.xml (original) +++ ofbiz/trunk/applications/product/script/org/ofbiz/product/inventory/InventoryReserveServices.xml Fri Dec 5 07:35:12 2008 @@ -92,7 +92,7 @@ <order-by field-name="${orderByString}"/> </entity-condition> <iterate entry-name="inventoryItemAndLocation" list-name="inventoryItemAndLocations"> - <if-compare field="inventoryItemAndLocation.locationTypeEnumId" operator="equals" value="FLT_PICKLOC"> + <if-compare field="parameters.quantityNotReserved" operator="greater" value="0" type="Double"> <!-- this is a little trick to get the InventoryItem value object without doing a query, possible since all fields on InventoryItem are also on InventoryItemAndLocation with the same names --> <make-value entity-name="InventoryItem" map-name="inventoryItemAndLocation" value-name="inventoryItem"/> <call-simple-method method-name="reserveForInventoryItemInline"/> @@ -112,7 +112,7 @@ <order-by field-name="${orderByString}"/> </entity-condition> <iterate entry-name="inventoryItemAndLocation" list-name="inventoryItemAndLocations"> - <if-compare field="inventoryItemAndLocation.locationTypeEnumId" operator="equals" value="FLT_BULK"> + <if-compare field="parameters.quantityNotReserved" operator="greater" value="0" type="Double"> <!-- this is a little trick to get the InventoryItem value object without doing a query, possible since all fields on InventoryItem are also on InventoryItemAndLocation with the same names --> <make-value entity-name="InventoryItem" map-name="inventoryItemAndLocation" value-name="inventoryItem"/> <call-simple-method method-name="reserveForInventoryItemInline"/> @@ -133,9 +133,17 @@ <order-by field-name="${orderByString}"/> </entity-condition> <iterate entry-name="inventoryItem" list-name="inventoryItems"> - <if-empty field="inventoryItem.locationSeqId"> - <call-simple-method method-name="reserveForInventoryItemInline"/> - </if-empty> + <if> + <condition> + <and> + <if-compare field="parameters.quantityNotReserved" operator="greater" value="0" type="Double"/> + <if-empty field="inventoryItem.locationSeqId"/> + </and> + </condition> + <then> + <call-simple-method method-name="reserveForInventoryItemInline"/> + </then> + </if> </iterate> </if-compare> @@ -370,25 +378,6 @@ <simple-method method-name="reserveForInventoryItemInline" short-description="Does a reservation for one InventoryItem, meant to be called in-line"> <!-- only do something with this inventoryItem if there is more inventory to reserve --> <if-compare field="parameters.quantityNotReserved" operator="greater" value="0" type="Double"> - <!-- get the promiseDatetime --> - <get-related-one value-name="inventoryItem" relation-name="ProductFacility" to-value-name="productFacility"/> - <set field="daysToShip" from-field="productFacility.daysToShip"/> - <if-empty field="daysToShip"> - <!-- if the product does not have its own days to ship, use Facility.defaultDaysToShip, if not then use 30 days as a USA industry default --> - <if-not-empty field="facility.defaultDaysToShip"> - <set field="daysToShip" from-field="facility.defaultDaysToShip" type="Long"/> - <else> - <set field="daysToShip" value="30" type="Long"/> - </else> - </if-not-empty> - </if-empty> - <call-bsh><![CDATA[ - java.sql.Timestamp orderDate = orderHeader.getTimestamp("orderDate"); - java.util.Calendar cal = java.util.Calendar.getInstance(); - cal.setTimeInMillis(orderDate.getTime()); - cal.add(java.util.Calendar.DAY_OF_YEAR, daysToShip.intValue()); - return org.ofbiz.base.util.UtilMisc.toMap("promisedDatetime", new java.sql.Timestamp(cal.getTimeInMillis())); - ]]></call-bsh> <if-compare value="SERIALIZED_INV_ITEM" operator="equals" field="inventoryItem.inventoryItemTypeId"> <if-compare value="INV_AVAILABLE" operator="equals" field="inventoryItem.statusId"> @@ -397,6 +386,7 @@ <store-value value-name="inventoryItem"/> <!-- store OrderItemShipGrpInvRes record --> + <call-simple-method method-name="getPromisedDateTime"/> <set from-field="parameters.orderId" field="reserveOisgirMap.orderId"/> <set from-field="parameters.orderItemSeqId" field="reserveOisgirMap.orderItemSeqId"/> <set from-field="parameters.shipGroupSeqId" field="reserveOisgirMap.shipGroupSeqId"/> @@ -445,6 +435,7 @@ <clear-field field-name="createDetailMap"/> <!-- create OrderItemShipGrpInvRes record --> + <call-simple-method method-name="getPromisedDateTime"/> <set from-field="parameters.orderId" field="reserveOisgirMap.orderId"/> <set from-field="parameters.orderItemSeqId" field="reserveOisgirMap.orderItemSeqId"/> <set from-field="parameters.shipGroupSeqId" field="reserveOisgirMap.shipGroupSeqId"/> @@ -472,6 +463,26 @@ </if-compare> </if-compare> </simple-method> + + <simple-method method-name="getPromisedDateTime" short-description="Get Inventory Promised Date/Time"> + <!-- get the promiseDatetime --> + <get-related-one value-name="inventoryItem" relation-name="ProductFacility" to-value-name="productFacility"/> + <set field="daysToShip" from-field="productFacility.daysToShip"/> + <if-empty field="daysToShip"> + <!-- if the product does not have its own days to ship, use Facility.defaultDaysToShip, if not then use 30 days as a USA industry default --> + <set field="daysToShip" from-field="facility.defaultDaysToShip" type="Long"/> + </if-empty> + <if-empty field="daysToShip"> + <set field="daysToShip" value="30" type="Long"/> + </if-empty> + <call-bsh><![CDATA[ + java.sql.Timestamp orderDate = orderHeader.getTimestamp("orderDate"); + java.util.Calendar cal = java.util.Calendar.getInstance(); + cal.setTimeInMillis(orderDate.getTime()); + cal.add(java.util.Calendar.DAY_OF_YEAR, daysToShip.intValue()); + return org.ofbiz.base.util.UtilMisc.toMap("promisedDatetime", new java.sql.Timestamp(cal.getTimeInMillis())); + ]]></call-bsh> + </simple-method> <simple-method method-name="reserveOrderItemInventory" short-description="Reserve Order Item Inventory"> <entity-one entity-name="OrderItemShipGrpInvRes" value-name="checkOisgirEntity"/> Modified: ofbiz/trunk/applications/product/script/org/ofbiz/product/inventory/InventoryServices.xml URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/product/script/org/ofbiz/product/inventory/InventoryServices.xml?rev=723764&r1=723763&r2=723764&view=diff ============================================================================== --- ofbiz/trunk/applications/product/script/org/ofbiz/product/inventory/InventoryServices.xml (original) +++ ofbiz/trunk/applications/product/script/org/ofbiz/product/inventory/InventoryServices.xml Fri Dec 5 07:35:12 2008 @@ -709,26 +709,28 @@ <entity-one entity-name="InventoryItem" value-name="inventoryItem"/> <!-- find all items which have a negative ATP --> - <entity-condition entity-name="InventoryItem" list-name="inventoryItems"> - <condition-list combine="and"> - <condition-expr field-name="productId" operator="equals" env-name="inventoryItem.productId"/> - <condition-expr field-name="facilityId" operator="equals" env-name="inventoryItem.facilityId"/> - <condition-expr field-name="inventoryItemTypeId" operator="equals" value="NON_SERIAL_INV_ITEM"/> - <condition-list combine="or"> - <condition-expr field-name="availableToPromiseTotal" operator="equals" env-name="nullField"/> - <condition-expr field-name="availableToPromiseTotal" operator="equals" value=""/> - <condition-expr field-name="availableToPromiseTotal" operator="less" value="0"/> + <entity-condition entity-name="BalanceInventoryItemsView" list-name="inventoryItems"> + <condition-list combine="or"> + <condition-list combine="and"> + <condition-expr field-name="productId" operator="equals" env-name="inventoryItem.productId"/> + <condition-expr field-name="facilityId" operator="equals" env-name="inventoryItem.facilityId"/> + <condition-expr field-name="inventoryItemTypeId" operator="equals" value="NON_SERIAL_INV_ITEM"/> + <condition-list combine="or"> + <condition-expr field-name="availableToPromiseTotal" operator="equals" env-name="nullField"/> + <condition-expr field-name="availableToPromiseTotal" operator="equals" value=""/> + <condition-expr field-name="availableToPromiseTotal" operator="less" value="0"/> + </condition-list> </condition-list> - <!-- Exclude the current item from the selection, because it will be added to the list anyway --> - <condition-expr field-name="inventoryItemId" operator="not-equals" env-name="inventoryItem.inventoryItemId"/> + <!-- the current item is added to the list, even if its atp is greater than zero, because there could be + negative reservations (backorders) on it, if the atp has been increased by an inventory variance --> + <condition-expr field-name="inventoryItemId" operator="equals" env-name="inventoryItem.inventoryItemId"/> </condition-list> - <!-- TODO: order the list of inventory items in a useful way, since operations occur below based on the first item --> + <order-by field-name="reservedDatetime"/> + <order-by field-name="sequenceId"/> </entity-condition> - <!-- the current item is added to the list, even if its atp is greater than zero, because there could be - negative reservations (backorders) on it, if the atp has been increased by an inventory variance --> - <field-to-list field-name="inventoryItem" list-name="inventoryItems"/> <!-- find their current reservations --> + <set field="reserveQtyAccum" value="0" type="Double"/> <iterate list-name="inventoryItems" entry-name="item"> <!-- If quantityOnHandTotal is not equal to availableToPromiseTotal this means that there are pending reservations on the item that cause availableToPromiseTotal @@ -737,51 +739,48 @@ for example, if we have a negative quantityOnHandTotal and quantityOnHandTotal equal to availableToPromiseTotal, then no reservations are present. --> - <if-compare-field field="item.quantityOnHandTotal" to-field="item.availableToPromiseTotal" operator="not-equals"> - <get-related value-name="item" relation-name="OrderItemShipGrpInvRes" list-name="relatedRes"/> - <!--<list-to-list list-name="relatedRes" to-list-name="reservations"/>--> - - <iterate list-name="relatedRes" entry-name="oneRelatedRes"> - <entity-condition entity-name="PicklistAndBinAndItem" list-name="picklistItemList"> - <condition-list combine="and"> - <condition-expr field-name="orderId" env-name="oneRelatedRes.orderId"/> - <condition-expr field-name="shipGroupSeqId" env-name="oneRelatedRes.shipGroupSeqId"/> - <condition-expr field-name="orderItemSeqId" env-name="oneRelatedRes.orderItemSeqId"/> - <condition-expr field-name="inventoryItemId" env-name="oneRelatedRes.inventoryItemId"/> - <condition-expr field-name="statusId" operator="not-equals" value="PICKLIST_CANCELLED"/> - <condition-expr field-name="statusId" operator="not-equals" value="PICKLIST_PICKED"/> - </condition-list> - </entity-condition> - - <!-- only cancel/re-reserve when there are no picklists associated; this will prevent - orders appearing on duplicate pick lists --> - - <if-empty field="picklistItemList"> - <log level="info" message="Order [${oneRelatedRes.orderId}] was not found on any picklist for InventoryItem [${oneRelatedRes.inventoryItemId}]"/> - <if> - <condition> - <and> - <if-compare-field field="parameters.priorityOrderId" to-field="oneRelatedRes.orderId" operator="equals"/> - <if-compare-field field="parameters.priorityOrderItemSeqId" to-field="oneRelatedRes.orderItemSeqId" operator="equals"/> - </and> - </condition> - <then> - <field-to-list field-name="oneRelatedRes" list-name="privilegedReservations"/> - </then> - <else> - <field-to-list field-name="oneRelatedRes" list-name="reservations"/> - </else> - </if> - </if-empty> - </iterate> - </if-compare-field> + <if> + <condition> + <and> + <if-compare-field field="reserveQtyAccum" operator="less" to-field="inventoryItem.quantityOnHandTotal" type="Double"/> + <if-compare-field field="item.quantityOnHandTotal" operator="not-equals" to-field="item.availableToPromiseTotal"/> + </and> + </condition> + <then> + <entity-condition entity-name="PicklistAndBinAndItem" list-name="picklistItemList"> + <condition-list combine="and"> + <condition-expr field-name="orderId" env-name="item.orderId"/> + <condition-expr field-name="shipGroupSeqId" env-name="item.shipGroupSeqId"/> + <condition-expr field-name="orderItemSeqId" env-name="item.orderItemSeqId"/> + <condition-expr field-name="inventoryItemId" env-name="item.inventoryItemId"/> + <condition-expr field-name="statusId" operator="not-equals" value="PICKLIST_CANCELLED"/> + <condition-expr field-name="statusId" operator="not-equals" value="PICKLIST_PICKED"/> + </condition-list> + </entity-condition> + <!-- only cancel/re-reserve when there are no picklists associated; this will prevent + orders appearing on duplicate pick lists --> + <if-empty field="picklistItemList"> + <log level="info" message="Order [${item.orderId}] was not found on any picklist for InventoryItem [${item.inventoryItemId}]"/> + <if> + <condition> + <and> + <if-compare-field field="parameters.priorityOrderId" operator="equals" to-field="item.orderId"/> + <if-compare-field field="parameters.priorityOrderItemSeqId" operator="equals" to-field="item.orderItemSeqId"/> + </and> + </condition> + <then> + <field-to-list field-name="item" list-name="privilegedReservations"/> + </then> + <else> + <field-to-list field-name="item" list-name="reservations"/> + </else> + </if> + <set field="reserveQtyAccum" value="${bsh:reserveQtyAccum + item.getDouble("quantity");}" type="Double"/> + </if-empty> + </then> + </if> </iterate> - <!-- sort the list by date --> - <set field="orderByList[]" value="reservedDatetime"/> - <set field="orderByList[]" value="sequenceId"/> - <order-value-list list-name="reservations" order-by-list-name="orderByList"/> - <list-to-list list-name="privilegedReservations" to-list-name="allReservations"/> <list-to-list list-name="reservations" to-list-name="allReservations"/> @@ -794,11 +793,7 @@ <!-- FIRST, cancel all the reservations --> <iterate list-name="allReservations" entry-name="oisgir"> - <clear-field field-name="cancelOisgirMap"/> - <set field="cancelOisgirMap.orderId" from-field="oisgir.orderId"/> - <set field="cancelOisgirMap.orderItemSeqId" from-field="oisgir.orderItemSeqId"/> - <set field="cancelOisgirMap.inventoryItemId" from-field="oisgir.inventoryItemId"/> - <set field="cancelOisgirMap.shipGroupSeqId" from-field="oisgir.shipGroupSeqId"/> + <set-service-fields service-name="cancelOrderItemShipGrpInvRes" to-map-name="cancelOisgirMap" map-name="oisgir"/> <call-service service-name="cancelOrderItemShipGrpInvRes" in-map-name="cancelOisgirMap"/> </iterate> @@ -811,23 +806,14 @@ <log level="verbose" message="Adding ${oisgir.orderId} to touchedOrderIdMap"/> </if-compare> </if-not-empty> - - <!-- require inventory is N because it had to be N to begin with to have a negative ATP --> - <clear-field field-name="resMap"/> + <set-service-fields service-name="reserveProductInventory" to-map-name="resMap" map-name="oisgir"/> <set field="resMap.productId" from-field="inventoryItem.productId"/> - <set field="resMap.orderId" from-field="oisgir.orderId"/> - <set field="resMap.orderItemSeqId" from-field="oisgir.orderItemSeqId"/> - <set field="resMap.quantity" from-field="oisgir.quantity"/> - <set field="resMap.reservedDatetime" from-field="oisgir.reservedDatetime"/> - <set field="resMap.reserveOrderEnumId" from-field="oisgir.reserveOrderEnumId"/> + <!-- require inventory is N because it had to be N to begin with to have a negative ATP --> <set field="resMap.requireInventory" value="N"/> - <set field="resMap.shipGroupSeqId" from-field="oisgir.shipGroupSeqId"/> - <set field="resMap.sequenceId" from-field="oisgir.sequenceId"/> <log level="info" message="Re-reserving product [${resMap.productId}] for order item [${resMap.orderId}:${resMap.orderItemSeqId}] quantity [${resMap.quantity}]; facility [${inventoryItem.facilityId}]"/> <if-empty field="inventoryItem.facilityId"> <log level="warning" message="In balanceInventoryItems there is no facilityId, so reserving from any facility for order item [${resMap.orderId}:${resMap.orderItemSeqId}]"></log> <call-service service-name="reserveProductInventory" in-map-name="resMap"/> - <else> <set field="resMap.facilityId" from-field="inventoryItem.facilityId"/> <call-service service-name="reserveProductInventoryByFacility" in-map-name="resMap"/> |
Free forum by Nabble | Edit this page |