diff --git a/org.adempiere.base/META-INF/MANIFEST.MF b/org.adempiere.base/META-INF/MANIFEST.MF index 262b344575..7437088b51 100644 --- a/org.adempiere.base/META-INF/MANIFEST.MF +++ b/org.adempiere.base/META-INF/MANIFEST.MF @@ -54,6 +54,7 @@ Export-Package: bsh, org.eevolution.model, org.idempiere.broadcast, org.idempiere.distributed, + org.idempiere.fa.service.api, org.idempiere.model Comment: Bundle-RequiredExecutionEnvironment: JavaSE-11 Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version>=1.11))" diff --git a/org.adempiere.base/src/org/adempiere/base/Core.java b/org.adempiere.base/src/org/adempiere/base/Core.java index fd8c74cc8e..c9203939e8 100644 --- a/org.adempiere.base/src/org/adempiere/base/Core.java +++ b/org.adempiere.base/src/org/adempiere/base/Core.java @@ -48,6 +48,9 @@ import org.compiere.process.ProcessCall; import org.compiere.util.CLogger; import org.compiere.util.PaymentExport; import org.compiere.util.ReplenishInterface; +import org.idempiere.fa.service.api.DepreciationFactoryLookupDTO; +import org.idempiere.fa.service.api.IDepreciationMethod; +import org.idempiere.fa.service.api.IDepreciationMethodFactory; /** * This is a facade class for the Service Locator. @@ -516,5 +519,26 @@ public class Core { return null; } + + /** + * lookup implement {@link IDepreciationMethod} + * @param factoryLookupDTO + * @return + */ + public static IDepreciationMethod getDepreciationMethod(DepreciationFactoryLookupDTO factoryLookupDTO) { + + List factoryList = + Service.locator().list(IDepreciationMethodFactory.class).getServices(); + if (factoryList != null) { + for(IDepreciationMethodFactory factory : factoryList) { + IDepreciationMethod depreciationMethod = factory.getDepreciationMethod(factoryLookupDTO); + if (depreciationMethod != null) { + return depreciationMethod; + } + } + } + + return null; + } } diff --git a/org.adempiere.base/src/org/compiere/model/MDepreciation.java b/org.adempiere.base/src/org/compiere/model/MDepreciation.java index d471de738d..81bb6e5bd4 100644 --- a/org.adempiere.base/src/org/compiere/model/MDepreciation.java +++ b/org.adempiere.base/src/org/compiere/model/MDepreciation.java @@ -2,6 +2,7 @@ package org.compiere.model; import java.math.BigDecimal; import java.math.RoundingMode; import java.sql.ResultSet; +import java.util.Calendar; import java.util.Properties; import java.util.logging.Level; import java.util.logging.Logger; @@ -13,6 +14,8 @@ import org.compiere.util.CLogger; import org.compiere.util.Env; import org.idempiere.fa.exceptions.AssetNotImplementedException; import org.idempiere.fa.exceptions.AssetNotSupportedException; +import org.idempiere.fa.service.api.DepreciationDTO; +import org.idempiere.fa.service.api.IDepreciationMethod; /** @@ -144,7 +147,7 @@ public class MDepreciation extends X_A_Depreciation * @return amortized value */ public BigDecimal invoke(MDepreciationWorkfile assetwk, MAssetAcct assetAcct, - int A_Current_Period, BigDecimal Accum_Dep) + int A_Current_Period, BigDecimal Accum_Dep, IDepreciationMethod depreciationMethod) { String depreciationType = getDepreciationType(); BigDecimal retValue = null; @@ -164,7 +167,24 @@ public class MDepreciation extends X_A_Depreciation { return BigDecimal.ZERO; } - if (depreciationType.equalsIgnoreCase("SL")) + + if (depreciationMethod != null) { + DepreciationDTO depreciationDTO = new DepreciationDTO(); + depreciationDTO.period = A_Current_Period; + depreciationDTO.salvage = assetwk.getA_Salvage_Value(); + depreciationDTO.totalAmount = assetwk.getA_Asset_Cost(); + depreciationDTO.useFullLife = new BigDecimal(assetwk.getA_Life_Period());// at the moment, int is ok for Thai, but for other country BigDecima is suitable, need to change AD + depreciationDTO.useFullLifeUnit = Calendar.MONTH; + depreciationDTO.trxName = assetwk.get_TrxName(); + depreciationDTO.depreciationId = assetwk.get_ID(); + depreciationDTO.inServiceDate = assetwk.getA_Asset().getAssetServiceDate(); + depreciationDTO.accountDate = assetwk.getDateAcct(); + depreciationDTO.accumulatedCost = assetwk.getA_Accumulated_Depr(); + depreciationDTO.startPeriodDepreciation = assetwk.getA_Current_Period(); + depreciationDTO.scale = getPrecision(); + // calculate expense use implement of IDepreciationMethod + retValue = depreciationMethod.caclulateDepreciation(depreciationDTO); + }else if (depreciationType.equalsIgnoreCase("SL")) { retValue = apply_SL(assetwk, assetAcct, A_Current_Period, Accum_Dep); } diff --git a/org.adempiere.base/src/org/compiere/model/MDepreciationWorkfile.java b/org.adempiere.base/src/org/compiere/model/MDepreciationWorkfile.java index 880f8ae226..0255dac62f 100644 --- a/org.adempiere.base/src/org/compiere/model/MDepreciationWorkfile.java +++ b/org.adempiere.base/src/org/compiere/model/MDepreciationWorkfile.java @@ -3,10 +3,12 @@ package org.compiere.model; import java.math.BigDecimal; import java.sql.ResultSet; import java.sql.Timestamp; +import java.util.Calendar; import java.util.Collection; import java.util.Properties; import java.util.logging.Level; +import org.adempiere.base.Core; import org.apache.commons.collections.keyvalue.MultiKey; import org.compiere.util.CCache; import org.compiere.util.CLogMgt; @@ -16,6 +18,9 @@ import org.compiere.util.Env; import org.compiere.util.TimeUtil; import org.idempiere.fa.feature.UseLife; import org.idempiere.fa.feature.UseLifeImpl; +import org.idempiere.fa.service.api.DepreciationDTO; +import org.idempiere.fa.service.api.DepreciationFactoryLookupDTO; +import org.idempiere.fa.service.api.IDepreciationMethod; /** @@ -649,6 +654,28 @@ public class MDepreciationWorkfile extends X_A_Depreciation_Workfile truncDepreciation(); int A_Current_Period = getA_Current_Period(); + + // lookup for implement of IDepreciationMethod + DepreciationFactoryLookupDTO depreciationFactoryLookupDTO = new DepreciationFactoryLookupDTO(); + depreciationFactoryLookupDTO.depreciationType = depreciation_C.getDepreciationType(); + IDepreciationMethod depreciationMethod = Core.getDepreciationMethod (depreciationFactoryLookupDTO); + + if(depreciationMethod != null) { + DepreciationDTO depreciationDTO = new DepreciationDTO(); + depreciationDTO.useFullLife = new BigDecimal(this.getA_Life_Period());// at the moment, int is ok for Thai, but for other country BigDecima is suitable, need to change AD + depreciationDTO.useFullLifeUnit = Calendar.MONTH; + depreciationDTO.depreciationId = this.get_ID(); + depreciationDTO.inServiceDate = this.getA_Asset().getAssetServiceDate(); + depreciationDTO.accountDate = this.getDateAcct(); + depreciationDTO.startPeriodDepreciation = this.getA_Current_Period(); + lifePeriods = (int)depreciationMethod.getCountPeriod(depreciationDTO); + + // it's safe, at the moment, core disable setting of lifePeriods_F + lifePeriods_C = lifePeriods; + lifePeriods_F = lifePeriods; + } + + for (int currentPeriod = A_Current_Period, cnt = 1; currentPeriod <= lifePeriods; currentPeriod++, cnt++) { exp_C = Env.ZERO; @@ -656,34 +683,42 @@ public class MDepreciationWorkfile extends X_A_Depreciation_Workfile String help = "" + accumDep_C + "|" + accumDep_F + " + "; - if (lifePeriods_C > currentPeriod || !depreciation_C.requireLastPeriodAdjustment()) + if (lifePeriods_C > currentPeriod || !depreciation_C.requireLastPeriodAdjustment()) { setFiscal(false); - exp_C = depreciation_C.invoke(this, assetacct, currentPeriod, accumDep_C); + exp_C = depreciation_C.invoke(this, assetacct, currentPeriod, accumDep_C, depreciationMethod); accumDep_C = accumDep_C.add(exp_C); } else if (lifePeriods_C == currentPeriod) { // last period - exp_C = assetCost.subtract(accumDep_C); + if (depreciationMethod != null && depreciationMethod.isPeriodAdjustment()) { + exp_C = depreciation_C.invoke(this, assetacct, currentPeriod, accumDep_C, depreciationMethod); + }else { + exp_C = assetCost.subtract(accumDep_C); + } accumDep_C = assetCost; } if (lifePeriods_F > currentPeriod || !depreciation_F.requireLastPeriodAdjustment()) { setFiscal(true); - exp_F = depreciation_F.invoke(this, assetacct, currentPeriod, accumDep_F); + exp_F = depreciation_F.invoke(this, assetacct, currentPeriod, accumDep_F, depreciationMethod); accumDep_F = accumDep_F.add(exp_F); } else if (lifePeriods_F == currentPeriod) { // last period (fiscal) - exp_F = assetCost.subtract(accumDep_F); + if (depreciationMethod != null && depreciationMethod.isPeriodAdjustment()) { + exp_C = depreciation_C.invoke(this, assetacct, currentPeriod, accumDep_C, depreciationMethod); + }else { + exp_F = assetCost.subtract(accumDep_F); + } accumDep_F = assetCost; } help += "" + exp_C + "|" + exp_F + " = " + accumDep_C + "|" + accumDep_F; // added by zuhri - int months = 0; + int months = 0; months = months + (currentPeriod - A_Current_Period); Timestamp dateAcct = TimeUtil.getMonthLastDay(TimeUtil.addMonths(getDateAcct(), months)); diff --git a/org.adempiere.base/src/org/idempiere/fa/service/api/DepreciationDTO.java b/org.adempiere.base/src/org/idempiere/fa/service/api/DepreciationDTO.java new file mode 100644 index 0000000000..711cccf9e4 --- /dev/null +++ b/org.adempiere.base/src/org/idempiere/fa/service/api/DepreciationDTO.java @@ -0,0 +1,74 @@ +package org.idempiere.fa.service.api; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.sql.Timestamp; +import java.util.Calendar; + +/** + * parameter to calculate depreciation + * @author hieplq + * + */ +public class DepreciationDTO implements Serializable { + /** + * + */ + private static final long serialVersionUID = -748366297153525253L; + /** + * period calculate for + */ + public int period; + /** + * remain amount after full depreciation + */ + public BigDecimal salvage; + /** + * time to depreciation + */ + public BigDecimal useFullLife; + /** + * UOM for {@link #useFullLife}, use constant from {@link Calendar} + * accept {@link Calendar#YEAR} {@link Calendar#MONTH} {@link Calendar#DATE} + */ + public int useFullLifeUnit; + /** + * date start depreciation + */ + public Timestamp inServiceDate; + /** + * date booking, at the moment {@link #inServiceDate} isn't mandatory, in case don't input {@link #inServiceDate}, can use accountDate as {@link #inServiceDate} + */ + public Timestamp accountDate; + /** + * date asset transfer to other org. + * so days to depreciate of last period of source org like end period of life, it can not full month days + * so days to depreciate of first period of destination org like start period of life, it can not full month days + */ + public Timestamp transferDay; + /** + * period start to calculate depreciate + */ + public int startPeriodDepreciation; + /** + * accumulated when start calculate for {@link #startPeriodDepreciation} + */ + public BigDecimal accumulatedCost; + /** + * asset cost + */ + public BigDecimal totalAmount; + + public int scale = 4; +/*** idempiere part ****/ + + /** + * in case DTO isn't enough or not suitable for your method, use depreciationId to get X_A_Depreciation_Workfile so you can get more relate info + */ + public int depreciationId; + + /** + * name of current transaction + */ + public String trxName; +} diff --git a/org.adempiere.base/src/org/idempiere/fa/service/api/DepreciationFactoryLookupDTO.java b/org.adempiere.base/src/org/idempiere/fa/service/api/DepreciationFactoryLookupDTO.java new file mode 100644 index 0000000000..10ed775442 --- /dev/null +++ b/org.adempiere.base/src/org/idempiere/fa/service/api/DepreciationFactoryLookupDTO.java @@ -0,0 +1,10 @@ +package org.idempiere.fa.service.api; + +/** + * pass to {@link IDepreciationMethodFactory} to lookup {@link IDepreciationMethod} implement + * @author hieplq + * + */ +public class DepreciationFactoryLookupDTO { + public String depreciationType; +} diff --git a/org.adempiere.base/src/org/idempiere/fa/service/api/IDepreciationMethod.java b/org.adempiere.base/src/org/idempiere/fa/service/api/IDepreciationMethod.java new file mode 100644 index 0000000000..02e610c4d3 --- /dev/null +++ b/org.adempiere.base/src/org/idempiere/fa/service/api/IDepreciationMethod.java @@ -0,0 +1,28 @@ +package org.idempiere.fa.service.api; + +import java.math.BigDecimal; + +/** + * implement this interface to provide depreciate calculate method + * @author hieplq + * + */ +public interface IDepreciationMethod { + /** + * calculate depreciation for each period + * @param depreciationDTO + * @return amount depreciation for {@link DepreciationDTO#period} + */ + public BigDecimal caclulateDepreciation (DepreciationDTO depreciationDTO); + /** + * get num of period to depreciation + * @param depreciationDTO + * @return + */ + public long getCountPeriod (DepreciationDTO depreciationDTO); + /** + * support to move all difference by round to end period + * @return + */ + public boolean isPeriodAdjustment (); +} diff --git a/org.adempiere.base/src/org/idempiere/fa/service/api/IDepreciationMethodFactory.java b/org.adempiere.base/src/org/idempiere/fa/service/api/IDepreciationMethodFactory.java new file mode 100644 index 0000000000..729ffa0687 --- /dev/null +++ b/org.adempiere.base/src/org/idempiere/fa/service/api/IDepreciationMethodFactory.java @@ -0,0 +1,15 @@ +package org.idempiere.fa.service.api; + +/** + * factory for {@link IDepreciationMethod} + * @author hieplq + * + */ +public interface IDepreciationMethodFactory { + /** + * lookup {@link IDepreciationMethod} + * @param factoryLookupDTO + * @return + */ + public IDepreciationMethod getDepreciationMethod(DepreciationFactoryLookupDTO factoryLookupDTO); +}