This is an automated email from the ASF dual-hosted git repository. nmalin pushed a commit to branch trunk in repository https://gitbox.apache.org/repos/asf/ofbiz-framework.git
The following commit(s) were added to refs/heads/trunk by this push: new 1f84596e20 Improved: Convert FixedAssetServices.xml mini lang to groovy (OFBIZ-12852) 1f84596e20 is described below commit 1f84596e20e9824bd0afbd1d8b1ff9955b9caf23 Author: Nicolas Malin <nicolas.ma...@nereide.fr> AuthorDate: Fri Sep 1 15:57:21 2023 +0200 Improved: Convert FixedAssetServices.xml mini lang to groovy (OFBIZ-12852) Finish to convert FixedAssetServices.xml with migrate service : * createFixedAssetMaint * updateFixedAssetMaint * createMaintsFromTimeInterval * autoAssignFixedAssetPartiesToMaintenance * createMaintsFromMeterReading * createFixedAssetMaintOrder * checkUpdateFixedAssetDepreciation * straightLineDepreciation * doubleDecliningBalanceDepreciation * calculateFixedAssetDepreciation --- .../accounting/config/AccountingErrorUiLabels.xml | 4 + .../minilang/fixedasset/FixedAssetServices.xml | 750 --------------------- .../accounting/servicedef/services_fixedasset.xml | 42 +- .../fixedasset/FixedAssetServices.groovy | 464 +++++++++++++ 4 files changed, 492 insertions(+), 768 deletions(-) diff --git a/applications/accounting/config/AccountingErrorUiLabels.xml b/applications/accounting/config/AccountingErrorUiLabels.xml index 4f1c0a6c70..00da5796fd 100644 --- a/applications/accounting/config/AccountingErrorUiLabels.xml +++ b/applications/accounting/config/AccountingErrorUiLabels.xml @@ -391,6 +391,10 @@ <value xml:lang="zh">找到的补充方法未知</value> <value xml:lang="zh-TW">找到的補充方法未知</value> </property> + <property key="AccountingFixedAssetNotFound"> + <value xml:lang="en">Fixed asset not found</value> + <value xml:lang="fr">Immobilisation non trouvée</value> + </property> <property key="AccountingGiftCardCannotBeCreated"> <value xml:lang="ar">خطأ: لا يمكن خلق بطاقة الهدية (فشل توليد الدليل)</value> <value xml:lang="de">FEHLER: Kann Geschenkkarte nicht erstellen (Fehler bei Id Erstellung)</value> diff --git a/applications/accounting/minilang/fixedasset/FixedAssetServices.xml b/applications/accounting/minilang/fixedasset/FixedAssetServices.xml deleted file mode 100644 index 856b2b2a13..0000000000 --- a/applications/accounting/minilang/fixedasset/FixedAssetServices.xml +++ /dev/null @@ -1,750 +0,0 @@ -<?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"> - - <!-- create/update/delete FixedAssetMaint --> - <simple-method method-name="createFixedAssetMaint" short-description="create a FixedAssetMaint"> - <make-value entity-name="FixedAssetMaint" value-field="newEntity"/> - <set-pk-fields map="parameters" value-field="newEntity"/> - <make-next-seq-id value-field="newEntity" seq-field-name="maintHistSeqId"/> <!-- this finds the next sub-sequence ID --> - <field-to-result field="newEntity.maintHistSeqId" result-name="maintHistSeqId"/> - <set-nonpk-fields map="parameters" value-field="newEntity"/> - <if-not-empty field="parameters.productMaintSeqId"> - <entity-one entity-name="FixedAsset" value-field="fixedAsset"/> - <entity-one entity-name="ProductMaint" value-field="productMaint"> - <field-map field-name="productId" from-field="fixedAsset.instanceOfProductId"/> - <field-map field-name="productMaintSeqId" from-field="parameters.productMaintSeqId"/> - </entity-one> - <set field="newEntity.productMaintTypeId" from-field="productMaint.productMaintTypeId"/> - </if-not-empty > - <if-not-empty field="productMaint.maintTemplateWorkEffortId"> - <set field="maintTemplateWorkEffortId" from-field="productMaint.maintTemplateWorkEffortId"/> - <else> - <!-- User can still pick a Template workEffort --> - <set field="maintTemplateWorkEffortId" from-field="parameters.maintTemplateWorkEffortId"/> - </else> - </if-not-empty> - <if-not-empty field="maintTemplateWorkEffortId"> - - <set field="duplicateTemplateWorkEffortMap.oldWorkEffortId" from-field="maintTemplateWorkEffortId"/> - <sequenced-id sequence-name="WorkEffort" field="duplicateTemplateWorkEffortMap.workEffortId"/> - <set field="duplicateTemplateWorkEffortMap.duplicateWorkEffortAssocs" value="Y"/> - <set field="duplicateTemplateWorkEffortMap.duplicateWorkEffortNotes" value="Y"/> - <set field="duplicateTemplateWorkEffortMap.duplicateWorkEffortContents" value="Y"/> - <set field="duplicateTemplateWorkEffortMap.duplicateWorkEffortAssignmentRates" value="Y"/> - <call-service service-name="duplicateWorkEffort" in-map-name="duplicateTemplateWorkEffortMap"/> - <set field="newEntity.scheduleWorkEffortId" from-field="duplicateTemplateWorkEffortMap.workEffortId"/> - - <else> - <!-- Create the WorkEffort --> - <!-- Maintenance WorkEffort entity --> - <entity-one entity-name="FixedAsset" value-field="fixedAsset"/> - <property-to-field field="workEffortName" resource="AccountingUiLabels" property="AccountingFixedAssetMaintWorkEffortName"/> - <set from-field="workEffortName" field="maintWorkEffortMap.workEffortName"/> - <set value="TASK" field="maintWorkEffortMap.workEffortTypeId"/> - <set value="WEPT_MAINTENANCE" field="maintWorkEffortMap.workEffortPurposeTypeId"/> - <set value="CAL_TENTATIVE" field="maintWorkEffortMap.currentStatusId"/> - <set from-field="userLogin.partyId" field="maintWorkEffortMap.quickAssignPartyId"/> - <set from-field="newEntity.fixedAssetId" field="maintWorkEffortMap.fixedAssetId"/> - <get-related-one to-value-field="productMaintType" relation-name="ProductMaintType" value-field="newEntity"/> - <set field="maintWorkEffortMap.description" from-field="productMaintType.description"/> - <!-- Optional dates supplied by Fixed Asset Calendar --> - <set from-field="parameters.estimatedStartDate" field="maintWorkEffortMap.estimatedStartDate"/> - <set from-field="parameters.estimatedCompletionDate" field="maintWorkEffortMap.estimatedCompletionDate"/> - <call-service service-name="createWorkEffort" in-map-name="maintWorkEffortMap"> - <result-to-field result-name="workEffortId" field="newEntity.scheduleWorkEffortId"/> - </call-service> - </else> - </if-not-empty> - <create-value value-field="newEntity"/> - <check-errors/> - <set field="workEffortId" from-field="newEntity.scheduleWorkEffortId"/> - <call-simple-method method-name="autoAssignFixedAssetPartiesToMaintenance"/> - </simple-method> - <simple-method method-name="updateFixedAssetMaint" short-description="Update an existing FixedAsset Maintenance"> - <entity-one entity-name="FixedAssetMaint" value-field="lookedUpValue"/> - <set field="oldStatusId" from-field="lookedUpValue.statusId"/> - <field-to-result field="oldStatusId"/> - <set-nonpk-fields map="parameters" value-field="lookedUpValue"/> - <if-not-empty field="parameters.productMaintSeqId"> - <entity-one entity-name="FixedAsset" value-field="fixedAsset"/> - <entity-one entity-name="ProductMaint" value-field="productMaint"> - <field-map field-name="productId" from-field="fixedAsset.instanceOfProductId"/> - <field-map field-name="productMaintSeqId" from-field="parameters.productMaintSeqId"/> - </entity-one> - <set field="lookedUpValue.productMaintTypeId" from-field="productMaint.productMaintTypeId"/> - </if-not-empty> - <store-value value-field="lookedUpValue"/> - <check-errors/> - <if> - <condition> - <and> - <if-compare field="lookedUpValue.statusId" value="FAM_COMPLETED" operator="equals"/> - <if-compare-field field="oldStatusId" to-field="lookedUpValue.statusId" operator="not-equals"/> - </and> - </condition> - <then> - <set field="workEffortId" from-field="lookedUpValue.scheduleWorkEffortId"/> - <entity-one entity-name="WorkEffort" value-field="workEffort"/> - <if> - <condition> - <and> - <not><if-empty field="workEffort"/></not> - <if-empty field="workEffort.actualCompletionDate"/> - <if-compare field="workEffort.currentStatusId" value="CAL_COMPLETED" operator="not-equals"/> - </and> - </condition> - <then> - <now-timestamp field="nowTimestamp"/> - <set field="updateWorkEffortCtx.workEffortId" from-field="workEffortId"/> - <set field="updateWorkEffortCtx.currentStatusId" value="CAL_ACCEPTED"/> - <call-service service-name="updateWorkEffort" in-map-name="updateWorkEffortCtx"/> - <check-errors/> - <set field="updateWorkEffortCtx.currentStatusId" value="CAL_COMPLETED"/> - <set field="updateWorkEffortCtx.actualCompletionDate" from-field="nowTimestamp"/> - <call-service service-name="updateWorkEffort" in-map-name="updateWorkEffortCtx"/> - <check-errors/> - <entity-condition entity-name="WorkEffortPartyAssignment" list="wepas" filter-by-date="true"> - <condition-expr field-name="workEffortId" operator="equals" from-field="workEffortId"/> - </entity-condition> - <iterate list="wepas" entry="wepa"> - <set field="wepa.thruDate" from-field="nowTimestamp"/> - <store-value value-field="wepa"/> - <check-errors/> - </iterate> - </then> - </if> - </then> - </if> - </simple-method> - <simple-method method-name="createMaintsFromMeterReading" short-description="Create Fixed Asset Maintenances From A Meter Reading"> - <set field="meterValue" from-field="parameters"/> - <if-not-empty field="meterValue.maintHistSeqId"> - <return/> - </if-not-empty> - <entity-one entity-name="FixedAsset" value-field="fixedAssetValue"/> - <if-empty field="fixedAssetValue.instanceOfProductId"> - <return/> - </if-empty> - <entity-and entity-name="ProductMaint" list="productMaintList"> - <field-map field-name="productId" from-field="fixedAssetValue.instanceOfProductId"/> - <field-map field-name="intervalMeterTypeId" from-field="meterValue.productMeterTypeId"/> - </entity-and> - <iterate list="productMaintList" entry="productMaintValue"> - <set field="repeatCount" from-field="productMaintValue.repeatCount" default-value="0" type="Long"/> - <entity-condition entity-name="FixedAssetMaint" list="maintList"> - <condition-list combine="and"> - <condition-expr field-name="fixedAssetId" operator="equals" from-field="fixedAssetValue.fixedAssetId"/> - <condition-expr field-name="productMaintTypeId" operator="equals" from-field="productMaintValue.productMaintTypeId"/> - <condition-expr field-name="intervalMeterTypeId" operator="equals" from-field="productMaintValue.intervalMeterTypeId"/> - <condition-expr field-name="statusId" operator="not-equals" value="FAM_CANCELLED"/> - </condition-list> - </entity-condition> - <set field="listSize" value="0" type="Long"/> - <if-not-empty field="maintList"> - <set field="listSize" value="${groovy:maintList.size()}" type="Long"/> - </if-not-empty> - <set field="maxIntervalQty" value="0" type="BigDecimal"/> - <iterate list="maintList" entry="maintValue"> - <if-not-empty field="maintValue.intervalQuantity"> - <if-compare-field field="maintValue.intervalQuantity" operator="greater" to-field="maxIntervalQty" type="BigDecimal"> - <set field="maxIntervalQty" from-field="maintValue.intervalQuantity" type="BigDecimal"/> - </if-compare-field> - </if-not-empty> - </iterate> - <set field="nextIntervalQty" value="${groovy:maxIntervalQty.add(productMaintValue.getBigDecimal("intervalQuantity"));}" type="BigDecimal"/> - <if-not-empty field="meterValue.meterValue"> - <if-compare-field field="nextIntervalQty" operator="less-equals" to-field="meterValue.meterValue" type="BigDecimal"> - <set field="maintDue" value="false"/> - <if-compare field="repeatCount" operator="greater" value="0" type="Long"> - <if-compare-field field="listSize" operator="less" to-field="repeatCount" type="Long"> - <set field="maintDue" value="true"/> - </if-compare-field> - <else> - <set field="maintDue" value="true"/> - </else> - </if-compare> - <if-compare field="maintDue" operator="equals" value="true"> - <set-service-fields service-name="createFixedAssetMaint" map="productMaintValue" to-map="createMaintCxt"/> - <set field="createMaintCxt.fixedAssetId" from-field="fixedAssetValue.fixedAssetId"/> - <set field="createMaintCxt.intervalQuantity" from-field="meterValue.meterValue"/> - <set field="createMaintCxt.statusId" value="FAM_CREATED"/> - <call-service service-name="createFixedAssetMaint" in-map-name="createMaintCxt"/> - <check-errors/> - </if-compare> - </if-compare-field> - </if-not-empty> - </iterate> - </simple-method> - <simple-method method-name="createMaintsFromTimeInterval" short-description="Create Fixed Asset Maintenances From A Product Maint Time Interval"> - <now-timestamp field="nowTimestamp"/> - <entity-condition entity-name="FixedAsset" list="fixedAssets"> - <condition-list combine="and"> - <condition-expr field-name="instanceOfProductId" operator="not-equals" from-field="null"/> - <condition-expr field-name="actualEndOfLife" operator="equals" from-field="null"/> - </condition-list> - </entity-condition> - <iterate list="fixedAssets" entry="fixedAsset"> - <entity-condition entity-name="ProductMaint" list="productMaints"> - <condition-list combine="and"> - <condition-expr field-name="productId" from-field="fixedAsset.instanceOfProductId"/> - <condition-expr field-name="intervalUomId" operator="like" value="TF_%"/> - </condition-list> - </entity-condition> - <iterate list="productMaints" entry="productMaint"> - <set field="repeatCount" from-field="productMaint.repeatCount" default-value="0" type="Long"/> - <entity-condition entity-name="FixedAssetMaintWorkEffort" list="maintList"> - <condition-list combine="and"> - <condition-expr field-name="fixedAssetId" operator="equals" from-field="fixedAsset.fixedAssetId"/> - <condition-expr field-name="productMaintTypeId" operator="equals" from-field="productMaint.productMaintTypeId"/> - <condition-expr field-name="intervalUomId" operator="equals" from-field="productMaint.intervalUomId"/> - <condition-expr field-name="statusId" operator="not-equals" value="FAM_CANCELLED"/> - </condition-list> - <order-by field-name="maintHistSeqId"/> - </entity-condition> - <set field="intervalQuantity" from-field="productMaint.intervalQuantity" default-value="0" type="Integer"/> - <if-compare field="productMaint.intervalUomId" operator="equals" value="TF_day"> - <set-calendar field="compareDate" from-field="nowTimestamp" days="-${intervalQuantity}"/> - <else> - <if-compare field="productMaint.intervalUomId" operator="equals" value="TF_mon"> - <set-calendar field="compareDate" from-field="nowTimestamp" months="-${intervalQuantity}"/> - <else> - <if-compare field="productMaint.intervalUomId" operator="equals" value="TF_yr"> - <set-calendar field="compareDate" from-field="nowTimestamp" years="-${intervalQuantity}"/> - </if-compare> - </else> - </if-compare> - </else> - </if-compare> - <if-not-empty field="compareDate"> - <set field="listSize" value="0" type="Long"/> - <if-not-empty field="maintList"> - <set field="listSize" value="${groovy:maintList.size()}" type="Long"/> - </if-not-empty> - <set field="lastSvcLong" value="0" type="Long"/> - <set field="lastSvcDate" from-field="lastSvcLong" type="Timestamp"/> - <iterate list="maintList" entry="maintValue"> - <set field="lastSvcDate" from-field="maintValue.actualCompletionDate" set-if-null="true"/> - </iterate> - <if-not-empty field="lastSvcDate"> - <if-compare-field field="lastSvcDate" operator="less" to-field="compareDate" type="Timestamp"> - <set field="maintDue" value="false"/> - <if-compare field="repeatCount" operator="greater" value="0" type="Long"> - <if-compare-field field="listSize" operator="less" to-field="repeatCount" type="Long"> - <set field="maintDue" value="true"/> - </if-compare-field> - <else> - <set field="maintDue" value="true"/> - </else> - </if-compare> - <if-compare field="maintDue" operator="equals" value="true"> - <set-service-fields service-name="createFixedAssetMaint" map="productMaint" to-map="createMaintCxt"/> - <set field="createMaintCxt.fixedAssetId" from-field="fixedAsset.fixedAssetId"/> - <set field="createMaintCxt.statusId" value="FAM_CREATED"/> - <call-service service-name="createFixedAssetMaint" in-map-name="createMaintCxt"/> - <check-errors/> - </if-compare> - </if-compare-field> - </if-not-empty> - </if-not-empty> - </iterate> - </iterate> - </simple-method> - - <!-- create/update/delete FixedAssetMaintOrder --> - <simple-method method-name="createFixedAssetMaintOrder" short-description="Create a FixedAsset Maintenance Order"> - <!-- Check, should exist orderId and orderItemId --> - <entity-one entity-name="OrderHeader" value-field="lookedUpValue"/> - <if-empty field="lookedUpValue"> - <set field="orderId" from-field="parameters.orderId"/> - <add-error> - <fail-property resource="AccountingUiLabels" property="AccountingOrderWithIdNotFound"/> - </add-error> - </if-empty> - <check-errors/> - - <!-- Check if user has not passed in orderItemSeqId then get list of OrderItems from database and default to first item --> - <if-empty field="parameters.orderItemSeqId"> - <entity-and entity-name="OrderItem" list="orderItems"> - <field-map field-name="orderId" from-field="parameters.orderId"/> - </entity-and> - <if-not-empty field="orderItems"> - <set field="orderItem" from-field="orderItems[0]"/> - <if-not-empty field="orderItem"> - <set field="parameters.orderItemSeqId" from-field="orderItem.orderItemSeqId"/> - </if-not-empty> - </if-not-empty> - - <else> - <!-- Check, should exist orderId and orderItemId --> - <entity-one entity-name="OrderItem" value-field="lookedUpValue"/> - <if-empty field="lookedUpValue"> - <set field="orderItemSeqId" from-field="parameters.orderItemSeqId"/> - <add-error> - <fail-property resource="AccountingUiLabels" property="AccountingOrderItemWithIdNotFound"/> - </add-error> - </if-empty> - </else> - </if-empty> - <check-errors/> - - <make-value entity-name="FixedAssetMaintOrder" value-field="newEntity"/> - <set-pk-fields map="parameters" value-field="newEntity"/> - <set-nonpk-fields map="parameters" value-field="newEntity"/> - <create-value value-field="newEntity"/> - </simple-method> - - <simple-method method-name="autoAssignFixedAssetPartiesToMaintenance" login-required="true" - short-description="Auto-assign Fixed Asset Parties to a Fixed Asset Maintenance"> - <if-empty field="maintHistSeqId"> - <set field="maintHistSeqId" from-field="parameters.maintHistSeqId"/> - </if-empty> - <if-empty field="fixedAssetId"> - <set field="fixedAssetId" from-field="parameters.fixedAssetId"/> - </if-empty> - <entity-one entity-name="FixedAssetMaint" value-field="maintValue"/> - <if-empty field="workEffortId"> - <set field="workEffortId" from-field="maintValue.scheduleWorkEffortId"/> - </if-empty> - <entity-and entity-name="PartyFixedAssetAssignAndRole" list="assignedParties" filter-by-date="true"> - <field-map field-name="fixedAssetId" from-field="fixedAssetId"/> - <field-map field-name="parentTypeId" value="FAM_ASSIGNEE"/> - </entity-and> - <iterate list="assignedParties" entry="assignedParty"> - <set field="assignPartyCtx.partyId" from-field="assignedParty.partyId"/> - <set field="assignPartyCtx.roleTypeId" from-field="assignedParty.roleTypeId"/> - <set field="assignPartyCtx.workEffortId" from-field="workEffortId"/> - <set field="assignPartyCtx.statusId" value="PRTYASGN_ASSIGNED"/> - <call-service service-name="assignPartyToWorkEffort" in-map-name="assignPartyCtx"/> - <check-errors/> - </iterate> - </simple-method> - - <!-- ============== Fixed Asset Depreciation methods ============== --> - <simple-method method-name="straightLineDepreciation" short-description="Calculate straight line depreciation to Fixed Asset[ (PC-SV)/expLife ]"> - <set field="expEndOfLifeYear" from-field="parameters.expEndOfLifeYear" type="Integer"/> - <set field="assetAcquiredYear" from-field="parameters.assetAcquiredYear" type="Integer"/> - <set field="purchaseCost" from-field="parameters.purchaseCost"/> - <set field="salvageValue" from-field="parameters.salvageValue"/> - <call-object-method obj-field="parameters.usageYears" method-name="intValue" ret-field="intUsageYears"/> - - <!-- Past depreciation based on standard formula --> - <set field="depreciationTotal" value="0.0" type="BigDecimal"/> - <if> - <condition> - <and> - <if-compare field="intUsageYears" operator="greater" value="0.0" type="BigDecimal"/> - <not><if-empty field="parameters.fixedAssetId"/></not> - </and> - </condition> - <then> - <set field="depreciation" value="0.0" type="BigDecimal"/> - <!--FORMULA : depreciation = (purchaseCost - salvageValue) / (expectedEndOfLife - dateAcquired) --> - <calculate field="numberOfYears"> - <calcop operator="subtract"> - <calcop operator="get" field="expEndOfLifeYear"/> - <calcop operator="get" field="assetAcquiredYear"/> - </calcop> - </calculate> - <if-compare field="numberOfYears" operator="greater" value="0.0" type="BigDecimal"> - <calculate field="depreciation" decimal-scale="2"> - <calcop operator="divide"> - <calcop operator="subtract"> - <calcop operator="get" field="purchaseCost"/> - <calcop operator="get" field="salvageValue"/> - </calcop> - <calcop operator="get" field="numberOfYears"/> - </calcop> - </calculate> - </if-compare> - <set field="depreciationYear" from-field="assetAcquiredYear" type="BigDecimal"/> - <if-compare-field field="numberOfYears" operator="less" to-field="intUsageYears" type="BigDecimal"> - <set field="intUsageYears" from-field="numberOfYears" type="BigDecimal"/> - </if-compare-field> - <loop count="${intUsageYears}"> - <calculate field="purchaseCost"> - <calcop operator="subtract"> - <calcop operator="get" field="purchaseCost"/> - <calcop operator="get" field="depreciation"/> - </calcop> - </calculate> - <calculate field="depreciationTotal"> - <calcop operator="add"> - <calcop operator="get" field="depreciationTotal"/> - <calcop operator="get" field="depreciation"/> - </calcop> - </calculate> - <field-to-list list="assetDepreciationTillDate" field="depreciation"/> - <field-to-list list="assetNBVAfterDepreciation" field="purchaseCost"/> - <clear-field field="assetDepreciationInfo"/> - <set field="assetDepreciationInfo.year" from-field="depreciationYear"/> - <set field="assetDepreciationInfo.depreciation" from-field="depreciation"/> - <set field="assetDepreciationInfo.depreciationTotal" from-field="depreciationTotal"/> - <set field="assetDepreciationInfo.nbv" from-field="purchaseCost"/> - <field-to-list list="assetDepreciationInfoList" field="assetDepreciationInfo"/> - <calculate field="depreciationYear"> - <calcop operator="add"> - <calcop operator="get" field="depreciationYear"/> - <number value="1"/> - </calcop> - </calculate> - </loop> - </then> - </if> - <if-empty field="assetDepreciationTillDate"> - <set field="depreciation" value="0.0" type="BigDecimal"/> - <field-to-list list="assetDepreciationTillDate" field="depreciation"/> - <field-to-list list="assetNBVAfterDepreciation" field="purchaseCost"/> - <set field="assetDepreciationInfo.year" from-field="assetAcquiredYear"/> - <set field="assetDepreciationInfo.depreciation" from-field="depreciation"/> - <set field="assetDepreciationInfo.depreciationTotal" from-field="depreciationTotal"/> - <set field="assetDepreciationInfo.nbv" from-field="purchaseCost"/> - <field-to-list list="assetDepreciationInfoList" field="assetDepreciationInfo"/> - </if-empty> - <log level="info" message="Using straight line formula depreciation calculated for fixedAsset (${parameters.fixedAssetId}) is ${depreciation}"/> - <field-to-result field="assetDepreciationTillDate"/> - <field-to-result field="assetNBVAfterDepreciation"/> - <field-to-result field="assetDepreciationInfoList"/> - - <!-- Next depreciation based on actual depreciation history --> - <set field="nextDepreciationAmount" value="0.0" type="BigDecimal"/> - <if> - <condition> - <not><if-empty field="parameters.fixedAssetId"/></not> - </condition> - <then> - <entity-one entity-name="FixedAsset" value-field="fixedAsset"/> - <!--FORMULA : depreciation = (purchaseCost - salvageValue - pastDepreciations) / remainingYears --> - <calculate field="remainingYears"> - <calcop operator="subtract"> - <calcop operator="get" field="expEndOfLifeYear"/> - <calcop operator="get" field="assetAcquiredYear"/> - <calcop operator="get" field="intUsageYears"/> - </calcop> - </calculate> - <if-compare field="remainingYears" operator="greater" value="0.0" type="BigDecimal"> - <calculate field="nextDepreciationAmount" decimal-scale="2"> - <calcop operator="divide"> - <calcop operator="subtract"> - <calcop operator="get" field="fixedAsset.purchaseCost"/> - <calcop operator="get" field="salvageValue"/> - <calcop operator="get" field="fixedAsset.depreciation"/> - </calcop> - <calcop operator="get" field="remainingYears"/> - </calcop> - </calculate> - </if-compare> - </then> - </if> - <field-to-result field="nextDepreciationAmount"/> - <calculate field="plannedPastDepreciationTotal"> - <calcop operator="subtract"> - <calcop operator="get" field="depreciationTotal"/> - <calcop operator="get" field="fixedAsset.depreciation"/> - </calcop> - </calculate> - <field-to-result field="plannedPastDepreciationTotal"/> - </simple-method> - - <simple-method method-name="doubleDecliningBalanceDepreciation" short-description="Calculate double declining balance depreciation to Fixed Asset"> - <set field="expEndOfLifeYear" from-field="parameters.expEndOfLifeYear" type="Integer"/> - <set field="assetAcquiredYear" from-field="parameters.assetAcquiredYear" type="Integer"/> - <set field="purchaseCost" from-field="parameters.purchaseCost"/> - <set field="salvageValue" from-field="parameters.salvageValue"/> - <call-object-method obj-field="parameters.usageYears" method-name="intValue" ret-field="intUsageYears"/> - <!-- Next depreciation based on actual depreciation history --> - <set field="nextDepreciationAmount" value="0.0" type="BigDecimal"/> - <if> - <condition> - <not><if-empty field="parameters.fixedAssetId"/></not> - </condition> - <then> - <entity-one entity-name="FixedAsset" value-field="fixedAsset"/> - <!--FORMULA : depreciation = 2 * (purchaseCost - salvageValue - pastDepreciations) / remainingYears --> - <calculate field="remainingYears"> - <calcop operator="subtract"> - <calcop operator="get" field="expEndOfLifeYear"/> - <calcop operator="get" field="assetAcquiredYear"/> - <calcop operator="get" field="intUsageYears"/> - </calcop> - </calculate> - <if-compare field="remainingYears" operator="greater" value="0.0" type="BigDecimal"> - <calculate field="nextDepreciationAmount" decimal-scale="2"> - <calcop operator="multiply"> - <calcop operator="divide"> - <calcop operator="subtract"> - <calcop operator="get" field="fixedAsset.purchaseCost"/> - <calcop operator="get" field="salvageValue"/> - <calcop operator="get" field="fixedAsset.depreciation"/> - </calcop> - <calcop operator="get" field="remainingYears"/> - </calcop> - <number value="2"/> - </calcop> - </calculate> - </if-compare> - </then> - </if> - <field-to-result field="nextDepreciationAmount"/> - - <!-- Past depreciation based on standard formula --> - <set field="depreciationTotal" value="0.0" type="BigDecimal"/> - <if> - <condition> - <and> - <if-compare field="intUsageYears" operator="greater" value="0.0" type="BigDecimal"/> - <not><if-empty field="parameters.fixedAssetId"/></not> - </and> - </condition> - <then> - <set field="depreciationYear" from-field="assetAcquiredYear" type="BigDecimal"/> - <loop count="${intUsageYears}"> - <set field="depreciation" value="0.0" type="BigDecimal"/> - <!--FORMULA : depreciation = (NBV - salvageValue) * 2 / (expectedEndOfLife - dateAcquired) --> - <calculate field="numberOfYears"> - <calcop operator="subtract"> - <calcop operator="get" field="expEndOfLifeYear"/> - <calcop operator="get" field="assetAcquiredYear"/> - </calcop> - </calculate> - <if-compare field="numberOfYears" operator="greater" value="0.0" type="BigDecimal"> - <calculate field="depreciation" decimal-scale="2"> - <calcop operator="multiply"> - <calcop operator="divide"> - <calcop operator="subtract"> - <calcop operator="get" field="purchaseCost"/> - <calcop operator="get" field="salvageValue"/> - </calcop> - <calcop operator="get" field="numberOfYears"/> - </calcop> - <number value="2"/> - </calcop> - </calculate> - </if-compare> - <calculate field="assetAcquiredYear"> - <calcop operator="add"> - <calcop operator="get" field="assetAcquiredYear"/> - <number value="1"/> - </calcop> - </calculate> - <calculate field="purchaseCost"> - <calcop operator="subtract"> - <calcop operator="get" field="purchaseCost"/> - <calcop operator="get" field="depreciation"/> - </calcop> - </calculate> - <calculate field="depreciationTotal"> - <calcop operator="add"> - <calcop operator="get" field="depreciationTotal"/> - <calcop operator="get" field="depreciation"/> - </calcop> - </calculate> - <field-to-list list="assetDepreciationTillDate" field="depreciation"/> - <field-to-list list="assetNBVAfterDepreciation" field="purchaseCost"/> - <clear-field field="assetDepreciationInfo"/> - <set field="assetDepreciationInfo.year" from-field="depreciationYear"/> - <set field="assetDepreciationInfo.depreciation" from-field="depreciation"/> - <set field="assetDepreciationInfo.depreciationTotal" from-field="depreciationTotal"/> - <set field="assetDepreciationInfo.nbv" from-field="purchaseCost"/> - <field-to-list list="assetDepreciationInfoList" field="assetDepreciationInfo"/> - <calculate field="depreciationYear"> - <calcop operator="add"> - <calcop operator="get" field="depreciationYear"/> - <number value="1"/> - </calcop> - </calculate> - </loop> - </then> - </if> - <if-empty field="assetDepreciationTillDate"> - <set field="depreciation" value="0.0" type="BigDecimal"/> - <field-to-list list="assetDepreciationTillDate" field="depreciation"/> - <field-to-list list="assetNBVAfterDepreciation" field="purchaseCost"/> - <set field="assetDepreciationInfo.year" from-field="assetAcquiredYear"/> - <set field="assetDepreciationInfo.depreciation" from-field="depreciation"/> - <set field="assetDepreciationInfo.depreciationTotal" from-field="depreciationTotal"/> - <set field="assetDepreciationInfo.nbv" from-field="purchaseCost"/> - <field-to-list list="assetDepreciationInfoList" field="assetDepreciationInfo"/> - </if-empty> - <log level="info" message="Using double decline formula depreciation calculated for fixedAsset (${parameters.fixedAssetId}) is ${assetDepreciationTillDate}"/> - <field-to-result field="assetDepreciationTillDate"/> - <field-to-result field="assetNBVAfterDepreciation"/> - <field-to-result field="assetDepreciationInfoList"/> - <field-to-result field="depreciationTotal" result-name="plannedPastDepreciationTotal"/> - </simple-method> - - <simple-method method-name="calculateFixedAssetDepreciation" short-description="Service to calculate the yearly depreciation from dateAcquired year to current financial year"> - <entity-one entity-name="FixedAsset" value-field="fixedAsset"/> - <if-empty field="fixedAsset"> - <add-error> - <fail-property resource="ManufacturingUiLabels" property="ManufacturingFixedAssetNotExist"/> - </add-error> - <check-errors/> - </if-empty> - <set field="startIndex" value="0" type="Integer"/> - <set field="endIndex" value="4" type="Integer"/> - - <!-- Extract asset end of life year from field expectedEndOfLife --> - <if-not-empty field="fixedAsset.expectedEndOfLife"> - <set field="expectedEndOfLife" from-field="fixedAsset.expectedEndOfLife"/> - <to-string field="expectedEndOfLife"/> - <call-object-method method-name="substring" obj-field="expectedEndOfLife" ret-field="expEndOfLifeYear"> - <field field="startIndex" type="int"/> - <field field="endIndex" type="int"/> - </call-object-method> - <else> - <property-to-field resource="AccountingUiLabels" property="AccountingExpEndOfLifeIsEmpty" field="successMessageList[]"/> - <return/> - </else> - </if-not-empty> - - <!-- Extract asset acquired year from field dateAcquired --> - <if-not-empty field="fixedAsset.dateAcquired"> - <set field="dateAcquired" from-field="fixedAsset.dateAcquired"/> - <to-string field="dateAcquired"/> - <call-object-method method-name="substring" obj-field="dateAcquired" ret-field="assetAcquiredYear"> - <field field="startIndex" type="int"/> - <field field="endIndex" type="int"/> - </call-object-method> - <else> - <property-to-field resource="AccountingUiLabels" property="AccountingDateAcquiredIsEmpty" field="successMessageList[]"/> - <return/> - </else> - </if-not-empty> - - <!-- if any asset's salvage value is empty then set it by 0 --> - <if-empty field="fixedAsset.salvageValue"> - <set field="salvageValue" value="0.0" type="BigDecimal"/> - <else> - <set field="salvageValue" from-field="fixedAsset.salvageValue"/> - </else> - </if-empty> - - <!-- Get running year --> - <now-timestamp field="nowTimestamp"/> - <to-string field="nowTimestamp"/> - <call-object-method method-name="substring" obj-field="nowTimestamp" ret-field="currentYear"> - <field field="startIndex" type="int"/> - <field field="endIndex" type="int"/> - </call-object-method> - - <!-- Calculate asset's total run in years --> - <calculate field="usageYears" type="Integer"> - <calcop operator="subtract"> - <calcop operator="get" field="currentYear"/> - <calcop operator="get" field="assetAcquiredYear"/> - </calcop> - </calculate> - - <entity-and entity-name="FixedAssetDepMethod" list="fixedAssetDepMethods" filter-by-date="true"> - <field-map field-name="fixedAssetId" from-field="parameters.fixedAssetId"/> - </entity-and> - <if-not-empty field="fixedAssetDepMethods"> - <first-from-list list="fixedAssetDepMethods" entry="fixedAssetDepMethod"/> - <get-related-one relation-name="CustomMethod" value-field="fixedAssetDepMethod" to-value-field="customMethod"/> - <log level="info" message="Depreciation service name for the FixedAsset ${parameters.fixedAssetId} is ${customMethod.customMethodName}"/> - - <set field="serviceInMap.fixedAssetId" from-field="parameters.fixedAssetId"/> - <set field="serviceInMap.expEndOfLifeYear" from-field="expEndOfLifeYear" type="Integer"/> - <set field="serviceInMap.assetAcquiredYear" from-field="assetAcquiredYear" type="Integer"/> - <set field="serviceInMap.purchaseCost" from-field="fixedAsset.purchaseCost"/> - <set field="serviceInMap.salvageValue" from-field="salvageValue"/> - <set field="serviceInMap.usageYears" from-field="usageYears" type="Integer"/> - <call-service service-name="${customMethod.customMethodName}" in-map-name="serviceInMap"> - <result-to-field result-name="assetDepreciationTillDate"/> - <result-to-field result-name="assetNBVAfterDepreciation"/> - <result-to-field result-name="assetDepreciationInfoList"/> - <result-to-field result-name="nextDepreciationAmount"/> - <result-to-field result-name="plannedPastDepreciationTotal"/> - </call-service> - <log level="info" message="Asset's depreciation calculated till date are ${assetDepreciationTillDate}"/> - <log level="info" message="Asset's Net Book Values (NBV) from acquired date after deducting depreciation are ${assetNBVAfterDepreciation}"/> - <field-to-result field="assetDepreciationTillDate"/> - <field-to-result field="assetNBVAfterDepreciation"/> - <field-to-result field="assetDepreciationInfoList"/> - <field-to-result field="nextDepreciationAmount"/> - <field-to-result field="plannedPastDepreciationTotal"/> - <else> - <property-to-field resource="AccountingUiLabels" property="AccountingFixedAssetDepreciationMethodNotFound" field="successMessageList[]"/> - <return/> - </else> - </if-not-empty> - </simple-method> - - <simple-method method-name="checkUpdateFixedAssetDepreciation" login-required="true" - short-description="If the accounting transaction is a depreciation transaction for a fixed asset, update the depreciation amount in the FixedAsset entity."> - <entity-one entity-name="AcctgTrans" value-field="acctgTrans"/> - <if> - <condition> - <and> - <if-compare field="acctgTrans.acctgTransTypeId" operator="equals" value="DEPRECIATION"/> - <not><if-empty field="acctgTrans.fixedAssetId"/></not> - </and> - </condition> - <then> - <get-related-one relation-name="FixedAsset" value-field="acctgTrans" to-value-field="fixedAsset"/> - <set field="creditCondition.debitCreditFlag" value="C"/> - <get-related relation-name="AcctgTransEntry" value-field="acctgTrans" list="creditTransactions" map="creditCondition"/> - <set field="depreciation" value="0.0" type="BigDecimal"/> - <iterate list="creditTransactions" entry="creditTransaction"> - <if-empty field="fixedAsset.purchaseCostUomId"> - <log level="warning" message="Found empty purchaseCostUomId for FixedAsset [${fixedAsset.fixedAssetId}]: setting it to ${creditTransaction.currencyUomId} to match the one used in the gl."/> - <set field="fixedAsset.purchaseCostUomId" from-field="creditTransaction.currencyUomId"/> - <store-value value-field="fixedAsset"/> - </if-empty> - <if-compare-field field="fixedAsset.purchaseCostUomId" operator="equals" to-field="creditTransaction.currencyUomId"> - <calculate field="depreciation"> - <calcop operator="add"> - <calcop operator="get" field="depreciation"/> - <calcop operator="get" field="creditTransaction.amount"/> - </calcop> - </calculate> - <else> - <if-compare-field field="fixedAsset.purchaseCostUomId" operator="equals" to-field="creditTransaction.origCurrencyUomId"> - <calculate field="depreciation"> - <calcop operator="add"> - <calcop operator="get" field="depreciation"/> - <calcop operator="get" field="creditTransaction.origAmount"/> - </calcop> - </calculate> - <else> - <log level="warning" message="Found an accounting transaction for depreciation of FixedAsset [${fixedAsset.fixedAssetId}] with a cuurency that doesn't match the currency used in the fixed asset: the depreciation total in the fixed asset will not be updated."/> - <return/> - </else> - </if-compare-field> - </else> - </if-compare-field> - </iterate> - <set field="depreciationTotal" from-field="fixedAsset.depreciation" default-value="0.0" type="BigDecimal"/> - <calculate field="depreciationTotal"> - <calcop operator="add"> - <calcop operator="get" field="depreciation"/> - <calcop operator="get" field="depreciationTotal"/> - </calcop> - </calculate> - <set field="fixedAsset.depreciation" from-field="depreciationTotal"/> - <store-value value-field="fixedAsset"/> - </then> - </if> - </simple-method> - -</simple-methods> diff --git a/applications/accounting/servicedef/services_fixedasset.xml b/applications/accounting/servicedef/services_fixedasset.xml index 40dbd5f8ec..a577499fc9 100644 --- a/applications/accounting/servicedef/services_fixedasset.xml +++ b/applications/accounting/servicedef/services_fixedasset.xml @@ -120,8 +120,8 @@ under the License. <auto-attributes include="pk" mode="IN" optional="false"/> </service> <!-- FixedAsset Maintenance Create/Update/Delete--> - <service name="createFixedAssetMaint" default-entity-name="FixedAssetMaint" engine="simple" - location="component://accounting/minilang/fixedasset/FixedAssetServices.xml" invoke="createFixedAssetMaint" auth="true"> + <service name="createFixedAssetMaint" default-entity-name="FixedAssetMaint" engine="groovy" + location="component://accounting/src/main/groovy/org/apache/ofbiz/accounting/fixedasset/FixedAssetServices.groovy" invoke="createFixedAssetMaint" auth="true"> <description>Create a Fixed Asset Maintenance</description> <permission-service service-name="fixedAssetPermissionCheck" main-action="CREATE"/> <auto-attributes include="pk" mode="IN" optional="false"/> @@ -131,8 +131,8 @@ under the License. <attribute name="maintTemplateWorkEffortId" mode="IN" type="String" optional="true"/> <override name="maintHistSeqId" mode="OUT"/> <!-- make this OUT rather than IN, we will automatically generate the next sub-sequence ID --> </service> - <service name="updateFixedAssetMaint" default-entity-name="FixedAssetMaint" engine="simple" - location="component://accounting/minilang/fixedasset/FixedAssetServices.xml" invoke="updateFixedAssetMaint" auth="true"> + <service name="updateFixedAssetMaint" default-entity-name="FixedAssetMaint" engine="groovy" + location="component://accounting/src/main/groovy/org/apache/ofbiz/accounting/fixedasset/FixedAssetServices.groovy" invoke="updateFixedAssetMaint" auth="true"> <description>Update a Fixed Asset Maintenance</description> <permission-service service-name="fixedAssetPermissionCheck" main-action="UPDATE"/> <auto-attributes include="pk" mode="IN" optional="false"/> @@ -144,13 +144,19 @@ under the License. <permission-service service-name="fixedAssetPermissionCheck" main-action="DELETE"/> <auto-attributes include="pk" mode="IN" optional="false"/> </service> - <service name="createMaintsFromTimeInterval" engine="simple" use-transaction="false" - location="component://accounting/minilang/fixedasset/FixedAssetServices.xml" invoke="createMaintsFromTimeInterval" auth="true"> + <service name="createMaintsFromTimeInterval" engine="groovy" + location="component://accounting/src/main/groovy/org/apache/ofbiz/accounting/fixedasset/FixedAssetServices.groovy" + use-transaction="false" invoke="createMaintsFromTimeInterval" auth="true"> <description>Create Fixed Asset Maintenances from ProductMaint time intervals. Currently works with day, month, and year interval types. This service is intended to be run as a regularly scheduled job.</description> <permission-service service-name="fixedAssetPermissionCheck" main-action="CREATE"/> </service> + <service name="autoAssignFixedAssetPartiesToMaintenance" engine="groovy" + location="component://accounting/src/main/groovy/org/apache/ofbiz/accounting/fixedasset/FixedAssetServices.groovy" invoke="autoAssignFixedAssetPartiesToMaintenance" auth="true"> + <attribute name="fixedAssetId" type="String" mode="IN"/> + <attribute name="workEffortId" type="String" mode="IN"/> + </service> <!-- FixedAsset Maintenance Meter Create/Update/Delete--> <service name="createFixedAssetMeter" default-entity-name="FixedAssetMeter" engine="entity-auto" invoke="create" auth="true"> <description>Create a Fixed asset Meter</description> @@ -164,8 +170,8 @@ under the License. <auto-attributes include="pk" mode="IN" optional="false"/> <auto-attributes include="nonpk" mode="IN" optional="true"/> </service> - <service name="createMaintsFromMeterReading" default-entity-name="FixedAssetMeter" engine="simple" - location="component://accounting/minilang/fixedasset/FixedAssetServices.xml" invoke="createMaintsFromMeterReading" auth="true"> + <service name="createMaintsFromMeterReading" default-entity-name="FixedAssetMeter" engine="groovy" + location="component://accounting/src/main/groovy/org/apache/ofbiz/accounting/fixedasset/FixedAssetServices.groovy" invoke="createMaintsFromMeterReading" auth="true"> <description>Create Maints From Meter Reading</description> <auto-attributes include="pk" mode="IN" optional="false"/> <auto-attributes include="nonpk" mode="IN" optional="true"/> @@ -176,8 +182,8 @@ under the License. <auto-attributes include="pk" mode="IN" optional="false"/> </service> <!-- FixedAsset Maintenance Order Create/Update/Delete--> - <service name="createFixedAssetMaintOrder" default-entity-name="FixedAssetMaintOrder" engine="simple" - location="component://accounting/minilang/fixedasset/FixedAssetServices.xml" invoke="createFixedAssetMaintOrder" auth="true"> + <service name="createFixedAssetMaintOrder" default-entity-name="FixedAssetMaintOrder" engine="groovy" + location="component://accounting/src/main/groovy/org/apache/ofbiz/accounting/fixedasset/FixedAssetServices.groovy" invoke="createFixedAssetMaintOrder" auth="true"> <description>Create a Fixed Asset Maintenance Order</description> <permission-service service-name="fixedAssetPermissionCheck" main-action="CREATE"/> <attribute name="fixedAssetId" type="String" mode="IN" optional="false"/> @@ -230,8 +236,8 @@ under the License. <permission-service service-name="fixedAssetPermissionCheck" main-action="DELETE"/> <auto-attributes include="pk" mode="IN" optional="false"/> </service> - <service name="checkUpdateFixedAssetDepreciation" default-entity-name="AcctgTrans" engine="simple" - location="component://accounting/minilang/fixedasset/FixedAssetServices.xml" invoke="checkUpdateFixedAssetDepreciation" auth="true"> + <service name="checkUpdateFixedAssetDepreciation" default-entity-name="AcctgTrans" engine="groovy" auth="true" + location="component://accounting/src/main/groovy/org/apache/ofbiz/accounting/fixedasset/FixedAssetServices.groovy" invoke="checkUpdateFixedAssetDepreciation"> <description>If the accounting transaction is a depreciation transaction for a fixed asset, update the depreciation amount in the FixedAsset entity.</description> <permission-service service-name="fixedAssetPermissionCheck" main-action="UPDATE"/> <auto-attributes include="pk" mode="IN" optional="false"/> @@ -249,20 +255,20 @@ under the License. <attribute name="nextDepreciationAmount" type="BigDecimal" mode="OUT" optional="false"/> <attribute name="plannedPastDepreciationTotal" type="BigDecimal" mode="OUT" optional="false"/> </service> - <service name="straightLineDepreciation" engine="simple" default-entity-name="FixedAsset" - location="component://accounting/minilang/fixedasset/FixedAssetServices.xml" invoke="straightLineDepreciation" auth="true"> + <service name="straightLineDepreciation" default-entity-name="FixedAsset" engine="groovy" auth="true" + location="component://accounting/src/main/groovy/org/apache/ofbiz/accounting/fixedasset/FixedAssetServices.groovy" invoke="straightLineDepreciation"> <description>Straight line depreciation service to Fixed Asset</description> <implements service="fixedAssetDepCalcInterface"/> <auto-attributes include="pk" mode="IN" optional="false"/> </service> - <service name="doubleDecliningBalanceDepreciation" engine="simple" default-entity-name="FixedAsset" - location="component://accounting/minilang/fixedasset/FixedAssetServices.xml" invoke="doubleDecliningBalanceDepreciation" auth="true"> + <service name="doubleDecliningBalanceDepreciation" default-entity-name="FixedAsset" engine="groovy" auth="true" + location="component://accounting/src/main/groovy/org/apache/ofbiz/accounting/fixedasset/FixedAssetServices.groovy" invoke="doubleDecliningBalanceDepreciation"> <description>Double declining balance depreciation service to Fixed Asset</description> <implements service="fixedAssetDepCalcInterface"/> <auto-attributes include="pk" mode="IN" optional="false"/> </service> - <service name="calculateFixedAssetDepreciation" engine="simple" default-entity-name="FixedAssetDepMethod" - location="component://accounting/minilang/fixedasset/FixedAssetServices.xml" invoke="calculateFixedAssetDepreciation" auth="true"> + <service name="calculateFixedAssetDepreciation" default-entity-name="FixedAssetDepMethod" engine="groovy" auth="true" + location="component://accounting/src/main/groovy/org/apache/ofbiz/accounting/fixedasset/FixedAssetServices.groovy" invoke="calculateFixedAssetDepreciation"> <description>Select the depreciation method according to the entry in FixedAssetDepMethod</description> <attribute name="fixedAssetId" type="String" mode="IN"/> <attribute name="assetDepreciationTillDate" type="List" mode="OUT" optional="true"/> diff --git a/applications/accounting/src/main/groovy/org/apache/ofbiz/accounting/fixedasset/FixedAssetServices.groovy b/applications/accounting/src/main/groovy/org/apache/ofbiz/accounting/fixedasset/FixedAssetServices.groovy new file mode 100644 index 0000000000..f85e67e1ae --- /dev/null +++ b/applications/accounting/src/main/groovy/org/apache/ofbiz/accounting/fixedasset/FixedAssetServices.groovy @@ -0,0 +1,464 @@ +import org.apache.ofbiz.base.util.UtilDateTime +import org.apache.ofbiz.entity.GenericValue +import org.apache.ofbiz.entity.condition.EntityCondition +import org.apache.ofbiz.entity.condition.EntityConditionBuilder + +import java.math.RoundingMode +import java.sql.Timestamp + +/* + * 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. + */ + +/** + * create a FixedAssetMaint + */ +Map createFixedAssetMaint() { + GenericValue newEntity = makeValue('FixedAssetMaint', parameters) + String maintTemplateWorkEffortId + newEntity.maintHistSeqId = delegator.getNextSeqId('FixedAssetMaint') + GenericValue fixedAsset = from('FixedAsset').where(parameters).queryOne() + if (parameters.productMaintSeqId) { + GenericValue productMaint = from('ProductMaint') + .where(productId: fixedAsset.instanceOfProductId, + productMaintSeqId: parameters.productMaintSeqId) + .queryOne() + newEntity.productMaintTypeId = productMaint.productMaintTypeId + maintTemplateWorkEffortId = productMaint.maintTemplateWorkEffortId ?: parameters.maintTemplateWorkEffortId + } + if (maintTemplateWorkEffortId) { + String workEffortId = delegator.getNextSeqId('WorkEffort') + run service: 'duplicateWorkEffort', with: + [oldWorkEffortId: maintTemplateWorkEffortId, + workEffortId: workEffortId, + duplicateWorkEffortAssocs: 'Y', + duplicateWorkEffortNotes: 'Y', + duplicateWorkEffortContents: 'Y', + duplicateWorkEffortAssignmentRates: 'Y'] + newEntity.scheduleWorkEffortId = workEffortId + } else { + // Create the WorkEffort and Maintenance WorkEffort entity + Map maintWorkEffortMap = [workEffortTypeId: 'TASK', + workEffortName: label('AccountingUiLabels', 'AccountingFixedAssetMaintWorkEffortName'), + workEffortPurposeTypeId: 'WEPT_MAINTENANCE', + currentStatusId: 'CAL_TENTATIVE', + quickAssignPartyId: userLogin.partyId, + fixedAssetId: fixedAsset.fixedAssetId, + estimatedStartDate: parameters.estimatedStartDate, + estimatedCompletionDate: parameters.estimatedCompletionDate] + maintWorkEffortMap.description = delegator.getRelatedOne('ProductMaintType', newEntity, true)?.description + Map serviceResult = run service: 'createWorkEffort', with: maintWorkEffortMap + newEntity.scheduleWorkEffortId = serviceResult.workEffortId + } + newEntity.create() + run service: 'autoAssignFixedAssetPartiesToMaintenance', with: [fixedAssetId: fixedAsset.fixedAssetId, + workEffortId: newEntity.scheduleWorkEffortId] + return success([maintHistSeqId: newEntity.maintHistSeqId]) +} + +/** + * update an existing FixedAsset Maintenance + */ +Map updateFixedAssetMaint() { + GenericValue lookedUpValue = from('FixedAssetMaint').where(parameters).queryOne() + String oldStatusId = lookedUpValue.statusId + lookedUpValue.setNonPKFields(parameters) + GenericValue fixedAsset = from('FixedAsset').where(parameters).cache().queryOne() + if (parameters.productMaintSeqId) { + GenericValue productMaint = from('ProductMaint') + .where(productId: fixedAsset.instanceOfProductId, + productMaintSeqId: parameters.productMaintSeqId) + .queryOne() + lookedUpValue.productMaintTypeId = productMaint.productMaintTypeId + } + lookedUpValue.store() + if (lookedUpValue.statusId == 'FAM_COMPLETED' + && oldStatusId != lookedUpValue.statusId) { + GenericValue workEffort = from('WorkEffort') + .where(workEffortId: lookedUpValue.scheduleWorkEffortId) + .cache() + .queryOne() + if (workEffort && !workEffort.actualCompletionDate && workEffort.currentStatusId != 'CAL_COMPLETED') { + Timestamp nowTimestamp = UtilDateTime.nowTimestamp() + run service: 'updateWorkEffort', with: [workEffortId: workEffort.workEffortId, + currentStatusId: 'CAL_ACCEPTED'] + run service: 'updateWorkEffort', with: [workEffortId: workEffort.workEffortId, + actualCompletionDate: nowTimestamp, + currentStatusId: 'CAL_COMPLETED'] + delegator.storeByCondition('WorkEffortPartyAssignment', + [thruDate: nowTimestamp], + EntityCondition.makeCondition([ + EntityCondition.makeCondition('workEffortId', workEffort.workEffortId), + EntityCondition.makeConditionDate('fromDate', 'thruDate')])) + } + } + return success() +} + +/** + * Create Fixed Asset Maintenances From A Meter Reading + */ +Map createMaintsFromMeterReading() { + if (parameters.maintHistSeqId) { + return success() + } + GenericValue fixedAsset = from('FixedAsset').where(parameters).cache().queryOne() + if (!fixedAsset.instanceOfProductId) { + return success() + } + from('ProductMaint') + .where(productId: fixedAsset.instanceOfProductId, + intervalMeterTypeId: parameters.productMeterTypeId) + .queryList() + .each {p -> + long repeatCount = p.repeatCount ?: 0l + EntityCondition cond = new EntityConditionBuilder().AND { + EQUALS(fixedAssetId: fixedAsset.fixedAssetId) + EQUALS(intervalMeterTypeId: p.intervalMeterTypeId) + EQUALS(productMaintTypeId: p.productMaintTypeId) + NOT_EQUAL(statusId: 'FAM_CANCELLED') + } + List maintList = from('FixedAssetMaint') + .where(cond) + .queryList() + long listSize = maintList ? maintList.size(): 0l + + BigDecimal maxIntervalQty = maintList ? maintList.stream() + .map { v -> v.intervalQuantity ?: 0 } + .collect() + .max(): 0 + + BigDecimal nextIntervalQty = maxIntervalQty + p.intervalQuantity + if (parameters.meterValue && + (nextIntervalQty > parameters.meterValue || + (repeatCount > 0 && listSize < repeatCount))) { + run service: 'createFixedAssetMaint', with: [* : p.getAllFields(), + fixedAssetId: fixedAsset.fixedAssetId, + intervalQuantity: parameters.meterValue, + statusId: 'FAM_CREATED'] + } + } + return success() +} + +/** + * Create Fixed Asset Maintenances From A Product Maint Time Interval + */ +Map createMaintsFromTimeInterval() { + Timestamp nowTimestamp = UtilDateTime.nowTimestamp() + EntityCondition cond = new EntityConditionBuilder().AND { + NOT_EQUAL(instanceOfProductId: null) + EQUALS(actualEndOfLife: null) + } + Map timeSwitch = [TF_day: Calendar.DAY_OF_MONTH, + TF_mon: Calendar.MONTH, + TF_yr: Calendar.YEAR] + from('FixedAsset') + .where(cond) + .queryList() + .each {f -> + cond = new EntityConditionBuilder().AND { + EQUALS(productId: f.instanceOfProductId) + LIKE(intervalUomId: 'TF_%') + } + from('ProductMaint') + .where(cond) + .queryList() + .each {p -> + if (timeSwitch.containsKey(p.intervalUomId)) { + long repeatCount = p.repeatCount ?: 0 + long intervalQuantity = p.intervalQuantity ?: 0 + Calendar calendar = Calendar.instance() + calendar.setTime(nowTimestamp) + calendar.add(timeSwitch[p.intervalUomId], -p.intervalQuantity) + cond = new EntityConditionBuilder().AND { + EQUALS(fixedAssetId: f.fixedAssetId) + EQUALS(intervalUomId: p.intervalUomId) + EQUALS(productMaintTypeId: p.productMaintTypeId) + NOT_EQUAL(statusId: 'FAM_CANCELLED') + } + List<GenericValue> maintList = from('FixedAssetMaintWorkEffort') + .where(cond) + .orderBy('maintHistSeqId') + .queryList() + long listSize = maintList ? maintList.size(): 0 + Timestamp lastSvcDate = maintList ? maintList.last().actualCompletionDate: null + if (lastSvcDate && lastSvcDate.before(calendar.getTime()) + && (repeatCount <= 0 || listSize < repeatCount)) { + run service: 'createFixedAssetMaint', with: [*: p.getAllFields(), + fixedAssetId: f.fixedAssetId, + statusId: 'FAM_CREATED'] + } + } + } + } + return success() +} + +/** + * Create a FixedAsset Maintenance Order + * @return + */ +Map createFixedAssetMaintOrder() { + GenericValue lookedUpValue = from('OrderHeader').where(parameters).queryOne() + if (!lookedUpValue) { + return error(label('AccountingUiLabels', 'AccountingOrderWithIdNotFound', parameters)) + } + + // Check if user has not passed in orderItemSeqId then get list of OrderItems from database and default to first item + if (!parameters.orderItemSeqId) { + parameters.orderItemSeqId = from('OrderItem').where(orderId: lookedUpValue.orderId).queryList()?.orderItemSeqId + } else { + lookedUpValue = from('OrderItem').where(parameters).queryOne() + if (!lookedUpValue) { + return error(label('AccountingUiLabels', 'AccountingOrderItemWithIdNotFound', parameters)) + } + } + delegator.create('FixedAssetMaintOrder', parameters) + return success() +} + +/** + * Auto-assign Fixed Asset Parties to a Fixed Asset Maintenance + */ +Map autoAssignFixedAssetPartiesToMaintenance() { + from('PartyFixedAssetAssignAndRole') + .where(fixedAssetId: parameters.fixedAssetId, + parentTypeId: 'FAM_ASSIGNEE') + .filterByDate() + .queryList() + .each { + run service: 'assignPartyToWorkEffort', with: [partyId: it.partyId, + roleTypeId: it.roleTypeId, + workEffortId: parameters.workEffortId, + statusId: 'PRTYASGN_ASSIGNED'] + } + return success() +} + + +/** + * Calculate straight line depreciation to Fixed Asset[ (PC-SV)/expLife ] + */ +Map straightLineDepreciation() { + BigDecimal depreciationTotal = 0 + BigDecimal depreciation = 0 + List assetDepreciationInfoList = [] + List assetDepreciationTillDate = [] + List assetNBVAfterDepreciation = [] + BigDecimal purchaseCost = parameters.purchaseCost + GenericValue fixedAsset = from('FixedAsset').where(parameters).queryOne() + if (! fixedAsset) { + return error(label('AccountingErrorUiLabels', 'AccountingFixedAssetNotFound')) + } + if (parameters.usageYears > 0) { + //FORMULA : depreciation = (purchaseCost - salvageValue) / (expectedEndOfLife - dateAcquired) + int numberOfYears = parameters.expEndOfLifeYear - parameters.assetAcquiredYear + if (numberOfYears > 0) { + depreciation = (purchaseCost - parameters.salvageValue) / numberOfYears + depreciation.setScale(2, RoundingMode.HALF_EVEN) + int intUsageYears = (numberOfYears < parameters.intUsageYears) ? parameters.intUsageYears : numberOfYears + for (int i = 1; i++; i <intUsageYears) { + purchaseCost -= depreciation + depreciationTotal += depreciation + assetDepreciationTillDate << depreciation + assetNBVAfterDepreciation << purchaseCost + assetDepreciationInfoList << [year: i, + depreciation: depreciation, + depreciationTotal: depreciationTotal, + nbv: purchaseCost] + } + } + } + + if (! assetDepreciationTillDate) { + assetDepreciationTillDate << depreciation + assetNBVAfterDepreciation << purchaseCost + assetDepreciationInfoList << [year: parameters.assetAcquiredYear, + depreciation: depreciation, + depreciationTotal: depreciationTotal, + nbv: purchaseCost] + } + logInfo "Using straight line formula depreciation calculated for fixedAsset (${parameters.fixedAssetId}) is ${depreciation}" + + // Next depreciation based on actual depreciation history + BigDecimal nextDepreciationAmount = 0 + + // FORMULA : depreciation = (purchaseCost - salvageValue - pastDepreciations) / remainingYears + int remainingYears = parameters.expEndOfLifeYear - parameters.assetAcquiredYear - parameters.intUsageYears + if (remainingYears > 0) { + nextDepreciationAmount = (fixedAsset.purchaseCost - parameters.salvageValue - fixedAsset.depreciation) / remainingYears + nextDepreciationAmount.setScale(2, RoundingMode.HALF_EVEN) + } + return success([assetDepreciationTillDate: assetDepreciationTillDate, + assetNBVAfterDepreciation: assetNBVAfterDepreciation, + assetDepreciationInfoList: assetDepreciationInfoList, + nextDepreciationAmount: nextDepreciationAmount, + plannedPastDepreciationTotal: depreciationTotal - fixedAsset.depreciation]) +} + +/** + * Calculate double declining balance depreciation to Fixed Asset + */ +Map doubleDecliningBalanceDepreciation() { + String expEndOfLifeYear = parameters.expEndOfLifeYear + String assetAcquiredYear = parameters.assetAcquiredYear + String purchaseCost = parameters.purchaseCost + String salvageValue = parameters.salvageValue + + // Next depreciation based on actual depreciation history + BigDecimal nextDepreciationAmount = 0 + GenericValue fixedAsset = from('FixedAsset').where(parameters).queryOne() + if (fixedAsset) { + int remainingYears = expEndOfLifeYear - assetAcquiredYear - parameters.usageYears + if (remainingYears > 0) { + nextDepreciationAmount = 2 * (purchaseCost - salvageValue - fixedAsset.depreciation) / remainingYears + } + } + + List assetDepreciationTillDate = [] + List assetNBVAfterDepreciation = [] + List assetDepreciationInfoList = [] + BigDecimal depreciationTotal = 0 + if (parameters.usageYears > 0 && fixedAsset) { + BigDecimal depreciationYear = assetAcquiredYear + for (int i = 0; i < parameters.usageYears; i++) { + BigDecimal depreciation = 0 + int numberOfYears = expEndOfLifeYear - assetAcquiredYear + if (numberOfYears > 0) { + depreciation = (purchaseCost - salvageValue) * 2 / numberOfYears + } + assetAcquiredYear++ + purchaseCost -= depreciation + depreciationTotal += depreciation + assetDepreciationTillDate << depreciation + assetNBVAfterDepreciation << purchaseCost + assetDepreciationInfoList << [nbv: purchaseCost, + year: depreciationYear, + depreciation: depreciation, + depreciationTotal: depreciationTotal] + } + + if (!assetDepreciationTillDate) { + assetDepreciationTillDate << 0 + assetNBVAfterDepreciation << purchaseCost + assetDepreciationInfoList << [nbv: purchaseCost, + year: assetAcquiredYear, + depreciation: 0, + depreciationTotal: depreciationTotal] + } + } + logInfo "Using double decline formula depreciation calculated for fixedAsset (${parameters.fixedAssetId}) is ${assetDepreciationTillDate}" + return success([assetDepreciationTillDate: assetDepreciationTillDate, + assetNBVAfterDepreciation: assetNBVAfterDepreciation, + assetDepreciationInfoList: assetDepreciationInfoList, + nextDepreciationAmount: nextDepreciationAmount, + plannedPastDepreciationTotal: depreciationTotal - fixedAsset.depreciation]) +} + +/** + * Service to calculate the yearly depreciation from dateAcquired year to current financial year + */ +Map calculateFixedAssetDepreciation() { + GenericValue fixedAsset = from('FixedAsset').where(parameters).queryOne() + if (!fixedAsset) { + return error(label('ManufacturingUiLabels', 'ManufacturingFixedAssetNotExist')) + } + String expEndOfLifeYear, assetAcquiredYear + + // Extract asset end of life year from field expectedEndOfLife + if (fixedAsset.expectedEndOfLife) { + expEndOfLifeYear = fixedAsset.expectedEndOfLife.toString().substring(0, 4) + } else { + return success(label('AccountingUiLabels', 'AccountingExpEndOfLifeIsEmpty')) + } + + // Extract asset acquired year from field dateAcquired + if (fixedAsset.expectedEndOfLife) { + assetAcquiredYear = fixedAsset.dateAcquired.toString().substring(0, 4) + } else { + return success(label('AccountingUiLabels', 'AccountingDateAcquiredIsEmpty')) + } + + // if any asset's salvage value is empty then set it by 0 + BigDecimal salvageValue = fixedAsset.salvageValue ?: 0.0 + + // Get running year + String currentYear = UtilDateTime.nowAsString().substring(0, 4) + + // Calculate asset's total run in years + int usageYears = currentYear - assetAcquiredYear + + GenericValue fixedAssetDepMethod = from('FixedAssetDepMethod') + .where(fixedAssetId: parameters.fixedAssetId) + .filterByDate() + .queryFirst() + if (fixedAssetDepMethod) { + GenericValue customMethod = fixedAssetDepMethod.getRelatedOne('CustomMethod', true) + logInfo "Depreciation service name for the FixedAsset ${parameters.fixedAssetId} is ${customMethod.customMethodName}" + Map serviceResult = run service: customMethod.customMethodName, with: [ + fixedAssetId: parameters.fixedAssetId, + expEndOfLifeYear: expEndOfLifeYear, + assetAcquiredYear: assetAcquiredYear, + purchaseCost: fixedAsset.purchaseCost, + salvageValue: salvageValue, + usageYears: usageYears] + logInfo "Asset's depreciation calculated till date are ${serviceResult.assetDepreciationTillDate}" + logInfo "Asset's Net Book Values (NBV) from acquired date after deducting depreciation are ${serviceResult.assetNBVAfterDepreciation}" + return serviceResult + } + return error(label('AccountingUiLabels', 'AccountingFixedAssetDepreciationMethodNotFound')) +} + +/** + * If the accounting transaction is a depreciation transaction for a fixed asset, update the depreciation amount in the FixedAsset entity. + */ +Map checkUpdateFixedAssetDepreciation() { + GenericValue acctgTrans = from('AcctgTrans').where(parameters).queryOne() + if (!acctgTrans && + acctgTrans.acctgTransTypeId == 'DEPRECIATION' + && acctgTrans.fixedAssetId) { + GenericValue fixedAsset = acctgTrans.getRelatedOne('FixedAsset', true) + BigDecimal depreciation = 0 + boolean nonValidUom = false + from('AcctgTransEntry') + .where(debitCreditFlag: 'C', + acctgTransId: acctgTrans.acctgTransId) + .queryList() + .each { + if (!fixedAsset.purchaseCostUomId) { + logWarning "Found empty purchaseCostUomId for FixedAsset [${fixedAsset.fixedAssetId}]: setting it to ${creditTransaction.currencyUomId} to match the one used in the gl." + fixedAsset.purchaseCostUomId = it.currencyUomId + fixedAsset.store() + } + if (fixedAsset.purchaseCostUomId == it.currencyUomId) { + depreciation += it.amount + } else { + nonValidUom = true + } + } + if (nonValidUom) { + return failure("Found an accounting transaction for depreciation of FixedAsset [${fixedAsset.fixedAssetId}] with a currency that doesn't match the currency used in the fixed asset: the depreciation total in the fixed asset will not be updated.") + } + + fixedAsset.depreciation = fixedAsset.depreciation ?: 0 + fixedAsset.depreciation += depreciation + fixedAsset.store() + } + return success() +}