| <?xml version="1.0" encoding="UTF-8"?> |
| <!-- |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, |
| software distributed under the License is distributed on an |
| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| KIND, either express or implied. See the License for the |
| specific language governing permissions and limitations |
| under the License. |
| --> |
| |
| <simple-methods xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| xmlns="http://ofbiz.apache.org/Simple-Method" xsi:schemaLocation="http://ofbiz.apache.org/Simple-Method http://ofbiz.apache.org/dtds/simple-methods.xsd"> |
| |
| <!-- a method to centralize facility security code, meant to be called in-line with |
| call-simple-method, and the checkAction and callingMethodName attributes should be in the method context --> |
| <simple-method method-name="checkFacilityRelatedPermission" short-description="Check Facility Related Permission"> |
| <if-empty field="callingMethodName"> |
| <property-to-field resource="CommonUiLabels" property="CommonPermissionThisOperation" field="callingMethodName"/> |
| </if-empty> |
| <if-empty field="checkAction"> |
| <set value="UPDATE" field="checkAction"/> |
| </if-empty> |
| |
| <if> |
| <condition> |
| <not> |
| <or> |
| <if-has-permission permission="CATALOG" action="_${checkAction}"/> |
| <if-has-permission permission="CATALOG_ADMIN"/> |
| <if-has-permission permission="FACILITY" action="_${checkAction}"/> |
| <if-has-permission permission="FACILITY_ADMIN"/> |
| <and> |
| <not><if-empty field="alternatePermissionRoot"/></not> |
| <if-has-permission permission="${alternatePermissionRoot}" action="_${checkAction}"/> |
| </and> |
| </or> |
| </not> |
| </condition> |
| <then> |
| <add-error> |
| <fail-property resource="ProductUiLabels" property="ProductCatalogCreatePermissionError"/> |
| </add-error> |
| </then> |
| </if> |
| </simple-method> |
| <simple-method method-name="facilityGenericPermission" short-description="Main permission logic"> |
| <set field="mainAction" from-field="parameters.mainAction"/> |
| <if-empty field="mainAction"> |
| <add-error> |
| <fail-property resource="ProductUiLabels" property="ProductMissingMainActionInPermissionService"/> |
| </add-error> |
| <check-errors/> |
| </if-empty> |
| |
| <set field="callingMethodName" from-field="parameters.resourceDescription"/> |
| <set field="checkAction" from-field="parameters.mainAction"/> |
| <call-simple-method method-name="checkFacilityRelatedPermission"/> |
| |
| <if-empty field="error_list"> |
| <set field="hasPermission" type="Boolean" value="true"/> |
| <field-to-result field="hasPermission"/> |
| |
| <else> |
| <property-to-field resource="ProductUiLabels" property="ProductFacilityPermissionError" field="failMessage"/> |
| <set field="hasPermission" type="Boolean" value="false"/> |
| <field-to-result field="hasPermission"/> |
| <field-to-result field="failMessage"/> |
| </else> |
| </if-empty> |
| </simple-method> |
| <simple-method method-name="checkProductFacilityRelatedPermission" short-description="ProductFacility Permission Checking Logic"> |
| <if-empty field="mainAction"> |
| <set field="mainAction" from-field="parameters.mainAction"/> |
| <if-empty field="mainAction"> |
| <add-error> |
| <fail-property resource="CommonUiLabels" property="CommonPermissionMainActionAttributeMissing"/> |
| </add-error> |
| </if-empty> |
| </if-empty> |
| <check-errors/> |
| <set field="resourceDescription" from-field="parameters.resourceDescription"/> |
| <if-empty field="resourceDescription"> |
| <property-to-field resource="CommonUiLabels" property="CommonPermissionThisOperation" field="resourceDescription"/> |
| </if-empty> |
| <set field="callingMethodName" from-field="resourceDescription"/> |
| <set field="checkAction" from-field="mainAction"/> |
| <set field="alternatePermissionRoot" value="FACILITY"/> |
| <call-simple-method method-name="checkProductRelatedPermission" xml-resource="component://product/minilang/product/product/ProductServices.xml"/> |
| <if-empty field="error_list"> |
| <set field="hasPermission" type="Boolean" value="true"/> |
| <field-to-result field="hasPermission"/> |
| |
| <else> |
| <property-to-field resource="ProductUiLabels" property="ProductFacilityPermissionError" field="failMessage"/> |
| <set field="hasPermission" type="Boolean" value="false"/> |
| <field-to-result field="hasPermission"/> |
| <field-to-result field="failMessage"/> |
| </else> |
| </if-empty> |
| </simple-method> |
| |
| <!-- InventoryItem methods --> |
| <simple-method method-name="createInventoryItem" short-description="Create an InventoryItem"> |
| |
| <!-- Create a lot before --> |
| <entity-one value-field="product" entity-name="Product"> |
| <field-map field-name="productId" from-field="parameters.productId"/> |
| </entity-one> |
| |
| <!-- Check if this product can or not have a lotId --> |
| <if> |
| <condition> |
| <and> |
| <if-compare operator="equals" value="Mandatory" field="product.lotIdFilledIn" /> |
| <if-empty field="parameters.lotId" /> |
| </and> |
| </condition> |
| <then> |
| <add-error> |
| <fail-property resource="ProductErrorUiLabels" property="ProductLotIdMandatory"/> |
| </add-error> |
| </then> |
| </if> |
| |
| <if> |
| <condition> |
| <and> |
| <if-compare operator="equals" value="Forbidden" field="product.lotIdFilledIn" /> |
| <not> |
| <if-empty field="parameters.lotId" /> |
| </not> |
| </and> |
| </condition> |
| <then> |
| <add-error> |
| <fail-property resource="ProductErrorUiLabels" property="ProductLotIdForbidden"/> |
| </add-error> |
| </then> |
| </if> |
| |
| <check-errors /> |
| |
| <!-- If this InventoryItem is returned by a manufacturing task, don't create a lot --> |
| <if-compare operator="equals" value="N" field="parameters.isReturned"> |
| <if-not-empty field="parameters.lotId"> |
| <!-- Check if the lot already exists --> |
| <entity-and entity-name="Lot" list="lotList"> |
| <field-map field-name="lotId" from-field="parameters.lotId" /> |
| </entity-and> |
| <if-empty field="lotList"> |
| <make-value entity-name="Lot" value-field="lot"/> |
| <set field="lot.lotId" from-field="parameters.lotId"/> |
| <create-value value-field="lot"/> |
| </if-empty> |
| </if-not-empty> |
| </if-compare> |
| |
| <make-value entity-name="InventoryItem" value-field="inventoryItem"/> |
| <!-- TODO: make sure availableToPromiseTotal and quantityOnHandTotal are not changed --> |
| <set-nonpk-fields map="parameters" value-field="inventoryItem"/> |
| |
| <call-simple-method method-name="inventoryItemCheckSetDefaultValues"/> |
| <check-errors/> |
| |
| <sequenced-id sequence-name="InventoryItem" field="inventoryItem.inventoryItemId"/> |
| <create-value value-field="inventoryItem"/> |
| <field-to-result field="inventoryItem.inventoryItemId" result-name="inventoryItemId"/> |
| </simple-method> |
| <simple-method method-name="createInventoryItemCheckSetAtpQoh" short-description="createInventoryItemCheckSetAtpQoh" login-required="false"> |
| <if> |
| <condition> |
| <or> |
| <not><if-empty field="parameters.availableToPromiseTotal"/></not> |
| <not><if-empty field="parameters.quantityOnHandTotal"/></not> |
| </or> |
| </condition> |
| <then> |
| <log level="info" message="Got an InventoryItem with ATP/QOH Total with ID ${parameters.inventoryItemId}, creating InventoryItemDetail"/> |
| <set from-field="parameters.inventoryItemId" field="createDetailMap.inventoryItemId"/> |
| <set from-field="parameters.availableToPromiseTotal" field="createDetailMap.availableToPromiseDiff"/> |
| <set from-field="parameters.quantityOnHandTotal" field="createDetailMap.quantityOnHandDiff"/> |
| <call-service service-name="createInventoryItemDetail" in-map-name="createDetailMap"/> |
| </then> |
| </if> |
| </simple-method> |
| <simple-method method-name="inventoryItemCheckSetDefaultValues" short-description="Check and, if empty, fills with default values ownerPartyId, currencyUomId, unitCost" login-required="false"> |
| <if-empty field="inventoryItem"> |
| <entity-one entity-name="InventoryItem" value-field="inventoryItem"/> |
| <set field="updateInventoryItem" value="Y"/> |
| </if-empty> |
| <!-- if all the inventoryItem's fields are already filled, return with success --> |
| <if> |
| <condition> |
| <and> |
| <not><if-empty field="inventoryItem.facilityId"/></not> |
| <not><if-empty field="inventoryItem.ownerPartyId"/></not> |
| <not><if-empty field="inventoryItem.currencyUomId"/></not> |
| <not><if-empty field="inventoryItem.unitCost"/></not> |
| </and> |
| </condition> |
| <then> |
| <return/> |
| </then> |
| </if> |
| <if-empty field="inventoryItem.facilityId"> |
| <add-error> |
| <fail-property resource="ProductUiLabels" property="FacilityInventoryItemsMissingFacilityId"/> |
| </add-error> |
| <check-errors/> |
| </if-empty> |
| <!-- if inventoryItem's ownerPartyId is empty, get the ownerPartyId from the facility --> |
| <if-empty field="inventoryItem.ownerPartyId"> |
| <get-related-one value-field="inventoryItem" relation-name="Facility" to-value-field="facility"/> |
| <set field="inventoryItem.ownerPartyId" from-field="facility.ownerPartyId"/> |
| <!-- if inventoryItem's ownerPartyId is still empty, return an error message --> |
| <if-empty field="inventoryItem.ownerPartyId"> |
| <add-error> |
| <fail-property resource="ProductUiLabels" property="FacilityInventoryItemsMissingOwnerPartyId"/> |
| </add-error> |
| <check-errors/> |
| </if-empty> |
| </if-empty> |
| <!-- if inventoryItem's currencyUomId is empty, get the currencyUomId |
| from the party accounting preferences of the owner of the inventory item --> |
| <if-empty field="inventoryItem.currencyUomId"> |
| <set field="partyAccountingPreferencesCallMap.organizationPartyId" from-field="inventoryItem.ownerPartyId"/> |
| <call-service service-name="getPartyAccountingPreferences" in-map-name="partyAccountingPreferencesCallMap"> |
| <result-to-field result-name="partyAccountingPreference" field="accPref"/> |
| </call-service> |
| <set field="inventoryItem.currencyUomId" from-field="accPref.baseCurrencyUomId"/> |
| <if-empty field="inventoryItem.currencyUomId"> |
| <property-to-field resource="general" property="currency.uom.id.default" field="inventoryItem.currencyUomId"/> |
| </if-empty> |
| <!-- if inventoryItem's currencyUomId is still empty, return an error message --> |
| <if-empty field="inventoryItem.currencyUomId"> |
| <add-error> |
| <fail-property resource="ProductUiLabels" property="FacilityInventoryItemsMissingCurrencyId"/> |
| </add-error> |
| <check-errors/> |
| </if-empty> |
| </if-empty> |
| <!-- if inventoryItem's unitCost is empty, get the product's standard |
| cost by calling the getProductCost service --> |
| <if-empty field="inventoryItem.unitCost"> |
| <set from-field="inventoryItem.productId" field="inputMap.productId"/> |
| <set from-field="inventoryItem.currencyUomId" field="inputMap.currencyUomId"/> |
| <set value="EST_STD" field="inputMap.costComponentTypePrefix"/> <!-- TODO: create a new service getProductStdCost that calls getProductCost --> |
| <call-service service-name="getProductCost" in-map-name="inputMap"> |
| <result-to-field result-name="productCost" field="inventoryItem.unitCost"/> |
| </call-service> |
| </if-empty> |
| <!-- if inventoryItem's unitCost is still empty, or negative return an error message --> |
| <!-- TODO/WARNING: getProductCost returns 0 even if no std costs are found --> |
| <if-empty field="inventoryItem.unitCost"> |
| <add-error> |
| <fail-property resource="ProductUiLabels" property="FacilityInventoryItemsMissingUnitCost"/> |
| </add-error> |
| </if-empty> |
| <check-errors/> |
| <!-- if you don't want inventory item with unitCost = 0, change the operator |
| attribute from "less" to "less-equals". |
| --> |
| <if-compare field="inventoryItem.unitCost" operator="less" value="0" type="BigDecimal"> |
| <add-error> |
| <fail-property resource="ProductUiLabels" property="FacilityInventoryItemsNegativeUnitCost"/> |
| </add-error> |
| </if-compare> |
| <check-errors/> |
| <if-not-empty field="updateInventoryItem"> |
| <store-value value-field="inventoryItem"/> |
| </if-not-empty> |
| </simple-method> |
| |
| <simple-method method-name="updateInventoryItem" short-description="Update an InventoryItem"> |
| <make-value entity-name="InventoryItem" value-field="lookupPKMap"/> |
| <set-pk-fields map="parameters" value-field="lookupPKMap"/> |
| <find-by-primary-key map="lookupPKMap" value-field="lookedUpValue"/> |
| <if-empty field="lookedUpValue.ownerPartyId"> |
| <get-related-one value-field="lookedUpValue" relation-name="Facility" to-value-field="oldFacility"/> |
| <set field="lookedUpValue.ownerPartyId" from-field="oldFacility.ownerPartyId"/> |
| </if-empty> |
| <field-to-result field="lookedUpValue.ownerPartyId" result-name="oldOwnerPartyId"/> |
| <field-to-result field="lookedUpValue.statusId" result-name="oldStatusId"/> |
| <field-to-result field="lookedUpValue.productId" result-name="oldProductId"/> |
| <!-- special handling for the unitCost --> |
| <if-not-empty field="parameters.unitCost"> |
| <if-compare field="parameters.unitCost" operator="less" value="0.0" type="BigDecimal"> |
| <add-error> |
| <fail-property resource="ProductUiLabels" property="FacilityInventoryItemsUnitCostCannotBeNegative"/> |
| </add-error> |
| <check-errors/> |
| </if-compare> |
| </if-not-empty> |
| <set field="oldUnitCost" from-field="lookedUpValue.unitCost"/> |
| <if-not-empty field="parameters.lotId"> |
| <!-- Check if the lot already exists --> |
| <entity-and entity-name="Lot" list="lotList"> |
| <field-map field-name="lotId" from-field="parameters.lotId" /> |
| </entity-and> |
| <if-empty field="lotList"> |
| <make-value entity-name="Lot" value-field="lot"/> |
| <set field="lot.lotId" from-field="parameters.lotId"/> |
| <create-value value-field="lot"/> |
| </if-empty> |
| </if-not-empty> |
| <set-nonpk-fields map="parameters" value-field="lookedUpValue"/> |
| <store-value value-field="lookedUpValue"/> |
| <!-- if the unit cost is changed create an InventoryItemDetail to keep track of unit cost history --> |
| <if-not-empty field="parameters.unitCost"> |
| <if-compare-field field="parameters.unitCost" to-field="oldUnitCost" operator="not-equals"> |
| <set field="createInventoryItemDetailInMap.inventoryItemId" from-field="lookedUpValue.inventoryItemId"/> |
| <set field="createInventoryItemDetailInMap.unitCost" from-field="parameters.unitCost"/> |
| <call-service service-name="createInventoryItemDetail" in-map-name="createInventoryItemDetailInMap"/> |
| </if-compare-field> |
| </if-not-empty> |
| </simple-method> |
| |
| <simple-method method-name="createInventoryItemStatus" short-description="Create an inventory item status record"> |
| <now-timestamp field="nowTimestamp"/> |
| |
| <!-- find the most recent InventoryItemStatus record and set the statusEndDatetime --> |
| <entity-and entity-name="InventoryItemStatus" list="oldInventoryItemStatusList"> |
| <field-map field-name="inventoryItemId" from-field="parameters.inventoryItemId"/> |
| <order-by field-name="-statusDatetime"/> |
| </entity-and> |
| <first-from-list list="oldInventoryItemStatusList" entry="oldInventoryItemStatus"/> |
| <if-not-empty field="oldInventoryItemStatus"> |
| <set field="oldInventoryItemStatus.statusEndDatetime" from-field="nowTimestamp"/> |
| <store-value value-field="oldInventoryItemStatus"/> |
| </if-not-empty> |
| |
| <make-value entity-name="InventoryItemStatus" value-field="inventoryItemStatus"/> |
| <set-nonpk-fields map="parameters" value-field="inventoryItemStatus"/> |
| <set-pk-fields map="parameters" value-field="inventoryItemStatus"/> |
| <set field="inventoryItemStatus.statusDatetime" from-field="nowTimestamp"/> |
| <set field="inventoryItemStatus.changeByUserLoginId" from-field="userLogin.userLoginId"/> |
| |
| <!-- make sure the current productId is set, if not passed in look up the current value --> |
| <if-empty field="inventoryItemStatus.productId"> |
| <entity-one entity-name="InventoryItem" value-field="inventoryItem"/> |
| <set field="inventoryItemStatus.productId" from-field="inventoryItem.productId"/> |
| </if-empty> |
| |
| <create-value value-field="inventoryItemStatus"/> |
| </simple-method> |
| |
| <simple-method method-name="createInventoryItemDetail" short-description="Create an InventoryItemDetail"> |
| <make-value entity-name="InventoryItemDetail" value-field="newEntity"/> |
| |
| <set from-field="parameters.inventoryItemId" field="newEntity.inventoryItemId"/> |
| <!-- NOTE DEJ20070927: not using make-next-seq-id because a single InventoryItem may see traffic from lots of threads at the same time, and make-next-seq-id doesn't do well with that <make-next-seq-id seq-field-name="inventoryItemDetailSeqId" value-field="newEntity" increment-by="1" numeric-padding="4"/> --> |
| <sequenced-id sequence-name="InventoryItemDetail" field="newEntity.inventoryItemDetailSeqId"/> |
| <field-to-result field="newEntity.inventoryItemDetailSeqId" result-name="inventoryItemDetailSeqId"/> |
| |
| <set-nonpk-fields map="parameters" value-field="newEntity"/> |
| |
| <!-- set the effectiveDate; if from an ItemIssuance lookup the issuedDateTime --> |
| <if-not-empty field="parameters.itemIssuanceId"> |
| <entity-one entity-name="ItemIssuance" value-field="itemIssuance"/> |
| <set field="newEntity.effectiveDate" from-field="itemIssuance.issuedDateTime"/> |
| <else> |
| <now-timestamp field="newEntity.effectiveDate"/> |
| </else> |
| </if-not-empty> |
| |
| <!-- if availableToPromiseDiff or quantityOnHandDiff are empty set to 0 --> |
| <if-empty field="newEntity.availableToPromiseDiff"><set field="newEntity.availableToPromiseDiff" value="0" type="BigDecimal"/></if-empty> |
| <if-empty field="newEntity.quantityOnHandDiff"><set field="newEntity.quantityOnHandDiff" value="0" type="BigDecimal"/></if-empty> |
| <if-empty field="newEntity.accountingQuantityDiff"><set field="newEntity.accountingQuantityDiff" value="0" type="BigDecimal"/></if-empty> |
| |
| <create-value value-field="newEntity"/> |
| </simple-method> |
| <simple-method method-name="updateInventoryItemFromDetail" short-description="Update an InventoryItem From the Associated Detail Records" login-required="false"> |
| <entity-one entity-name="InventoryItem" value-field="inventoryItem"/> |
| <entity-one entity-name="InventoryItemDetailSummary" value-field="inventoryItemDetailSummary"/> |
| |
| <set field="inventoryItem.availableToPromiseTotal" from-field="inventoryItemDetailSummary.availableToPromiseTotal"/> |
| <set field="inventoryItem.quantityOnHandTotal" from-field="inventoryItemDetailSummary.quantityOnHandTotal"/> |
| <set field="inventoryItem.accountingQuantityTotal" from-field="inventoryItemDetailSummary.accountingQuantityTotal"/> |
| <store-value value-field="inventoryItem"/> |
| </simple-method> |
| |
| <simple-method method-name="updateSerializedInventoryTotals" short-description="Update the totals on serialized inventory"> |
| <entity-one entity-name="InventoryItem" value-field="inventoryItem"/> |
| <if-compare field="inventoryItem.inventoryItemTypeId" value="SERIALIZED_INV_ITEM" operator="equals"> |
| <if> |
| <!-- available --> |
| <condition> |
| <and> |
| <if-compare field="inventoryItem.statusId" value="INV_AVAILABLE" operator="equals"/> |
| <or> |
| <if-compare field="inventoryItem.availableToPromiseTotal" operator="not-equals" value="1" type="BigDecimal"/> |
| <if-compare field="inventoryItem.quantityOnHandTotal" operator="not-equals" value="1" type="BigDecimal"/> |
| </or> |
| </and> |
| </condition> |
| <then> |
| <set field="inventoryItem.availableToPromiseTotal" value="1" type="BigDecimal"/> |
| <set field="inventoryItem.quantityOnHandTotal" value="1" type="BigDecimal"/> |
| <log level="always" message="In updateSerializedInventoryTotals Storing totals for item [${inventoryItem.inventoryItemId}] INV_AVAIABLE [1/1]"/> |
| <store-value value-field="inventoryItem"/> |
| </then> |
| |
| <!-- delivered --> |
| <else-if> |
| <condition> |
| <and> |
| <if-compare field="inventoryItem.statusId" value="INV_DELIVERED" operator="equals"/> |
| <or> |
| <if-compare field="inventoryItem.availableToPromiseTotal" operator="not-equals" value="0" type="BigDecimal"/> |
| <if-compare field="inventoryItem.quantityOnHandTotal" operator="not-equals" value="0" type="BigDecimal"/> |
| </or> |
| </and> |
| </condition> |
| <then> |
| <set field="inventoryItem.availableToPromiseTotal" value="0" type="BigDecimal"/> |
| <set field="inventoryItem.quantityOnHandTotal" value="0" type="BigDecimal"/> |
| <log level="always" message="In updateSerializedInventoryTotals Storing totals [${inventoryItem.inventoryItemId}] for INV_DELIVERED [0/0]"/> |
| <store-value value-field="inventoryItem"/> |
| </then> |
| </else-if> |
| |
| <!-- any promised; or on-hand but not available status --> |
| <else-if> |
| <condition> |
| <and> |
| <if-compare field="inventoryItem.statusId" operator="not-equals" value="INV_AVAILABLE"/> |
| <if-compare field="inventoryItem.statusId" operator="not-equals" value="INV_DELIVERED"/> |
| <or> |
| <if-compare field="inventoryItem.availableToPromiseTotal" operator="not-equals" value="0" type="BigDecimal"/> |
| <if-compare field="inventoryItem.quantityOnHandTotal" operator="not-equals" value="1" type="BigDecimal"/> |
| </or> |
| </and> |
| </condition> |
| <then> |
| <set field="inventoryItem.availableToPromiseTotal" value="0" type="BigDecimal"/> |
| <set field="inventoryItem.quantityOnHandTotal" value="1" type="BigDecimal"/> |
| <log level="always" message="In updateSerializedInventoryTotals Storing totals [${inventoryItem.inventoryItemId}] for other status [0/1]"/> |
| <store-value value-field="inventoryItem"/> |
| </then> |
| </else-if> |
| </if> |
| </if-compare> |
| </simple-method> |
| |
| <simple-method method-name="updateOldInventoryToDetailAll" short-description="Update Old Inventory To Detail All"> |
| <!-- find all InventoryItem records where oldQuantityOnHand or oldAvailableToPromise are not null --> |
| <entity-condition entity-name="InventoryItem" list="inventoryItemList"> |
| <condition-list combine="or"> |
| <condition-expr field-name="oldQuantityOnHand" operator="not-equals" value=""/> |
| <condition-expr field-name="oldAvailableToPromise" operator="not-equals" value=""/> |
| </condition-list> |
| </entity-condition> |
| <iterate list="inventoryItemList" entry="inventoryItem"> |
| <set from-field="inventoryItem" field="callServiceMap.inventoryItem"/> |
| <call-service service-name="updateOldInventoryToDetailSingle" in-map-name="callServiceMap"/> |
| <clear-field field="callServiceMap.inventoryItem"/> |
| </iterate> |
| </simple-method> |
| <simple-method method-name="updateOldInventoryToDetailSingle" short-description="Update Old Inventory To Detail Single"> |
| <!-- for each create an InventoryItemDetail representing the old QOH or ATP value, then null those fields --> |
| <set from-field="parameters.inventoryItem.inventoryItemId" field="createDetailMap.inventoryItemId"/> |
| <set from-field="parameters.inventoryItem.oldAvailableToPromise" field="createDetailMap.availableToPromiseDiff"/> |
| <set from-field="parameters.inventoryItem.oldQuantityOnHand" field="createDetailMap.quantityOnHandDiff"/> |
| <call-service service-name="createInventoryItemDetail" in-map-name="createDetailMap"/> |
| |
| <clear-field field="parameters.inventoryItem.oldAvailableToPromise"/> |
| <clear-field field="parameters.inventoryItem.oldQuantityOnHand"/> |
| <store-value value-field="parameters.inventoryItem"/> |
| </simple-method> |
| |
| <simple-method method-name="checkProductInventoryDiscontinuation" short-description="Check Product Inventory Discontinuation" login-required="false"> |
| <set from-field="parameters.productId" field="productIdMap.productId"/> |
| <find-by-primary-key entity-name="Product" map="productIdMap" value-field="product"/> |
| <now-timestamp field="nowTimestamp"/> |
| |
| <!-- if discontinueProductSales field is empty and the product is a variant, get the fieldcontent from the virtual product --> |
| <if-not-empty field="product"> |
| <if-compare field="product.isVariant" value="Y" operator="equals"> |
| <!-- retrieve related virtual product because also to be used later --> |
| <set field="getAssoc.productIdTo" from-field="product.productId"/> |
| <set field="getAssoc.productAssocTypeId" value="PRODUCT_VARIANT"/> |
| <find-by-and entity-name="ProductAssoc" map="getAssoc" list="assocs"/> |
| <if-not-empty field="assocs"> |
| <filter-list-by-date list="assocs" to-list="assocsDate"/> |
| <first-from-list list="assocsDate" entry="assoc"/> |
| <if-not-empty field="assoc"> |
| <get-related-one value-field="assoc" relation-name="MainProduct" to-value-field="virtProduct"/> |
| <if-empty field="product.salesDiscWhenNotAvail"> |
| <set field="product.salesDiscWhenNotAvail" from-field="virtProduct.salesDiscWhenNotAvail"/> |
| </if-empty> |
| </if-not-empty> |
| </if-not-empty> |
| </if-compare> |
| </if-not-empty> |
| |
| <!-- before checking inventory availability see if the product is already discontinued, and discontinued in the past (if in the future, still check availability and discontinue now if necessary) --> |
| <if> |
| <condition> |
| <and> |
| <not><if-empty field="product"/></not> |
| <if-compare field="product.salesDiscWhenNotAvail" operator="equals" value="Y"/> |
| <or> |
| <if-empty field="product.salesDiscontinuationDate"/> |
| <if-compare-field field="product.salesDiscontinuationDate" to-field="nowTimestamp" operator="greater" type="Timestamp"/> |
| </or> |
| </and> |
| </condition> |
| <then> |
| <!-- now for the real fun, get the inventory available if is less-equal to zero discontinue product --> |
| <call-service service-name="getProductInventoryAvailable" in-map-name="productIdMap"> |
| <result-to-field result-name="availableToPromiseTotal"/> |
| </call-service> |
| <if-compare field="availableToPromiseTotal" operator="less-equals" value="0" type="BigDecimal"> |
| <set from-field="parameters.productId" field="discontinueProductSalesMap.productId"/> |
| <call-service service-name="discontinueProductSales" in-map-name="discontinueProductSalesMap"/> |
| </if-compare> |
| |
| <!-- check if related virtual product has no variant left, if yes discontinue the virtual product too when salesDiscWhenNotAvail is 'Y'--> |
| <if-not-empty field="virtProduct"> |
| <if-compare field="virtProduct.salesDiscWhenNotAvail" operator="equals" value="Y"> |
| <set field="getFromAssoc.productId" from-field="virtProduct.productId"/> |
| <set field="getFromAssoc.productAssocTypeId" value="PRODUCT_VARIANT"/> |
| <find-by-and entity-name="ProductAssoc" map="getFromAssoc" list="assocs"/> |
| <filter-list-by-date list="assocs" to-list="assocsDate"/> |
| <if-empty field="assocsDate"> |
| <set from-field="virtProduct.productId" field="discontinueProductSalesMap.productId"/> |
| <call-service service-name="discontinueProductSales" in-map-name="discontinueProductSalesMap"/> |
| </if-empty> |
| </if-compare> |
| </if-not-empty> |
| |
| </then> |
| </if> |
| </simple-method> |
| |
| |
| <simple-method method-name="createInventoryItemVariance" short-description="Create an InventoryItemVariance"> |
| |
| <!-- add changes to availableToPromise and quantityOnHand --> |
| <make-value entity-name="InventoryItem" value-field="inventoryItemLookup"/> |
| <set-pk-fields map="parameters" value-field="inventoryItemLookup"/> |
| <find-by-primary-key map="inventoryItemLookup" value-field="inventoryItem"/> |
| |
| <if-compare field="inventoryItem.inventoryItemTypeId" operator="not-equals" value="NON_SERIAL_INV_ITEM"> |
| <string-to-list string="Can only create an InventoryItemVariance for a Non-Serialized Inventory Item" list="error_list"/> |
| </if-compare> |
| <check-errors/> |
| |
| <!-- instead of updating InventoryItem, add an InventoryItemDetail --> |
| <set from-field="parameters.inventoryItemId" field="createDetailMap.inventoryItemId"/> |
| <set from-field="parameters.physicalInventoryId" field="createDetailMap.physicalInventoryId"/> |
| <set from-field="parameters.availableToPromiseVar" field="createDetailMap.availableToPromiseDiff"/> |
| <set from-field="parameters.quantityOnHandVar" field="createDetailMap.quantityOnHandDiff"/> |
| <set from-field="parameters.varianceReasonId" field="createDetailMap.reasonEnumId"/> |
| <set from-field="parameters.comments" field="createDetailMap.description"/> |
| <call-service service-name="createInventoryItemDetail" in-map-name="createDetailMap"/> |
| |
| <make-value entity-name="InventoryItemVariance" value-field="newEntity"/> |
| <set-pk-fields map="parameters" value-field="newEntity"/> |
| <set-nonpk-fields map="parameters" value-field="newEntity"/> |
| <create-value value-field="newEntity"/> |
| |
| <!-- TODO: (possibly a big deal?) check to see if any reserved inventory needs to be changed because of a change in availableToPromise --> |
| <!-- TODO: make sure availableToPromise is never greater than the quantityOnHand? --> |
| </simple-method> |
| |
| <simple-method method-name="createPhysicalInventoryAndVariance" short-description="Create a PhysicalInventory and an InventoryItemVariance"> |
| <set-service-fields service-name="createPhysicalInventory" map="parameters" to-map="createPhysicalInventoryMap"/> |
| <call-service service-name="createPhysicalInventory" in-map-name="createPhysicalInventoryMap"> |
| <result-to-field result-name="physicalInventoryId" field="parameters.physicalInventoryId"/> |
| <result-to-result result-name="physicalInventoryId" service-result-name="physicalInventoryId"/> |
| </call-service> |
| <set-service-fields service-name="createInventoryItemVariance" map="parameters" to-map="createInventoryItemVarianceMap"/> |
| <call-service service-name="createInventoryItemVariance" in-map-name="createInventoryItemVarianceMap"/> |
| </simple-method> |
| |
| <!-- ================================================================ --> |
| <!-- Check/Reserve Inventory Services --> |
| <!-- ================================================================ --> |
| |
| <simple-method method-name="getProductInventoryAvailable" short-description="Get Inventory Available for a Product" login-required="false" use-transaction="true"> |
| <!-- |
| this method can be called with some optional parameters: |
| -facilityId |
| -partyId |
| -locationSeqId |
| -containerId |
| If the service definitions are used then only some of these will ever be specified, or none of them. |
| |
| Whatever it is called with, it will basically get a list of InventoryItems and total the available amount. |
| --> |
| |
| <!-- <log level="info" message="Getting inventory available to promise count; parameters are: ${parameters}"/> --> |
| |
| <!-- FIXME: this is an hack to get all the items with a null location: |
| if the parameters.locationSeqId string is equal to "nullField" then |
| set the lookupFieldMap.locationSeqId to null |
| --> |
| <if-compare field="parameters.locationSeqId" operator="equals" value="nullField"> |
| <set from-field="nullField" field="lookupFieldMap.locationSeqId"/> |
| </if-compare> |
| |
| <set from-field="parameters.inventoryItemId" field="lookupFieldMap.inventoryItemId"/> |
| <set from-field="parameters.productId" field="lookupFieldMap.productId"/> |
| <set from-field="parameters.facilityId" field="lookupFieldMap.facilityId"/> |
| <set from-field="parameters.partyId" field="lookupFieldMap.partyId"/> |
| <set from-field="parameters.locationSeqId" field="lookupFieldMap.locationSeqId"/> |
| <set from-field="parameters.containerId" field="lookupFieldMap.containerId"/> |
| <set from-field="parameters.lotId" field="lookupFieldMap.lotId"/> |
| <!-- we might get away with a cache here since real serious errors will occur during the reservation service... but only if we need the speed --> |
| <if-compare field="parameters.useCache" operator="equals" value="true" type="Boolean"> |
| <!-- if caching was requested, don't use an iterator --> |
| <find-by-and entity-name="InventoryItem" map="lookupFieldMap" list="inventoryItems" use-cache="true"/> |
| <else> |
| <find-by-and entity-name="InventoryItem" map="lookupFieldMap" list="inventoryItems" use-iterator="true" use-cache="false"/> |
| </else> |
| </if-compare> |
| |
| <set field="parameters.availableToPromiseTotal" value="0" type="BigDecimal"/> |
| <set field="parameters.quantityOnHandTotal" value="0" type="BigDecimal"/> |
| <iterate list="inventoryItems" entry="inventoryItem"> |
| <!-- NOTE: this code no longer distinguishes between serialized and non-serialized because both now have availableToPromiseTotal and quantityOnHandTotal populated (for serialized are based on status, non-serialized are based on InventoryItemDetail) --> |
| <if> |
| <condition> |
| <or> |
| <and> |
| <not><if-empty field="parameters.statusId"/></not> |
| <if-compare-field field="parameters.statusId" operator="equals" to-field="inventoryItem.statusId"/> |
| </and> |
| <and> |
| <if-empty field="parameters.statusId"/> |
| <or> |
| <if-empty field="inventoryItem.statusId"/> |
| <if-compare field="inventoryItem.statusId" operator="equals" value="INV_AVAILABLE"/> |
| <if-compare field="inventoryItem.statusId" operator="equals" value="INV_NS_RETURNED"/> |
| <if-compare field="inventoryItem.inventoryItemTypeId" operator="equals" value="SERIALIZED_INV_ITEM"/><!-- status is reflected in total fields --> |
| </or> |
| </and> |
| </or> |
| </condition> |
| <then> |
| <set field="parameters.quantityOnHandTotal" value="${parameters.quantityOnHandTotal + inventoryItem.quantityOnHandTotal}" type="BigDecimal"/> |
| <set field="parameters.availableToPromiseTotal" value="${parameters.availableToPromiseTotal + inventoryItem.availableToPromiseTotal}" type="BigDecimal"/> |
| </then> |
| </if> |
| </iterate> |
| |
| <field-to-result field="parameters.availableToPromiseTotal" result-name="availableToPromiseTotal"/> |
| <field-to-result field="parameters.quantityOnHandTotal" result-name="quantityOnHandTotal"/> |
| </simple-method> |
| |
| <simple-method method-name="countProductInventoryOnHand" short-description="Count Inventory On Hand for a Product constrained by a facilityId at a given date." use-transaction="false"> |
| <entity-condition entity-name="InventoryItemDetailForSum" list="inventoryItemDetailTotals"> |
| <condition-list combine="and"> |
| <condition-expr field-name="effectiveDate" operator="less-equals" from-field="parameters.inventoryCountDate"/> |
| <condition-expr field-name="facilityId" operator="equals" from-field="parameters.facilityId"/> |
| <condition-expr field-name="productId" operator="equals" from-field="parameters.productId"/> |
| </condition-list> |
| <select-field field-name="quantityOnHandSum"/> |
| </entity-condition> |
| <first-from-list list="inventoryItemDetailTotals" entry="inventoryItemDetailTotal"/> |
| <set field="quantityOnHandTotal" from-field="inventoryItemDetailTotal.quantityOnHandSum" type="BigDecimal" default-value="0"/> |
| <field-to-result field="quantityOnHandTotal" result-name="quantityOnHandTotal"/> |
| </simple-method> |
| |
| <simple-method method-name="countProductInventoryShippedForSales" short-description="Count Inventory Shipped for Sales Orders for a Product constrained by a facilityId in a given date range." use-transaction="false"> |
| <if-empty field="parameters.thruDate"> |
| <now-timestamp field="parameters.thruDate"/> |
| </if-empty> |
| <entity-condition entity-name="InventoryItemDetailForSum" list="inventoryItemDetailTotals"> |
| <condition-list combine="and"> |
| <condition-expr field-name="effectiveDate" operator="greater-equals" from-field="parameters.fromDate"/> |
| <condition-expr field-name="effectiveDate" operator="less" from-field="parameters.thruDate"/> |
| <condition-expr field-name="facilityId" operator="equals" from-field="parameters.facilityId"/> |
| <condition-expr field-name="productId" operator="equals" from-field="parameters.productId"/> |
| <condition-expr field-name="orderId" operator="not-equals" from-field="nullField"/> |
| <condition-expr field-name="quantityOnHandDiff" operator="less" value="0"/> |
| </condition-list> |
| <select-field field-name="quantityOnHandSum"/> |
| </entity-condition> |
| <first-from-list list="inventoryItemDetailTotals" entry="inventoryItemDetailTotal"/> |
| <set field="quantityOnHandTotal" from-field="${inventoryItemDetailTotal.quantityOnHandSum * -1}" type="BigDecimal" default-value="0"/> |
| <field-to-result field="quantityOnHandTotal" result-name="quantityOnHandTotal"/> |
| </simple-method> |
| |
| <simple-method method-name="getMktgPackagesAvailable" short-description="Get Marketing Packages Available From Components In Inventory" login-required="false" use-transaction="false"> |
| <set field="availableToPromiseTotal" value="0" type="BigDecimal"/> |
| <set field="quantityOnHandTotal" value="0" type="BigDecimal"/> |
| <set from-field="parameters.productId" field="lookupMktgPkgParams.productId"/> |
| <entity-one entity-name="Product" value-field="product"/> |
| <set field="isMarketingPkgAuto" value="${groovy: org.apache.ofbiz.entity.util.EntityTypeUtil.hasParentType(delegator, 'ProductType', 'productTypeId', product.productTypeId, 'parentTypeId', 'MARKETING_PKG_AUTO')}" type="Boolean"/> |
| <if-compare field="isMarketingPkgAuto" operator="equals" value="true" type="Boolean"> |
| <set field="productIdMap.productId" from-field="product.productId"/> |
| <call-service service-name="getProductInventoryAvailable" in-map-name="productIdMap"> |
| <result-to-field result-name="availableToPromiseTotal"/> |
| <result-to-field result-name="quantityOnHandTotal"/> |
| </call-service> |
| <else> |
| <set value="PRODUCT_COMPONENT" field="lookupMktgPkgParams.type"/> |
| <call-service service-name="getAssociatedProducts" in-map-name="lookupMktgPkgParams"> |
| <result-to-field result-name="assocProducts"/> |
| </call-service> |
| </else> |
| </if-compare> |
| |
| <!-- if there are any components, then the ATP and QOH are based on the quantities of those component |
| products and found with another service --> |
| <if-not-empty field="assocProducts"> |
| <set from-field="assocProducts" field="inventoryByAssocProductsParams.assocProducts"/> |
| <set from-field="parameters.facilityId" field="inventoryByAssocProductsParams.facilityId"/> |
| <set from-field="parameters.statusId" field="inventoryByAssocProductsParams.statusId"/> |
| <call-service service-name="getProductInventoryAvailableFromAssocProducts" in-map-name="inventoryByAssocProductsParams"> |
| <result-to-field result-name="quantityOnHandTotal"/> |
| <result-to-field result-name="availableToPromiseTotal"/> |
| </call-service> |
| </if-not-empty> |
| |
| <field-to-result field="availableToPromiseTotal"/> |
| <field-to-result field="quantityOnHandTotal"/> |
| </simple-method> |
| |
| <!-- |
| Code in balanceInventoryItems service was doing same job which reassignInventoryReservations service is doing. Purpose of both the services are same. In fact reassignInventoryReservations service does better job of |
| reserving items for an order. 1) It takes into account the order priority, currentPromisedDate, reservedDateTime and sequenceId. where as balanceInventoryItems was prioritizing orders |
| based on reservedDatetime and sequenceId. 2) reassignInventoryReservations excludes items with sufficient inventory, where as balanceInventoryItems also pulls up order items which have sufficient inventory. |
| |
| Calling reassignInventoryReservations from balanceInventoryItems. balanceInventoryItems can be deleted, but not deleting it because its used in many places in OFBiz. |
| To DO: We can delete balanceInventoryItems in future and replace it with reassignInventoryReservations every where. |
| --> |
| |
| <simple-method method-name="balanceInventoryItems" short-description="Balances available-to-promise on inventory items"> |
| <entity-one entity-name="InventoryItem" value-field="inventoryItem"/> |
| <set field="reassignInventoryReservationsCtx.productId" from-field="inventoryItem.productId"/> |
| <set field="reassignInventoryReservationsCtx.facilityId" from-field="inventoryItem.facilityId"/> |
| <set field="reassignInventoryReservationsCtx.fromDate" from-field="nowTimestamp"/> |
| <call-service service-name="reassignInventoryReservations" in-map-name="reassignInventoryReservationsCtx"/> |
| </simple-method> |
| |
| <simple-method method-name="reassignInventoryReservations" short-description="Balances available-to-promise on inventory items"> |
| <entity-condition entity-name="OrderItemShipGrpInvResAndItem" list="relatedRes"> |
| <condition-list combine="and"> |
| <condition-expr field-name="productId" operator="equals" from-field="parameters.productId"/> |
| <condition-expr field-name="facilityId" operator="equals" from-field="parameters.facilityId"/> |
| <condition-expr field-name="inventoryItemTypeId" operator="equals" value="NON_SERIAL_INV_ITEM"/> |
| <condition-list combine="or"> |
| <condition-expr field-name="currentPromisedDate" operator="greater" from-field="parameters.fromDate" ignore-if-null="true"/> |
| <condition-list combine="or"> |
| <condition-expr field-name="quantityNotAvailable" operator="greater" value="0"/> |
| <condition-expr field-name="availableToPromiseTotal" operator="equals" from-field="nullField"/> |
| <condition-expr field-name="availableToPromiseTotal" operator="equals" value=""/> |
| <condition-expr field-name="availableToPromiseTotal" operator="less" value="0"/> |
| </condition-list> |
| </condition-list> |
| </condition-list> |
| <order-by field-name="priority"/> |
| <order-by field-name="currentPromisedDate"/> |
| <order-by field-name="reservedDatetime"/> |
| <order-by field-name="sequenceId"/> |
| </entity-condition> |
| |
| <iterate list="relatedRes" entry="oneRelatedRes"> |
| <entity-condition entity-name="PicklistAndBinAndItem" list="picklistItemList"> |
| <condition-list combine="and"> |
| <condition-expr field-name="orderId" from-field="oneRelatedRes.orderId"/> |
| <condition-expr field-name="shipGroupSeqId" from-field="oneRelatedRes.shipGroupSeqId"/> |
| <condition-expr field-name="orderItemSeqId" from-field="oneRelatedRes.orderItemSeqId"/> |
| <condition-expr field-name="inventoryItemId" from-field="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="oneRelatedRes" list="privilegedReservations"/> |
| </then> |
| <else> |
| <field-to-list field="oneRelatedRes" list="reservations"/> |
| </else> |
| </if> |
| </if-empty> |
| </iterate> |
| |
| <list-to-list list="privilegedReservations" to-list="allReservations"/> |
| <list-to-list list="reservations" to-list="allReservations"/> |
| |
| <!-- FIRST, cancel all the reservations --> |
| <iterate list="allReservations" entry="oisgir"> |
| <clear-field field="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"/> |
| <call-service service-name="cancelOrderItemShipGrpInvRes" in-map-name="cancelOisgirMap"/> |
| </iterate> |
| |
| <!-- THEN, re-reserve the cancelled items --> |
| <iterate list="allReservations" entry="oisgir"> |
| <!-- maintain a Set (in a Map) of orderIds that we have reallocated for, but only if they had some quantityNotReserved --> |
| <if-not-empty field="oisgir.quantityNotAvailable"> |
| <if-compare field="oisgir.quantityNotAvailable" operator="greater" value="0" type="BigDecimal"> |
| <set field="touchedOrderIdMap[oisgir.orderId]" value="Y"/> |
| <log level="verbose" message="Adding ${oisgir.orderId} to touchedOrderIdMap"/> |
| </if-compare> |
| </if-not-empty> |
| <entity-one entity-name="OrderHeader" value-field="orderHeader"> |
| <field-map field-name="orderId" from-field="oisgir.orderId"/> |
| </entity-one> |
| |
| <!-- require inventory is N because it had to be N to begin with to have a negative ATP --> |
| <clear-field field="resMap"/> |
| <set field="resMap.productId" from-field="parameters.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"/> |
| <set field="resMap.requireInventory" value="N"/> |
| <set field="resMap.shipGroupSeqId" from-field="oisgir.shipGroupSeqId"/> |
| <set field="resMap.sequenceId" from-field="oisgir.sequenceId"/> |
| <set field="resMap.facilityId" from-field="parameters.facilityId"/> |
| <set field="resMap.priority" from-field="orderHeader.priority"/> |
| <log level="info" message="Re-reserving product [${resMap.productId}] for order item [${resMap.orderId}:${resMap.orderItemSeqId}] quantity [${resMap.quantity}]; facility [${parameters.facilityId}]"/> |
| <call-service service-name="reserveProductInventoryByFacility" in-map-name="resMap"/> |
| </iterate> |
| |
| <!-- now go through touchedOrderIdMap keys and make a Set/Map of orderIds that are no longer on back-order --> |
| <iterate-map key="touchedOrderId" value="throwAwayValue" map="touchedOrderIdMap"> |
| <set field="checkOrderIsOnBackOrderMap.orderId" from-field="touchedOrderId"/> |
| <call-service service-name="checkOrderIsOnBackOrder" in-map-name="checkOrderIsOnBackOrderMap"> |
| <result-to-field result-name="isBackOrder"/> |
| </call-service> |
| |
| <if-compare field="isBackOrder" operator="equals" value="false" type="Boolean"> |
| <set field="noLongerOnBackOrderIdMap[touchedOrderId]" value="Y"/> |
| </if-compare> |
| </iterate-map> |
| <if-not-empty field="noLongerOnBackOrderIdMap"> |
| <call-object-method obj-field="noLongerOnBackOrderIdMap" method-name="keySet" ret-field="noLongerOnBackOrderIdSet"/> |
| <field-to-result field="noLongerOnBackOrderIdSet"/> |
| </if-not-empty> |
| </simple-method> |
| |
| <simple-method method-name="balanceOrderItemsWithNegativeReservations" short-description="To balance order items with negative reservations"> |
| <entity-one entity-name="OrderHeader" value-field="orderHeader" auto-field-map="true"/> |
| <get-related-one value-field="orderHeader" relation-name="ProductStore" to-value-field="productStore"/> |
| <if-compare field="productStore.balanceResOnOrderCreation" operator="equals" value="Y"> |
| <entity-condition entity-name="OrderItemAndShipGrpInvResAndItem" list="oisgirais"> |
| <condition-list combine="and"> |
| <condition-expr field-name="orderId" operator="equals" from-field="parameters.orderId"/> |
| <condition-expr field-name="quantityNotAvailable" operator="greater" value="0"/> |
| <condition-expr field-name="quantityNotAvailable" operator="not-equals" value=""/> |
| <condition-expr field-name="quantityNotAvailable" operator="not-equals" from-field="nullField"/> |
| </condition-list> |
| </entity-condition> |
| <iterate list="oisgirais" entry="oisgir"> |
| <set field="orderItems[oisgir.orderItemSeqId]" from-field="oisgir"/> |
| </iterate> |
| <now-timestamp field="nowTimestamp"/> |
| <iterate-map key="orderItemSeqId" value="oisgir" map="orderItems"> |
| <set field="reassignInventoryReservationsCtx.productId" from-field="oisgir.productId"/> |
| <set field="reassignInventoryReservationsCtx.facilityId" from-field="oisgir.facilityId"/> |
| <if-not-empty field="oisgir.shipBeforeDate"> |
| <set field="reassignInventoryReservationsCtx.fromDate" from-field="oisgir.shipBeforeDate"/> |
| <else> |
| <set field="reassignInventoryReservationsCtx.fromDate" from-field="nowTimestamp"/> |
| </else> |
| </if-not-empty> |
| <call-service service-name="reassignInventoryReservations" in-map-name="reassignInventoryReservationsCtx"/> |
| </iterate-map> |
| <else> |
| <log level="info" message="Not reassigning the reservations because productStore.balanceResOnOrderCreation is set to N or null."/> |
| </else> |
| </if-compare> |
| </simple-method> |
| |
| <!-- Inventory Transfer Services --> |
| <simple-method method-name="createInventoryTransfer" short-description="Create an Inventory Transfer"> |
| |
| <make-value entity-name="InventoryTransfer" value-field="newEntity"/> |
| <set-nonpk-fields map="parameters" value-field="newEntity"/> |
| <sequenced-id sequence-name="InventoryTransfer" field="newEntity.inventoryTransferId"/> |
| <field-to-result field="newEntity.inventoryTransferId" result-name="inventoryTransferId"/> |
| |
| <create-value value-field="newEntity"/> |
| </simple-method> |
| <simple-method method-name="updateInventoryTransfer" short-description="Update an Inventory Transfer"> |
| |
| <set from-field="parameters.inventoryTransferId" field="lookupPKMap.inventoryTransferId"/> |
| <find-by-primary-key entity-name="InventoryTransfer" map="lookupPKMap" value-field="inventoryTransfer"/> |
| |
| <if-not-empty field="parameters.statusId"> |
| <if-compare-field field="parameters.statusId" to-field="inventoryTransfer.statusId" operator="not-equals"> |
| <!-- make sure a StatusValidChange record exists, if not return error --> |
| <entity-one entity-name="StatusValidChange" value-field="checkStatusValidChange" auto-field-map="false"> |
| <field-map field-name="statusId" from-field="inventoryTransfer.statusId"/> |
| <field-map field-name="statusIdTo" from-field="parameters.statusId"/> |
| </entity-one> |
| <if-empty field="checkStatusValidChange"> |
| <set value="ERROR: Changing the status from ${inventoryTransfer.statusId} to ${parameters.statusId} is not allowed." field="error_list[]"/> |
| </if-empty> |
| <check-errors/> |
| </if-compare-field> |
| </if-not-empty> |
| |
| <set-nonpk-fields map="parameters" value-field="inventoryTransfer"/> |
| <store-value value-field="inventoryTransfer"/> |
| </simple-method> |
| |
| <simple-method method-name="createInventoryTransfersForProduct" short-description="Create inventory transfers for the given product and quantity. Return the units not available for transfers."> |
| <now-timestamp field="nowTimestamp"/> |
| |
| <!-- check the product; make sure its a physical item --> |
| <entity-one entity-name="Product" value-field="product"/> |
| <entity-one entity-name="Facility" value-field="facility" use-cache="true"/> |
| <get-related-one value-field="product" relation-name="ProductType" to-value-field="productType"/> |
| <if-compare field="productType.isPhysical" operator="equals" value="N"> |
| <set field="quantityNotTransferred" value="0" type="BigDecimal"/> |
| <else> |
| <!-- before we do the find, put together the orderBy list based on which reserveOrderEnumId is specified --> |
| <!-- FIFO=first in first out, so it should be order by ASCending receive or expire date |
| LIFO=last in first out, so it means order by DESCending receive or expire date |
| --> |
| <if-compare value="INVRO_GUNIT_COST" operator="equals" field="parameters.reserveOrderEnumId"> |
| <set value="unitCost DESC" field="orderByString"/> |
| <else> |
| <if-compare value="INVRO_LUNIT_COST" operator="equals" field="parameters.reserveOrderEnumId"> |
| <set value="+unitCost" field="orderByString"/> |
| <else> |
| <if-compare value="INVRO_FIFO_EXP" operator="equals" field="parameters.reserveOrderEnumId"> |
| <set value="+expireDate" field="orderByString"/> |
| <else> |
| <if-compare value="INVRO_LIFO_EXP" operator="equals" field="parameters.reserveOrderEnumId"> |
| <set value="-expireDate" field="orderByString"/> |
| <else> |
| <if-compare value="INVRO_LIFO_REC" operator="equals" field="parameters.reserveOrderEnumId"> |
| <set value="-datetimeReceived" field="orderByString"/> |
| <else> |
| <!-- the default reserveOrderEnumId is INVRO_FIFO_REC, ie FIFO based on date received --> |
| <set value="+datetimeReceived" field="orderByString"/> |
| <set value="INVRO_FIFO_REC" field="parameters.reserveOrderEnumId"/> |
| </else> |
| </if-compare> |
| </else> |
| </if-compare> |
| </else> |
| </if-compare> |
| </else> |
| </if-compare> |
| </else> |
| </if-compare> |
| |
| <set from-field="parameters.quantity" field="quantityNotTransferred"/> |
| |
| <set field="locationTypeEnumIds" value="${groovy: ['FLT_PICKLOC', 'FLT_BULK', null]}"/> |
| <iterate list="locationTypeEnumIds" entry="locationTypeEnumId"> |
| <find-by-and entity-name="InventoryItemAndLocation" map="lookupFieldMap" list="inventoryItemAndLocations" use-iterator="true" order-by-list="orderByList"/> |
| <entity-condition entity-name="InventoryItemAndLocation" list="inventoryItemAndLocations"> |
| <condition-list> |
| <condition-expr field-name="locationTypeEnumId" value="${locationTypeEnumId}" ignore-if-empty="true" ignore-if-null="true"/> |
| <condition-expr field-name="productId" value="${parameters.productId}"/> |
| <condition-expr field-name="containerId" value="${parameters.containerId}" ignore-if-empty="true" ignore-if-null="true"/> |
| <condition-expr field-name="facilityId" value="${parameters.facilityId}"/> |
| <condition-expr field-name="availableToPromiseTotal" operator="greater" value="0"/> |
| </condition-list> |
| <order-by field-name="${orderByString}"/> |
| </entity-condition> |
| <!-- first transfer InventoryItems in FLT_PICKLOC type locations, then FLT_BULK locations, then InventoryItems with no locations --> |
| <iterate list="inventoryItemAndLocations" entry="inventoryItemAndLocation"> |
| <clear-field field="inputMap"/> |
| <set field="inputMap.inventoryItemId" from-field="inventoryItemAndLocation.inventoryItemId"/> |
| <if-empty field="parameters.statusId"> |
| <set field="inputMap.statusId" value="IXF_REQUESTED"/> |
| <else> |
| <set field="inputMap.statusId" value="${parameters.statusId}"/> |
| </else> |
| </if-empty> |
| <set field="inputMap.facilityId" from-field="parameters.facilityId"/> |
| <set field="inputMap.facilityIdTo" from-field="parameters.facilityIdTo"/> |
| <set field="inputMap.sendDate" from-field="parameters.sendDate"/> |
| <!-- TODO: inventory transfers for serialized items are not yet implemented --> |
| <if-compare field="inventoryItemAndLocation.inventoryItemTypeId" operator="equals" value="NON_SERIAL_INV_ITEM"> |
| <if-compare-field field="quantityNotTransferred" to-field="inventoryItemAndLocation.availableToPromiseTotal" operator="greater" type="BigDecimal"> |
| <set field="inputMap.xferQty" from-field="inventoryItemAndLocation.availableToPromiseTotal"/> |
| <else> |
| <set field="inputMap.xferQty" from-field="quantityNotTransferred"/> |
| </else> |
| </if-compare-field> |
| <add-error> |
| <fail-message message="inputMap = ${inputMap}"/> |
| </add-error> |
| <call-service service-name="createInventoryTransfer" in-map-name="inputMap"/> |
| <add-error> |
| <fail-message message="quantityNotTransferred = ${quantityNotTransferred}"/> |
| </add-error> |
| <calculate field="quantityNotTransferred"> |
| <calcop operator="subtract" field="quantityNotTransferred"> |
| <calcop operator="get" field="inputMap.xferQty"/> |
| </calcop> |
| </calculate> |
| </if-compare> |
| <if-compare operator="equals" value="0" field="quantityNotTransferred"> |
| <break/> |
| </if-compare> |
| </iterate> |
| </iterate> |
| </else> |
| </if-compare> |
| |
| <field-to-result field="quantityNotTransferred"/> |
| <if-compare operator="greater" value="0" field="quantityNotTransferred"> |
| <add-error> |
| <fail-property resource="ProductUiLabels" property="FormFieldTitle_quantityNotAvailable"/> |
| </add-error> |
| <add-error> |
| <fail-message message="${quantityNotTransferred}"/> |
| </add-error> |
| <check-errors/> |
| </if-compare> |
| </simple-method> |
| |
| <simple-method method-name="changeOwnerUponIssuance" short-description="If product store setOwnerUponIssuance is Y or empty, set the inventory item owner upon issuance."> |
| <entity-one entity-name="ItemIssuance" value-field="itemIssuance"/> |
| <get-related-one value-field="itemIssuance" relation-name="InventoryItem" to-value-field="inventoryItem"/> |
| <if-not-empty field="inventoryItem"> |
| <if-compare field="inventoryItem.inventoryItemTypeId" operator="equals" value="SERIALIZED_INV_ITEM"> |
| <get-related-one value-field="itemIssuance" relation-name="OrderHeader" to-value-field="orderHeader"/> |
| <if-not-empty field="orderHeader"> |
| <set field="orderRoleAndMap.orderId" from-field="orderHeader.orderId"/> |
| <set field="orderRoleAndMap.roleTypeId" value="END_USER_CUSTOMER"/> |
| <find-by-and entity-name="OrderRole" list="orderRoles" map="orderRoleAndMap"/> |
| <first-from-list list="orderRoles" entry="orderRole"/> |
| <entity-one entity-name="ProductStore" value-field="productStore" auto-field-map="false"> |
| <field-map field-name="productStoreId" from-field="orderHeader.productStoreId"/> |
| </entity-one> |
| <if> |
| <condition> |
| <and> |
| <not><if-empty field="orderRole"/></not> |
| <or> |
| <if-empty field="productStore"/> |
| <if-empty field="productStore.setOwnerUponIssuance"/> |
| <if-compare field="productStore.setOwnerUponIssuance" operator="equals" value="Y"/> |
| </or> |
| </and> |
| </condition> |
| <then> |
| <set field="updateContext.ownerPartyId" from-field="orderRole.partyId"/> |
| </then> |
| </if> |
| </if-not-empty> |
| <set field="updateContext.inventoryItemId" from-field="inventoryItem.inventoryItemId"/> |
| <call-service service-name="updateInventoryItem" in-map-name="updateContext"/> |
| </if-compare> |
| </if-not-empty> |
| </simple-method> |
| <simple-method method-name="setOrderReservationPriority" short-description="Sets priority of an order for Inventory Reservation, orders with HIGH priority would be served first."> |
| <set field="orderId" from-field="parameters.orderId"/> |
| <entity-one entity-name="OrderHeader" value-field="orderHeader"> |
| <field-map field-name="orderId" from-field="orderId"/> |
| </entity-one> |
| <set field="priority" from-field="parameters.priority"/> |
| <if-empty field="priority"> |
| <entity-and entity-name="OrderItemShipGrpInvRes" list="oisgirs"> |
| <field-map field-name="orderId" from-field="orderId"/> |
| </entity-and> |
| <iterate list="oisgirs" entry="oisgir"> |
| <set field="oisgir.priority" default-value="2"/> |
| <store-value value-field="oisgir"/> |
| </iterate> |
| <set field="orderHeader.priority" default-value="2"/> |
| <store-value value-field="orderHeader"/> |
| <else> |
| <set field="orderHeader.priority" from-field="priority"/> |
| <store-value value-field="orderHeader"/> |
| <entity-and entity-name="OrderItemShipGrpInvRes" list="oisgirs"> |
| <field-map field-name="orderId" from-field="orderId"/> |
| </entity-and> |
| <iterate list="oisgirs" entry="oisgir"> |
| <set field="oisgir.priority" from-field="priority"/> |
| <store-value value-field="oisgir"/> |
| <clear-field field="oisgir"/> |
| </iterate> |
| <entity-condition entity-name="OrderItemAndShipGrpInvResAndItem" list="oisgirais"> |
| <condition-expr field-name="orderId" operator="equals" from-field="orderId"/> |
| </entity-condition> |
| <iterate list="oisgirais" entry="oisgir"> |
| <set field="reassignInventoryReservationsCtx.productId" from-field="oisgir.productId"/> |
| <set field="reassignInventoryReservationsCtx.facilityId" from-field="oisgir.facilityId"/> |
| <call-service service-name="reassignInventoryReservations" in-map-name="reassignInventoryReservationsCtx"/> |
| <clear-field field="reassignInventoryReservationsCtx"/> |
| </iterate> |
| </else> |
| </if-empty> |
| </simple-method> |
| <simple-method method-name="setLastInventoryCount" short-description="Service that updates stock availability of products"> |
| <entity-one entity-name="InventoryItem" value-field="inventoryItem" auto-field-map="false"> |
| <field-map field-name="inventoryItemId" from-field="parameters.inventoryItemId"/> |
| </entity-one> |
| <entity-and entity-name="ProductFacility" list="productFacilities"> |
| <field-map field-name="productId" from-field="inventoryItem.productId" /> |
| </entity-and> |
| <if-not-empty field="productFacilities"> |
| <iterate list="productFacilities" entry="productFacility"> |
| <set field="serviceInMap.productId" from-field="productFacility.productId"/> |
| <set field="serviceInMap.facilityId" from-field="productFacility.facilityId"/> |
| <call-service service-name="getInventoryAvailableByFacility" in-map-name="serviceInMap"> |
| <result-to-field result-name="availableToPromiseTotal"/> |
| </call-service> |
| <clear-field field="serviceInMap"/> |
| <set field="productFacility.lastInventoryCount" from-field="availableToPromiseTotal"/> |
| <set-service-fields service-name="updateProductFacility" map="productFacility" to-map="serviceInMap"/> |
| <call-service service-name="updateProductFacility" in-map-name="serviceInMap"/> |
| <clear-field field="productFacility"/> |
| <clear-field field="serviceInMap"/> |
| </iterate> |
| </if-not-empty> |
| </simple-method> |
| <simple-method method-name="createUpdateFacilityGeoPoint" short-description="Create or update GeoPoint assigned to facility"> |
| <if-empty field="parameters.geoPointId"> |
| <set-service-fields service-name="createGeoPoint" map="parameters" to-map="createGeoPointMap"/>/> |
| <call-service service-name="createGeoPoint" in-map-name="createGeoPointMap"> |
| <result-to-field result-name="geoPointId" field="geoPointId"/> |
| </call-service> |
| <entity-one entity-name="Facility" value-field="facility"/> |
| <set field="facility.geoPointId" from-field="geoPointId"/> |
| <store-value value-field="facility"/> |
| <else> |
| <set-service-fields service-name="updateGeoPoint" map="parameters" to-map="updateGeoPointMap"/>/> |
| <call-service service-name="updateGeoPoint" in-map-name="updateGeoPointMap"/> |
| </else> |
| </if-empty> |
| </simple-method> |
| |
| <simple-method method-name="createInventoryItemLabelAppl" short-description="Create an InventoryItemLabelAppl"> |
| <make-value entity-name="InventoryItemLabelAppl" value-field="newEntity"/> |
| <set-pk-fields map="parameters" value-field="newEntity"/> |
| <set-nonpk-fields map="parameters" value-field="newEntity"/> |
| <entity-one entity-name="InventoryItemLabel" value-field="inventoryItemLabel"/> |
| <set field="newEntity.inventoryItemLabelTypeId" from-field="inventoryItemLabel.inventoryItemLabelTypeId"/> |
| <create-value value-field="newEntity"/> |
| </simple-method> |
| |
| </simple-methods> |