blob: ce88ffb9f53d83e8bb8daa0399416f6a4cbcc27a [file] [log] [blame]
<?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">
<!-- CostComponent services -->
<simple-method method-name="cancelCostComponents" short-description="Cancels CostComponents">
<set from-field="parameters.costComponentId" field="costsAndMap.costComponentId"/>
<set from-field="parameters.productId" field="costsAndMap.productId"/>
<set from-field="parameters.costUomId" field="costsAndMap.costUomId"/>
<set from-field="parameters.costComponentTypeId" field="costsAndMap.costComponentTypeId"/>
<find-by-and entity-name="CostComponent" map="costsAndMap" list="existingCosts"/>
<filter-list-by-date list="existingCosts"/>
<iterate list="existingCosts" entry="existingCost">
<now-timestamp field="existingCost.thruDate"/>
<store-value value-field="existingCost"/>
</iterate>
</simple-method>
<simple-method method-name="recreateCostComponent" short-description="Create a CostComponent and cancel the existing ones">
<!-- The existing costs of the same type are expired -->
<set from-field="parameters.productId" field="costsAndMap.productId"/>
<set from-field="parameters.costUomId" field="costsAndMap.costUomId"/>
<set from-field="parameters.costComponentTypeId" field="costsAndMap.costComponentTypeId"/>
<find-by-and entity-name="CostComponent" map="costsAndMap" list="existingCosts"/>
<filter-list-by-date list="existingCosts"/>
<iterate list="existingCosts" entry="existingCost">
<now-timestamp field="existingCost.thruDate"/>
<store-value value-field="existingCost"/>
</iterate>
<!-- The new cost is created -->
<make-value value-field="newEntity" entity-name="CostComponent"/>
<set-nonpk-fields map="parameters" value-field="newEntity"/>
<sequenced-id sequence-name="CostComponent" field="newEntity.costComponentId"/>
<if-empty field="newEntity.fromDate">
<now-timestamp field="newEntity.fromDate"/>
</if-empty>
<create-value value-field="newEntity"/>
<field-to-result field="newEntity.costComponentId" result-name="costComponentId"/>
</simple-method>
<!-- Services to get the product and tasks costs -->
<simple-method method-name="getProductCost" short-description="Gets the product's costs (from CostComponent or ProductPrice)">
<entity-condition entity-name="CostComponent" list="costComponents" filter-by-date="true">
<condition-list>
<condition-expr field-name="productId" operator="equals" from-field="parameters.productId"/>
<condition-expr field-name="costUomId" operator="equals" from-field="parameters.currencyUomId"/>
<condition-expr field-name="costComponentTypeId" operator="like" value="${parameters.costComponentTypePrefix}_%"/>
</condition-list>
</entity-condition>
<set field="productCost" value="0" type="BigDecimal"/>
<iterate list="costComponents" entry="costComponent">
<calculate field="productCost" decimal-scale="6">
<calcop operator="add" field="costComponent.cost">
<calcop operator="get" field="productCost"/>
</calcop>
</calculate>
<!--set field="productCost" value="${costComponent.cost + productCost}" type="BigDecimal"/-->
</iterate>
<!-- if the cost is zero, and the product is a variant, get the cost of the virtual -->
<if-compare field="productCost" operator="equals" value="0" type="BigDecimal">
<entity-one entity-name="Product" value-field="product"/>
<set from-field="product.productId" field="assocAndMap.productIdTo"/>
<set value="PRODUCT_VARIANT" field="assocAndMap.productAssocTypeId"/>
<find-by-and entity-name="ProductAssoc" map="assocAndMap" list="virtualAssocs"/>
<filter-list-by-date list="virtualAssocs"/>
<first-from-list list="virtualAssocs" entry="virtualAssoc"/>
<if-not-empty field="virtualAssoc">
<set from-field="virtualAssoc.productId" field="inputMap.productId"/>
<set from-field="parameters.currencyUomId" field="inputMap.currencyUomId"/>
<set from-field="parameters.costComponentTypePrefix" field="inputMap.costComponentTypePrefix"/>
<call-service service-name="getProductCost" in-map-name="inputMap">
<result-to-field result-name="productCost"/>
</call-service>
</if-not-empty>
</if-compare>
<!-- if the cost is zero, get the purchase cost from the SupplierProduct -->
<if-compare field="productCost" operator="equals" value="0" type="BigDecimal">
<set field="orderByList[]" value="+supplierPrefOrderId"/>
<set field="orderByList[]" value="+lastPrice"/>
<clear-field field="costsAndMap"/>
<set from-field="parameters.productId" field="costsAndMap.productId"/>
<set from-field="parameters.currencyUomId" field="costsAndMap.currencyUomId"/>
<find-by-and entity-name="SupplierProduct" map="costsAndMap" list="priceCosts" order-by-list="orderByList"/>
<filter-list-by-date list="priceCosts" from-field-name="availableFromDate" thru-field-name="availableThruDate"/>
<first-from-list list="priceCosts" entry="priceCost"/>
<if-not-empty field="priceCost.lastPrice">
<set from-field="priceCost.lastPrice" field="productCost"/>
</if-not-empty>
<!-- if the cost is zero, get the purchase cost from the SupplierProduct
in a different currency and try to convert
-->
<if-compare field="productCost" operator="equals" value="0" type="BigDecimal">
<clear-field field="costsAndMap"/>
<set from-field="parameters.productId" field="costsAndMap.productId"/>
<find-by-and entity-name="SupplierProduct" map="costsAndMap" list="priceCosts" order-by-list="orderByList"/>
<filter-list-by-date list="priceCosts" from-field-name="availableFromDate" thru-field-name="availableThruDate"/>
<first-from-list list="priceCosts" entry="priceCost"/>
<if-not-empty field="priceCost.lastPrice">
<!-- we try to convert the lastPrice to the desired currency -->
<clear-field field="inputMap"/>
<set from-field="priceCost.lastPrice" field="inputMap.originalValue"/>
<set from-field="priceCost.currencyUomId" field="inputMap.uomId"/>
<set from-field="parameters.currencyUomId" field="inputMap.uomIdTo"/>
<call-service service-name="convertUom" in-map-name="inputMap" require-new-transaction="true" break-on-error="false">
<result-to-field result-name="convertedValue" field="productCost"/>
</call-service>
<!-- if currency conversion fails then a 0 cost will be returned -->
<if-empty field="productCost">
<log level="warning" message="Currency conversion failed for ProductCost lookup; unable to convert from ${priceCost.currencyUomId} to ${parameters.currencyUomId}"/>
<set field="productCost" value="0" type="BigDecimal"/>
</if-empty>
</if-not-empty>
</if-compare>
</if-compare>
<!--
<if-compare field="productCost" operator="equals" value="0" type="BigDecimal">
<clear-field field="costsAndMap"/>
<set from-field="parameters.productId" field="costsAndMap.productId"/>
<set from-field="parameters.currencyUomId" field="costsAndMap.currencyUomId"/>
<set from-field="parameters.productPriceTypeId" field="costsAndMap.productPriceTypeId"/>
<find-by-and entity-name="ProductPrice" map="costsAndMap" list="priceCosts"/>
<filter-list-by-date list="priceCosts"/>
<first-from-list list="priceCosts" entry="priceCost"/>
<if-not-empty field="priceCost.price">
<set from-field="priceCost.price" field="productCost"/>
</if-not-empty>
</if-compare>
-->
<field-to-result field="productCost"/>
</simple-method>
<simple-method method-name="getTaskCost" short-description="Gets the production run task's costs">
<!-- First of all, the estimated task time is computed -->
<set-service-fields service-name="getEstimatedTaskTime" map="parameters" to-map="inputMap"/>
<set from-field="parameters.workEffortId" field="inputMap.taskId"/>
<call-service service-name="getEstimatedTaskTime" in-map-name="inputMap">
<result-to-field result-name="estimatedTaskTime" field="totalEstimatedTaskTime"/>
<result-to-field result-name="setupTime"/>
</call-service>
<calculate field="estimatedTaskTime" decimal-scale="6">
<calcop operator="subtract" field="totalEstimatedTaskTime">
<calcop operator="get" field="setupTime"/>
</calcop>
</calculate>
<entity-one entity-name="WorkEffort" value-field="task"/>
<if-not-empty field="task">
<get-related-one value-field="task" relation-name="FixedAsset" to-value-field="fixedAsset"/>
<set from-field="parameters.currencyUomId" field="costsAndMap.amountUomId"/>
<set value="SETUP_COST" field="costsAndMap.fixedAssetStdCostTypeId"/>
<get-related value-field="fixedAsset" relation-name="FixedAssetStdCost" map="costsAndMap" list="setupCosts"/>
<filter-list-by-date list="setupCosts"/>
<!--<filter-list-by-and list-name="costs" map-name="costsAndMap"/>-->
<first-from-list list="setupCosts" entry="setupCost"/>
<set value="USAGE_COST" field="costsAndMap.fixedAssetStdCostTypeId"/>
<get-related value-field="fixedAsset" relation-name="FixedAssetStdCost" map="costsAndMap" list="usageCosts"/>
<filter-list-by-date list="usageCosts"/>
<first-from-list list="usageCosts" entry="usageCost"/>
</if-not-empty>
<calculate field="taskCost" decimal-scale="6">
<calcop operator="add">
<calcop operator="multiply" field="estimatedTaskTime">
<calcop operator="get" field="usageCost.amount"/>
</calcop>
<calcop operator="multiply" field="setupTime">
<calcop operator="get" field="setupCost.amount"/>
</calcop>
</calcop>
</calculate>
<!-- Time is converted from milliseconds to hours -->
<calculate field="taskCost" decimal-scale="6">
<calcop operator="divide" field="taskCost">
<number value="3600000"/>
</calcop>
</calculate>
<!-- Now compute the costs derived from CostComponentCalc records associated with the task -->
<get-related relation-name="WorkEffortCostCalc" list="weccs" value-field="task"/>
<filter-list-by-date list="weccs"/>
<iterate list="weccs" entry="wecc">
<clear-field field="totalCostComponentCost"/>
<clear-field field="totalCostComponentTime"/>
<get-related-one relation-name="CostComponentCalc" to-value-field="costComponentCalc" value-field="wecc"/>
<get-related-one relation-name="CustomMethod" to-value-field="customMethod" value-field="costComponentCalc"/>
<if-empty field="customMethod">
<if-not-empty field="costComponentCalc.perMilliSecond">
<if-compare operator="not-equals" value="0" field="costComponentCalc.perMilliSecond" type="BigDecimal">
<calculate field="totalCostComponentTime" decimal-scale="6">
<calcop operator="divide" field="totalEstimatedTaskTime">
<calcop operator="get" field="costComponentCalc.perMilliSecond"/>
</calcop>
</calculate>
<calculate field="totalCostComponentCost" decimal-scale="6">
<calcop operator="multiply" field="totalCostComponentTime">
<calcop operator="get" field="costComponentCalc.variableCost"/>
</calcop>
</calculate>
<calculate field="totalCostComponentCost" decimal-scale="6">
<calcop operator="add" field="totalCostComponentCost">
<calcop operator="get" field="costComponentCalc.fixedCost"/>
</calcop>
</calculate>
<set field="costsByType.${wecc.costComponentTypeId}" from-field="totalCostComponentCost"/>
</if-compare>
</if-not-empty>
<else>
<!-- FIXME: formulas are still not supported for standard costs -->
</else>
</if-empty>
</iterate>
<field-to-result field="taskCost"/>
<field-to-result field="costsByType"/>
</simple-method>
<!-- services to automatically generate cost information -->
<simple-method method-name="calculateAllProductsCosts" short-description="Calculates estimated costs for all the products">
<!--filter-by-date="true"-->
<entity-condition entity-name="Product" list="products">
<select-field field-name="productId"/>
<order-by field-name="-billOfMaterialLevel"/>
</entity-condition>
<set from-field="parameters.currencyUomId" field="inMap.currencyUomId"/>
<set from-field="parameters.costComponentTypePrefix" field="inMap.costComponentTypePrefix"/>
<iterate list="products" entry="product">
<set from-field="product.productId" field="inMap.productId"/>
<call-service service-name="calculateProductCosts" in-map-name="inMap"/>
</iterate>
</simple-method>
<simple-method method-name="calculateProductCosts" short-description="Calculates the product's cost">
<!-- the existing costs are expired -->
<set value="${parameters.costComponentTypePrefix}_ROUTE_COST" field="cancelMap.costComponentTypeId"/>
<set from-field="parameters.productId" field="cancelMap.productId"/>
<set from-field="parameters.currencyUomId" field="cancelMap.costUomId"/>
<call-service service-name="cancelCostComponents" in-map-name="cancelMap"/>
<set value="${parameters.costComponentTypePrefix}_MAT_COST" field="cancelMap.costComponentTypeId"/>
<call-service service-name="cancelCostComponents" in-map-name="cancelMap"/>
<!-- calculate the total materials' cost -->
<set from-field="parameters.productId" field="callSvcMap.productId"/>
<call-service service-name="getManufacturingComponents" in-map-name="callSvcMap">
<result-to-field result-name="componentsMap"/>
</call-service>
<if-not-empty field="componentsMap">
<iterate list="componentsMap" entry="componentMap">
<clear-field field="inputMap"/>
<set field="product" from-field="componentMap.product"/>
<set field="inputMap.productId" from-field="product.productId"/>
<set field="inputMap.currencyUomId" from-field="parameters.currencyUomId"/>
<set field="inputMap.costComponentTypePrefix" from-field="parameters.costComponentTypePrefix"/>
<call-service service-name="getProductCost" in-map-name="inputMap">
<result-to-field result-name="productCost"/>
</call-service>
<calculate field="totalProductsCost" decimal-scale="6">
<calcop operator="add" field="totalProductsCost">
<calcop operator="multiply" field="componentMap.quantity">
<calcop operator="get" field="productCost"/>
</calcop>
</calcop>
</calculate>
</iterate>
<else>
<clear-field field="inputMap"/>
<set field="inputMap.productId" from-field="parameters.productId"/>
<set field="inputMap.currencyUomId" from-field="parameters.currencyUomId"/>
<set field="inputMap.costComponentTypePrefix" from-field="parameters.costComponentTypePrefix"/>
<call-service service-name="getProductCost" in-map-name="inputMap">
<result-to-field result-name="productCost"/>
</call-service>
<calculate field="totalProductsCost" decimal-scale="6">
<calcop operator="get" field="productCost"/>
</calculate>
</else>
</if-not-empty>
<!-- calculate the total tasks' cost -->
<set field="callSvcMap.ignoreDefaultRouting" value="Y"/>
<call-service service-name="getProductRouting" in-map-name="callSvcMap">
<result-to-field result-name="tasks"/>
<result-to-field result-name="routing"/>
</call-service>
<iterate list="tasks" entry="task">
<clear-field field="callSvcMap"/>
<set from-field="task.workEffortIdTo" field="callSvcMap.workEffortId"/>
<set from-field="parameters.currencyUomId" field="callSvcMap.currencyUomId"/>
<set from-field="parameters.productId" field="callSvcMap.productId"/>
<set from-field="routing.workEffortId" field="callSvcMap.routingId"/>
<call-service service-name="getTaskCost" in-map-name="callSvcMap">
<result-to-field result-name="taskCost" field="taskCost"/>
<result-to-field result-name="costsByType" field="costsByType"/>
</call-service>
<calculate field="totalTaskCost" decimal-scale="6">
<calcop operator="add" field="totalTaskCost">
<calcop operator="get" field="taskCost"/>
</calcop>
</calculate>
<iterate-map map="costsByType" key="costType" value="costAmount">
<if-not-empty field="totalCostsByType.${costType}">
<calculate field="totalCostsByType.${costType}" decimal-scale="6">
<calcop operator="add" field="costAmount">
<calcop operator="get" field="totalCostsByType.${costType}"/>
</calcop>
</calculate>
<else>
<set field="totalCostsByType.${costType}" from-field="costAmount"/>
</else>
</if-not-empty>
<calculate field="totalOtherTaskCost" decimal-scale="6">
<calcop operator="add" field="totalOtherTaskCost">
<calcop operator="get" field="costAmount"/>
</calcop>
</calculate>
</iterate-map>
</iterate>
<calculate field="totalCost" decimal-scale="6">
<calcop operator="add" field="totalTaskCost">
<calcop operator="get" field="totalProductsCost"/>
<calcop operator="get" field="totalOtherTaskCost"/>
</calcop>
</calculate>
<!-- The CostComponent records are created. -->
<if-not-empty field="totalTaskCost">
<if-compare field="totalTaskCost" operator="greater" value="0" type="BigDecimal">
<clear-field field="callSvcMap"/>
<set value="${parameters.costComponentTypePrefix}_ROUTE_COST" field="callSvcMap.costComponentTypeId"/>
<set from-field="parameters.productId" field="callSvcMap.productId"/>
<set from-field="parameters.currencyUomId" field="callSvcMap.costUomId"/>
<set from-field="totalTaskCost" field="callSvcMap.cost"/>
<call-service service-name="recreateCostComponent" in-map-name="callSvcMap"/>
</if-compare>
</if-not-empty>
<if-not-empty field="totalProductsCost">
<if-compare field="totalProductsCost" operator="greater" value="0" type="BigDecimal">
<clear-field field="callSvcMap"/>
<set value="${parameters.costComponentTypePrefix}_MAT_COST" field="callSvcMap.costComponentTypeId"/>
<set from-field="parameters.productId" field="callSvcMap.productId"/>
<set from-field="parameters.currencyUomId" field="callSvcMap.costUomId"/>
<set from-field="totalProductsCost" field="callSvcMap.cost"/>
<call-service service-name="recreateCostComponent" in-map-name="callSvcMap"/>
</if-compare>
</if-not-empty>
<iterate-map map="totalCostsByType" key="costType" value="totalCostAmount">
<clear-field field="callSvcMap"/>
<set value="${parameters.costComponentTypePrefix}_${costType}" field="callSvcMap.costComponentTypeId"/>
<set from-field="parameters.productId" field="callSvcMap.productId"/>
<set from-field="parameters.currencyUomId" field="callSvcMap.costUomId"/>
<set from-field="totalCostAmount" field="callSvcMap.cost"/>
<call-service service-name="recreateCostComponent" in-map-name="callSvcMap"/>
</iterate-map>
<!-- Now compute the costs derived from CostComponentCalc records associated with the product -->
<entity-condition entity-name="ProductCostComponentCalc" list="productCostComponentCalcs" filter-by-date="true">
<condition-expr field-name="productId" from-field="parameters.productId"/>
<order-by field-name="sequenceNum"/>
</entity-condition>
<iterate list="productCostComponentCalcs" entry="productCostComponentCalc">
<get-related-one relation-name="CostComponentCalc" to-value-field="costComponentCalc" value-field="productCostComponentCalc"/>
<get-related-one relation-name="CustomMethod" to-value-field="customMethod" value-field="costComponentCalc"/>
<if-empty field="customMethod">
<!-- TODO: not supported for CostComponentCalc entries directly associated to a product -->
<log level="warning" message="Unable to create cost component for cost component calc with id [${costComponentCalc.costComponentCalcId}] because customMethod is not set"/>
<else>
<clear-field field="customMethodParameters"/>
<set field="customMethodParameters.productCostComponentCalc" from-field="productCostComponentCalc"/>
<set field="customMethodParameters.costComponentCalc" from-field="costComponentCalc"/>
<set from-field="parameters.currencyUomId" field="customMethodParameters.currencyUomId"/>
<set from-field="parameters.costComponentTypePrefix" field="customMethodParameters.costComponentTypePrefix"/>
<set from-field="totalCost" field="customMethodParameters.baseCost"/>
<call-service service-name="${customMethod.customMethodName}" in-map-name="customMethodParameters">
<result-to-field result-name="productCostAdjustment"/>
</call-service>
<clear-field field="callSvcMap"/>
<set value="${parameters.costComponentTypePrefix}_${productCostComponentCalc.costComponentTypeId}" field="callSvcMap.costComponentTypeId"/>
<set from-field="productCostComponentCalc.productId" field="callSvcMap.productId"/>
<set from-field="parameters.currencyUomId" field="callSvcMap.costUomId"/>
<set from-field="productCostAdjustment" field="callSvcMap.cost"/>
<call-service service-name="recreateCostComponent" in-map-name="callSvcMap"/>
<!--set field="totalCost" value="${totalCost + productCostAdjustment}" type="BigDecimal"/-->
<calculate field="totalCost" decimal-scale="6">
<calcop operator="add" field="totalCost">
<calcop operator="get" field="productCostAdjustment"/>
</calcop>
</calculate>
</else>
</if-empty>
</iterate>
<field-to-result field="totalCost"/>
</simple-method>
<simple-method method-name="calculateProductAverageCost" short-description="Calculate inventory average cost for a product">
<entity-condition entity-name="InventoryItem" list="inventoryItems">
<condition-list>
<condition-expr field-name="productId" from-field="parameters.productId"/>
<condition-expr field-name="facilityId" from-field="parameters.facilityId" ignore-if-empty="true"/>
<condition-expr field-name="ownerPartyId" from-field="parameters.ownerPartyId" ignore-if-empty="true"/>
<condition-expr field-name="unitCost" operator="not-equals" from-field="nullField"/>
</condition-list>
<select-field field-name="quantityOnHandTotal"/>
<select-field field-name="unitCost"/>
<select-field field-name="currencyUomId"/>
</entity-condition>
<set field="totalQuantityOnHand" type="BigDecimal" value="0"/>
<set field="totalInventoryCost" type="BigDecimal" value="0"/>
<set field="absValOfTotalQOH" type="BigDecimal" value="0"/>
<set field="absValOfTotalInvCost" type="BigDecimal" value="0"/>
<set field="differentCurrencies" type="Boolean" value="false"/>
<iterate list="inventoryItems" entry="inventoryItem">
<calculate field="totalQuantityOnHand">
<calcop operator="add" >
<calcop operator="get" field="totalQuantityOnHand"/>
<calcop operator="get" field="inventoryItem.quantityOnHandTotal"/>
</calcop>
</calculate>
<if-empty field="currencyUomId">
<set field="currencyUomId" from-field="inventoryItem.currencyUomId"/>
</if-empty>
<if-compare field="differentCurrencies" operator="equals" value="false" type="Boolean">
<if-compare-field field="inventoryItem.currencyUomId" operator="equals" to-field="currencyUomId">
<calculate field="totalInventoryCost" type="BigDecimal">
<calcop operator="add">
<calcop operator="get" field="totalInventoryCost"/>
<calcop operator="multiply">
<calcop operator="get" field="inventoryItem.quantityOnHandTotal"/>
<calcop operator="get" field="inventoryItem.unitCost"/>
</calcop>
</calcop>
</calculate>
<!-- calculation of absolute values of QOH and total inventory cost -->
<if-compare field="inventoryItem.quantityOnHandTotal" operator="less" value="0">
<calculate field="absValOfTotalQOH">
<calcop operator="add">
<calcop operator="get" field="absValOfTotalQOH"/>
<calcop operator="negative" field="inventoryItem.quantityOnHandTotal"/>
</calcop>
</calculate>
<calculate field="absValOfTotalInvCost" type="BigDecimal">
<calcop operator="add">
<calcop operator="get" field="absValOfTotalInvCost"/>
<calcop operator="multiply">
<calcop operator="negative" field="inventoryItem.quantityOnHandTotal"/>
<calcop operator="get" field="inventoryItem.unitCost"/>
</calcop>
</calcop>
</calculate>
<else>
<calculate field="absValOfTotalQOH">
<calcop operator="add" >
<calcop operator="get" field="absValOfTotalQOH"/>
<calcop operator="get" field="inventoryItem.quantityOnHandTotal"/>
</calcop>
</calculate>
<calculate field="absValOfTotalInvCost" type="BigDecimal">
<calcop operator="add">
<calcop operator="get" field="absValOfTotalInvCost"/>
<calcop operator="multiply">
<calcop operator="get" field="inventoryItem.quantityOnHandTotal"/>
<calcop operator="get" field="inventoryItem.unitCost"/>
</calcop>
</calcop>
</calculate>
</else>
</if-compare>
<else>
<set field="differentCurrencies" type="Boolean" value="true"/>
</else>
</if-compare-field>
</if-compare>
</iterate>
<if-compare field="absValOfTotalQOH" operator="not-equals" value="0" type="BigDecimal">
<calculate field="productAverageCost" type="BigDecimal">
<calcop operator="divide">
<calcop operator="get" field="absValOfTotalInvCost"/>
<calcop operator="get" field="absValOfTotalQOH"/>
</calcop>
</calculate>
<else>
<set field="productAverageCost" type="BigDecimal" value="0"/>
</else>
</if-compare>
<field-to-result field="totalQuantityOnHand"/>
<if-compare field="differentCurrencies" operator="equals" value="false" type="Boolean">
<field-to-result field="totalInventoryCost"/>
<field-to-result field="productAverageCost"/>
<field-to-result field="currencyUomId"/>
</if-compare>
</simple-method>
<simple-method method-name="updateProductAverageCostOnReceiveInventory" short-description="Update a Product Average Cost record on receive inventory">
<entity-one entity-name="InventoryItem" value-field="inventoryItem"/>
<set field="organizationPartyId" from-field="inventoryItem.ownerPartyId"/>
<if-empty field="organizationPartyId">
<entity-one entity-name="Facility" value-field="facility" auto-field-map="true"/>
<set field="organizationPartyId" from-field="facility.ownerPartyId"/>
<if-empty field="organizationPartyId">
<get-related-one relation-name="ProductStore" to-value-field="productStore" value-field="facility"/>
<set field="organizationPartyId" from-field="productStore.ownerPartyId"/>
<if-empty field="organizationPartyId">
<add-error error-list-name="error_list">
<fail-property resource="ProductUiLabels" property="ProductOwnerPartyIsMissing"/>
</add-error>
</if-empty>
<check-errors/>
</if-empty>
</if-empty>
<entity-and entity-name="ProductAverageCost" list="productAverageCostList" filter-by-date="true">
<field-map field-name="productId" from-field="parameters.productId"/>
<field-map field-name="facilityId" from-field="parameters.facilityId"/>
<field-map field-name="productAverageCostTypeId" value="SIMPLE_AVG_COST"/>
<field-map field-name="organizationPartyId"/>
</entity-and>
<first-from-list list="productAverageCostList" entry="productAverageCost"/>
<!-- <log level="always" message="In updateProductAverageCostOnReceiveInventory found productAverageCost: ${productAverageCost}"/> -->
<set-service-fields service-name="createProductAverageCost" map="parameters" to-map="productAverageCostMap"/>
<set field="productAverageCostMap.productAverageCostTypeId" value="SIMPLE_AVG_COST"/>
<set field="productAverageCostMap.organizationPartyId" from-field="organizationPartyId"/>
<if-empty field="productAverageCost">
<set field="productAverageCostMap.averageCost" from-field="inventoryItem.unitCost"/>
<else>
<!-- Expire existing one and calculate average cost -->
<set-service-fields service-name="updateProductAverageCost" map="productAverageCost" to-map="updateProductAverageCostMap"/>
<now-timestamp field="updateProductAverageCostMap.thruDate"/>
<call-service service-name="updateProductAverageCost" in-map-name="updateProductAverageCostMap"/>
<set field="serviceInMap.productId" from-field="parameters.productId"/>
<set field="serviceInMap.facilityId" from-field="parameters.facilityId"/>
<call-service service-name="getInventoryAvailableByFacility" in-map-name="serviceInMap">
<result-to-field result-name="quantityOnHandTotal"/>
</call-service>
<set field="oldProductQuantity" value="${quantityOnHandTotal - parameters.quantityAccepted}" type="BigDecimal"/>
<set field="productAverageCostMap.averageCost" value="${((productAverageCost.averageCost * oldProductQuantity) + (inventoryItem.unitCost * parameters.quantityAccepted))/(quantityOnHandTotal)}" type="BigDecimal"/>
<property-to-field resource="arithmetic" property="finaccount.decimals" field="roundingDecimals" default="2"/>
<property-to-field resource="arithmetic" property="finaccount.roundingSimpleMethod" field="roundingMode" default="HalfUp"/>
<calculate field="productAverageCostMap.averageCost" type="BigDecimal" decimal-scale="${roundingDecimals}" rounding-mode="${roundingMode}">
<calcop operator="get" field="productAverageCostMap.averageCost"/>
</calculate>
<!-- ensure that the new ProductAverageCost record has a different PK than the previous one by setting the fromDate to now, plus an offset if needed -->
<now-timestamp field="nowTimestamp"/>
<set field="timeDiff" value="${groovy: return nowTimestamp.getTime() - productAverageCost.fromDate.getTime()}" type="Long"/>
<if-compare field="timeDiff" operator="less-equals" value="1000" type="Long">
<set-calendar field="productAverageCostMap.fromDate" from-field="nowTimestamp" seconds="+1"/>
<else>
<set field="productAverageCostMap.fromDate" from-field="nowTimestamp"/>
</else>
</if-compare>
</else>
</if-empty>
<!-- <log level="info" message="In updateProductAverageCostOnReceiveInventory creating new average cost with productAverageCostMap: ${productAverageCostMap}"/> -->
<call-service service-name="createProductAverageCost" in-map-name="productAverageCostMap"/>
<log level="info" message="For facilityId ${parameters.facilityId}, Average cost of product ${parameters.productId} is set from ${updateProductAverageCostMap.averageCost} to ${productAverageCostMap.averageCost}"/>
</simple-method>
<simple-method method-name="getProductAverageCost" short-description="Service to get the average cost of product">
<set field="inventoryItem" from-field="parameters.inventoryItem"/>
<set field="getPartyAcctgPrefMap.organizationPartyId" from-field="inventoryItem.ownerPartyId"/>
<call-service service-name="getPartyAccountingPreferences" in-map-name="getPartyAcctgPrefMap">
<result-to-field result-name="partyAccountingPreference"/>
</call-service>
<if-compare field="partyAccountingPreference.cogsMethodId" operator="equals" value="COGS_AVG_COST">
<entity-and entity-name="ProductAverageCost" list="productAverageCostList" filter-by-date="true">
<field-map field-name="productAverageCostTypeId" value="SIMPLE_AVG_COST"/> <!-- TODO: handle for WEIGHTED_AVG_COST and MOVING_AVG_COST -->
<field-map field-name="organizationPartyId" from-field="inventoryItem.ownerPartyId"/>
<field-map field-name="productId" from-field="inventoryItem.productId"/>
<field-map field-name="facilityId" from-field="inventoryItem.facilityId"/>
</entity-and>
<first-from-list list="productAverageCostList" entry="productAverageCost"/>
</if-compare>
<if-not-empty field="productAverageCost">
<set field="unitCost" from-field="productAverageCost.averageCost" type="BigDecimal"/>
<else>
<set field="unitCost" from-field="inventoryItem.unitCost" type="BigDecimal"/>
</else>
</if-not-empty>
<field-to-result field="unitCost"/>
</simple-method>
<simple-method method-name="productCostPercentageFormula" short-description="Formula that creates a cost component equal to a percentage of total product cost">
<set field="productCostComponentCalc" from-field="parameters.productCostComponentCalc"/>
<set field="costComponentCalc" from-field="parameters.costComponentCalc"/>
<set field="inputMap.productId" from-field="productCostComponentCalc.productId"/>
<set field="inputMap.currencyUomId" from-field="parameters.currencyUomId"/>
<set field="inputMap.costComponentTypePrefix" from-field="parameters.costComponentTypePrefix"/>
<call-service service-name="getProductCost" in-map-name="inputMap">
<result-to-field result-name="productCost"/>
</call-service>
<!--set field="productCostAdjustment" value="${parameters.baseCost * costComponentCalc.fixedCost}" type="BigDecimal"/-->
<calculate field="productCostAdjustment" type="BigDecimal" decimal-scale="6">
<calcop operator="multiply" field="costComponentCalc.fixedCost">
<calcop operator="get" field="parameters.baseCost"/>
</calcop>
</calculate>
<field-to-result field="productCostAdjustment"/>
</simple-method>
</simple-methods>