From 9a1add059dcbaf7b5bbc45f84f77e5753266f15d Mon Sep 17 00:00:00 2001 From: "Owner.Owner-PC" Date: Mon, 10 Sep 2012 12:22:06 +0700 Subject: [PATCH] commit new asset classes --- .../org/compiere/acct/Doc_AssetAddition.java | 180 ++++ .../org/compiere/acct/Doc_AssetDisposed.java | 74 ++ .../src/org/compiere/acct/Doc_AssetReval.java | 95 +++ .../org/compiere/acct/Doc_AssetTransfer.java | 95 +++ .../compiere/acct/Doc_DepreciationEntry.java | 90 ++ .../src/org/compiere/acct/FactUtil.java | 65 ++ .../src/org/compiere/model/MAssetClass.java | 210 +++++ .../org/compiere/model/MAssetDisposed.java | 438 ++++++++++ .../src/org/compiere/model/MAssetProduct.java | 93 ++ .../src/org/compiere/model/MAssetReval.java | 258 ++++++ .../src/org/compiere/model/MAssetType.java | 231 +++++ .../compiere/model/MConversionRateUtil.java | 103 +++ .../src/org/compiere/model/MDepreciation.java | 462 ++++++++++ .../compiere/model/MDepreciationBuild.java | 28 + .../model/MDepreciationConvention.java | 116 +++ .../compiere/model/MDepreciationEntry.java | 373 ++++++++ .../org/compiere/model/MDepreciationExp.java | 301 +++++++ .../compiere/model/MDepreciationMethod.java | 245 ++++++ .../src/org/compiere/model/MIFixedAsset.java | 330 ++++++++ .../src/org/compiere/model/SetGetModel.java | 20 + .../src/org/compiere/model/SetGetUtil.java | 796 ++++++++++++++++++ .../compiere/util/ArhRuntimeException.java | 186 ++++ .../NoCurrencyConversionException.java | 86 ++ .../AssetAlreadyDepreciatedException.java | 20 + .../fa/exceptions/AssetArrayException.java | 33 + .../AssetCheckDocumentException.java | 19 + .../fa/exceptions/AssetException.java | 35 + .../AssetInvalidTransitionException.java | 40 + .../AssetInvoiceWithMixedLines_LRO.java | 17 + .../exceptions/AssetNotActiveException.java | 18 + .../AssetNotImplementedException.java | 20 + .../AssetNotSupportedException.java | 18 + .../AssetProductStockedException.java | 20 + .../AssetStatusChangedException.java | 33 + .../DepreciationNoInPeriodException.java | 21 + .../src/org/idempiere/fa/feature/UseLife.java | 35 + .../org/idempiere/fa/feature/UseLifeImpl.java | 425 ++++++++++ .../fa/model/CalloutA_Asset_Addition.java | 131 +++ .../fa/model/CalloutA_Asset_Disposed.java | 86 ++ .../fa/model/CalloutA_Asset_Reval.java | 56 ++ .../fa/model/CalloutA_Asset_Transfer.java | 72 ++ .../model/CalloutA_Depreciation_Workfile.java | 63 ++ .../org/idempiere/fa/model/CalloutAsset.java | 196 +++++ .../idempiere/fa/model/ModelValidator.java | 284 +++++++ .../process/A_Asset_Addition_ProcessAll.java | 44 + .../process/A_Asset_CreateFromMatchInv.java | 48 ++ .../fa/process/A_Depreciation_Exp_Check.java | 171 ++++ .../fa/process/A_Depreciation_Exp_Modify.java | 86 ++ .../process/A_Depreciation_Exp_Process.java | 25 + .../A_Depreciation_Workfile_Build.java | 66 ++ .../fa/process/ImportFixedAsset.java | 411 +++++++++ .../fa/process/ProjectCreateAsset.java | 124 +++ .../org/idempiere/fa/process/SvrProcess2.java | 97 +++ .../org/idempiere/fa/util/POCacheLocal.java | 101 +++ .../src/org/idempiere/fa/util/Util.java | 47 ++ 55 files changed, 7737 insertions(+) create mode 100644 org.adempiere.base/src/org/compiere/acct/Doc_AssetAddition.java create mode 100644 org.adempiere.base/src/org/compiere/acct/Doc_AssetDisposed.java create mode 100644 org.adempiere.base/src/org/compiere/acct/Doc_AssetReval.java create mode 100644 org.adempiere.base/src/org/compiere/acct/Doc_AssetTransfer.java create mode 100644 org.adempiere.base/src/org/compiere/acct/Doc_DepreciationEntry.java create mode 100644 org.adempiere.base/src/org/compiere/acct/FactUtil.java create mode 100644 org.adempiere.base/src/org/compiere/model/MAssetClass.java create mode 100644 org.adempiere.base/src/org/compiere/model/MAssetDisposed.java create mode 100644 org.adempiere.base/src/org/compiere/model/MAssetProduct.java create mode 100644 org.adempiere.base/src/org/compiere/model/MAssetReval.java create mode 100644 org.adempiere.base/src/org/compiere/model/MAssetType.java create mode 100644 org.adempiere.base/src/org/compiere/model/MConversionRateUtil.java create mode 100644 org.adempiere.base/src/org/compiere/model/MDepreciation.java create mode 100644 org.adempiere.base/src/org/compiere/model/MDepreciationBuild.java create mode 100644 org.adempiere.base/src/org/compiere/model/MDepreciationConvention.java create mode 100644 org.adempiere.base/src/org/compiere/model/MDepreciationEntry.java create mode 100644 org.adempiere.base/src/org/compiere/model/MDepreciationExp.java create mode 100644 org.adempiere.base/src/org/compiere/model/MDepreciationMethod.java create mode 100644 org.adempiere.base/src/org/compiere/model/MIFixedAsset.java create mode 100644 org.adempiere.base/src/org/compiere/model/SetGetModel.java create mode 100644 org.adempiere.base/src/org/compiere/model/SetGetUtil.java create mode 100644 org.adempiere.base/src/org/compiere/util/ArhRuntimeException.java create mode 100644 org.adempiere.base/src/org/idempiere/exceptions/NoCurrencyConversionException.java create mode 100644 org.adempiere.base/src/org/idempiere/fa/exceptions/AssetAlreadyDepreciatedException.java create mode 100644 org.adempiere.base/src/org/idempiere/fa/exceptions/AssetArrayException.java create mode 100644 org.adempiere.base/src/org/idempiere/fa/exceptions/AssetCheckDocumentException.java create mode 100644 org.adempiere.base/src/org/idempiere/fa/exceptions/AssetException.java create mode 100644 org.adempiere.base/src/org/idempiere/fa/exceptions/AssetInvalidTransitionException.java create mode 100644 org.adempiere.base/src/org/idempiere/fa/exceptions/AssetInvoiceWithMixedLines_LRO.java create mode 100644 org.adempiere.base/src/org/idempiere/fa/exceptions/AssetNotActiveException.java create mode 100644 org.adempiere.base/src/org/idempiere/fa/exceptions/AssetNotImplementedException.java create mode 100644 org.adempiere.base/src/org/idempiere/fa/exceptions/AssetNotSupportedException.java create mode 100644 org.adempiere.base/src/org/idempiere/fa/exceptions/AssetProductStockedException.java create mode 100644 org.adempiere.base/src/org/idempiere/fa/exceptions/AssetStatusChangedException.java create mode 100644 org.adempiere.base/src/org/idempiere/fa/exceptions/DepreciationNoInPeriodException.java create mode 100644 org.adempiere.base/src/org/idempiere/fa/feature/UseLife.java create mode 100644 org.adempiere.base/src/org/idempiere/fa/feature/UseLifeImpl.java create mode 100644 org.adempiere.base/src/org/idempiere/fa/model/CalloutA_Asset_Addition.java create mode 100644 org.adempiere.base/src/org/idempiere/fa/model/CalloutA_Asset_Disposed.java create mode 100644 org.adempiere.base/src/org/idempiere/fa/model/CalloutA_Asset_Reval.java create mode 100644 org.adempiere.base/src/org/idempiere/fa/model/CalloutA_Asset_Transfer.java create mode 100644 org.adempiere.base/src/org/idempiere/fa/model/CalloutA_Depreciation_Workfile.java create mode 100644 org.adempiere.base/src/org/idempiere/fa/model/CalloutAsset.java create mode 100644 org.adempiere.base/src/org/idempiere/fa/model/ModelValidator.java create mode 100644 org.adempiere.base/src/org/idempiere/fa/process/A_Asset_Addition_ProcessAll.java create mode 100644 org.adempiere.base/src/org/idempiere/fa/process/A_Asset_CreateFromMatchInv.java create mode 100644 org.adempiere.base/src/org/idempiere/fa/process/A_Depreciation_Exp_Check.java create mode 100644 org.adempiere.base/src/org/idempiere/fa/process/A_Depreciation_Exp_Modify.java create mode 100644 org.adempiere.base/src/org/idempiere/fa/process/A_Depreciation_Exp_Process.java create mode 100644 org.adempiere.base/src/org/idempiere/fa/process/A_Depreciation_Workfile_Build.java create mode 100644 org.adempiere.base/src/org/idempiere/fa/process/ImportFixedAsset.java create mode 100644 org.adempiere.base/src/org/idempiere/fa/process/ProjectCreateAsset.java create mode 100644 org.adempiere.base/src/org/idempiere/fa/process/SvrProcess2.java create mode 100644 org.adempiere.base/src/org/idempiere/fa/util/POCacheLocal.java create mode 100644 org.adempiere.base/src/org/idempiere/fa/util/Util.java diff --git a/org.adempiere.base/src/org/compiere/acct/Doc_AssetAddition.java b/org.adempiere.base/src/org/compiere/acct/Doc_AssetAddition.java new file mode 100644 index 0000000000..0a64abd223 --- /dev/null +++ b/org.adempiere.base/src/org/compiere/acct/Doc_AssetAddition.java @@ -0,0 +1,180 @@ +package org.compiere.acct; + +import java.math.BigDecimal; +import java.sql.ResultSet; +import java.util.ArrayList; + +import org.compiere.model.I_C_Project; +import org.compiere.model.I_C_Project_Acct; +import org.compiere.model.MAccount; +import org.compiere.model.MAcctSchema; +import org.compiere.model.MAssetAcct; +import org.compiere.model.MAssetAddition; +import org.compiere.model.MCharge; +import org.compiere.model.MDocType; +import org.compiere.model.MProject; +import org.compiere.model.ProductCost; +import org.compiere.model.X_C_Project_Acct; +import org.compiere.util.DB; +import org.compiere.util.Env; + + +/** + * @author Teo_Sarca, SC ARHIPAC SERVICE SRL + */ +public class Doc_AssetAddition extends Doc +{ + public Doc_AssetAddition (MAcctSchema as, ResultSet rs, String trxName) + { + super(as, MAssetAddition.class, rs, MDocType.DOCBASETYPE_GLDocument, trxName); + } + + + protected String loadDocumentDetails() + { + return null; + } + + + public BigDecimal getBalance() + { + return Env.ZERO; + } + + /** + * Produce inregistrarea: + *
+	 *	20.., 21..[A_Asset_Acct]			=	23..[P_Asset_Acct/Project Acct]
+	 * 
+ */ + + public ArrayList createFacts(MAcctSchema as) + { + MAssetAddition assetAdd = getAssetAddition(); + ArrayList facts = new ArrayList(); + Fact fact = new Fact(this, as, assetAdd.getPostingType()); + facts.add(fact); + // + if (MAssetAddition.A_SOURCETYPE_Imported.equals(assetAdd.getA_SourceType()) + || MAssetAddition.A_CAPVSEXP_Expense.equals(assetAdd.getA_CapvsExp())) //@win prevent create journal if expense addition + { + // no accounting if is imported record + return facts; + } + // + BigDecimal assetValueAmt = assetAdd.getAssetValueAmt(); + FactLine[] fls = FactUtil.createSimpleOperation(fact, null, + getA_Asset_Acct(), getP_Asset_Acct(as), + as.getC_Currency_ID(), + assetValueAmt, + false); + // Set BPartner and C_Project dimension for "Imobilizari in curs / Property Being" + final int invoiceBP_ID = getInvoicePartner_ID(); + final int invoiceProject_ID = getInvoiceProject_ID(); + if (invoiceBP_ID > 0) + { + fls[1].setC_BPartner_ID(invoiceBP_ID); + } + if (invoiceProject_ID >0) + { + fls[1].setC_Project_ID(invoiceProject_ID); + } + // + return facts; + } + + private MAssetAddition getAssetAddition() + { + return (MAssetAddition)getPO(); + } + + private MAccount getP_Asset_Acct(MAcctSchema as) + { + MAssetAddition assetAdd = getAssetAddition(); + // Source Account + MAccount pAssetAcct = null; + if (MAssetAddition.A_SOURCETYPE_Project.equals(assetAdd.getA_SourceType())) + { + I_C_Project prj = assetAdd.getC_Project(); + return getProjectAcct(prj, as); + } + else if (MAssetAddition.A_SOURCETYPE_Manual.equals(assetAdd.getA_SourceType()) + && getC_Charge_ID() > 0) // backward compatibility: only if charge defined; if not fallback to product account + { + pAssetAcct = MCharge.getAccount(getC_Charge_ID(), as, null); + return pAssetAcct; + } + else if (MAssetAddition.A_SOURCETYPE_Invoice.equals(assetAdd.getA_SourceType()) + && assetAdd.getC_InvoiceLine().getC_Project_ID() > 0) + { + I_C_Project prj = assetAdd.getC_InvoiceLine().getC_Project(); + return getProjectAcct(prj, as); + } + else + { + pAssetAcct = getP_Expense_Acct(assetAdd.getM_Product_ID(), as); + } + // + return pAssetAcct; + } + + public MAccount getP_Expense_Acct(int M_Product_ID, MAcctSchema as) + { + ProductCost pc = new ProductCost(getCtx(), M_Product_ID, 0, null); + return pc.getAccount(ProductCost.ACCTTYPE_P_Expense, as); + } + + + private MAccount getProjectAcct(I_C_Project prj, MAcctSchema as) + { + // TODO: keep in sync with org.compiere.acct.Doc_ProjectIssue.createFacts(MAcctSchema) logic + String projectCategory = prj.getProjectCategory(); + String acctName = X_C_Project_Acct.COLUMNNAME_PJ_WIP_Acct; + if (MProject.PROJECTCATEGORY_AssetProject.equals(projectCategory)) + acctName = X_C_Project_Acct.COLUMNNAME_PJ_Asset_Acct; + // + String sql = "SELECT "+acctName + + " FROM "+I_C_Project_Acct.Table_Name + + " WHERE "+I_C_Project_Acct.COLUMNNAME_C_Project_ID+"=?" + +" AND "+I_C_Project_Acct.COLUMNNAME_C_AcctSchema_ID+"=?" + ; + int acct_id = DB.getSQLValueEx(getTrxName(), sql, prj.getC_Project_ID(), as.get_ID()); + return MAccount.get(getCtx(), acct_id); + } + + private MAccount getA_Asset_Acct() + { + MAssetAddition assetAdd = getAssetAddition(); + int acct_id = MAssetAcct + .forA_Asset_ID(getCtx(), assetAdd.getA_Asset_ID(), assetAdd.getPostingType(), assetAdd.getDateAcct(), null) + .getA_Asset_Acct(); + return MAccount.get(getCtx(), acct_id); + } + + public int getInvoicePartner_ID() + { + MAssetAddition assetAdd = getAssetAddition(); + if (MAssetAddition.A_SOURCETYPE_Invoice.equals(assetAdd.getA_SourceType()) + && assetAdd.getC_Invoice_ID() > 0) + { + return assetAdd.getC_Invoice().getC_BPartner_ID(); + } + else + { + return 0; + } + } + public int getInvoiceProject_ID() + { + MAssetAddition assetAdd = getAssetAddition(); + if (MAssetAddition.A_SOURCETYPE_Invoice.equals(assetAdd.getA_SourceType()) + && assetAdd.getC_Invoice_ID() > 0) + { + return assetAdd.getC_InvoiceLine().getC_Project_ID(); + } + else + { + return 0; + } + } +} diff --git a/org.adempiere.base/src/org/compiere/acct/Doc_AssetDisposed.java b/org.adempiere.base/src/org/compiere/acct/Doc_AssetDisposed.java new file mode 100644 index 0000000000..5527c497ef --- /dev/null +++ b/org.adempiere.base/src/org/compiere/acct/Doc_AssetDisposed.java @@ -0,0 +1,74 @@ +package org.compiere.acct; + +import java.math.BigDecimal; +import java.sql.ResultSet; +import java.util.ArrayList; + +import org.compiere.model.MAccount; +import org.compiere.model.MAcctSchema; +import org.compiere.model.MAssetAcct; +import org.compiere.model.MAssetDisposed; +import org.compiere.model.MDocType; +import org.compiere.util.Env; + + +/** + * @author Teo_Sarca, SC ARHIPAC SERVICE SRL + */ +public class Doc_AssetDisposed extends Doc +{ + /** + * @param ass + * @param clazz + * @param rs + * @param defaultDocumentType + * @param trxName + */ + public Doc_AssetDisposed (MAcctSchema as, ResultSet rs, String trxName) + { + super(as, MAssetDisposed.class, rs, MDocType.DOCBASETYPE_GLDocument, trxName); + } + + + protected String loadDocumentDetails() + { + return null; + } + + + public BigDecimal getBalance() + { + return Env.ZERO; + } + + + public ArrayList createFacts(MAcctSchema as) + { + MAssetDisposed assetDisp = (MAssetDisposed)getPO(); + + ArrayList facts = new ArrayList(); + Fact fact = new Fact(this, as, assetDisp.getPostingType()); + facts.add(fact); + // + fact.createLine(null, getAccount(MAssetAcct.COLUMNNAME_A_Asset_Acct) + , as.getC_Currency_ID() + , Env.ZERO, assetDisp.getA_Disposal_Amt()); + fact.createLine(null, getAccount(MAssetAcct.COLUMNNAME_A_Accumdepreciation_Acct) + , as.getC_Currency_ID() + , assetDisp.getA_Accumulated_Depr_Delta(), Env.ZERO); + fact.createLine(null, getAccount(MAssetAcct.COLUMNNAME_A_Disposal_Loss_Acct) + , as.getC_Currency_ID() + , assetDisp.getExpense(), Env.ZERO); + // + return facts; + } + + private MAccount getAccount(String accountName) + { + MAssetDisposed assetDisp = (MAssetDisposed)getPO(); + MAssetAcct assetAcct = MAssetAcct.forA_Asset_ID(getCtx(), assetDisp.getA_Asset_ID(), assetDisp.getPostingType(), assetDisp.getDateAcct(),null); + int account_id = (Integer)assetAcct.get_Value(accountName); + return MAccount.get(getCtx(), account_id); + } + +} diff --git a/org.adempiere.base/src/org/compiere/acct/Doc_AssetReval.java b/org.adempiere.base/src/org/compiere/acct/Doc_AssetReval.java new file mode 100644 index 0000000000..1c73d5b089 --- /dev/null +++ b/org.adempiere.base/src/org/compiere/acct/Doc_AssetReval.java @@ -0,0 +1,95 @@ +package org.compiere.acct; + +import java.math.BigDecimal; +import java.sql.ResultSet; +import java.util.ArrayList; + +import org.compiere.model.MAccount; +import org.compiere.model.MAcctSchema; +import org.compiere.model.MAssetAcct; +import org.compiere.model.MAssetReval; +import org.compiere.model.MDocType; +import org.compiere.util.Env; + + +/** + * @author Anca Bradau www.arhipac.ro + * + */ +public class Doc_AssetReval extends Doc +{ + + + private final String POSTINGTYPE_Actual = "A"; + public Doc_AssetReval (MAcctSchema as, ResultSet rs, String trxName) + { + super(as, MAssetReval.class, rs, MDocType.DOCBASETYPE_GLJournal, trxName); + } + + + public ArrayList createFacts(MAcctSchema as) + { + MAssetAcct assetAcct = getAssetAcct(); + MAssetReval assetRe = getAssetReval(); + + ArrayList facts = new ArrayList(); + Fact fact = new Fact(this, as, assetAcct.getPostingType()); + facts.add(fact); + + MAccount dr = MAccount.get(getCtx(), assetAcct.getA_Asset_Acct()); + MAccount cr = MAccount.get(getCtx(), assetAcct.getA_Reval_Cost_Offset_Acct()); + FactUtil.createSimpleOperation(fact, null, dr, cr, as.getC_Currency_ID(), + assetRe.getA_Asset_Cost_Change().subtract(assetRe.getA_Asset_Cost()), false); + + + MAccount drd = MAccount.get(getCtx(), assetAcct.getA_Reval_Cost_Offset_Acct()); + MAccount crd = MAccount.get(getCtx(), assetAcct.getA_Accumdepreciation_Acct()); + FactUtil.createSimpleOperation(fact, null, drd, crd, as.getC_Currency_ID(), + assetRe.getA_Change_Acumulated_Depr().subtract(assetRe.getA_Accumulated_Depr()), false); + + + return facts; + } + + + public BigDecimal getBalance() + { + return Env.ZERO; + } + + + protected String loadDocumentDetails() + { + return null; + } + public String getPostingType() + { + return POSTINGTYPE_Actual; + } + + private MAssetAcct getAssetAcct() + { + return MAssetAcct.forA_Asset_ID(getCtx(), getA_Asset_ID(), getPostingType() , getDateAcct(), null); + } + private MAssetReval getAssetReval() + { + return (MAssetReval)getPO(); + } + + /** + * Get A_Asset_ID + * @return Asset + */ + public int getA_Asset_ID() + { + int index = p_po.get_ColumnIndex("A_Asset_ID"); + if (index != -1) + { + Integer ii = (Integer)p_po.get_Value(index); + if (ii != null) + return ii.intValue(); + } + return 0; + } + +} diff --git a/org.adempiere.base/src/org/compiere/acct/Doc_AssetTransfer.java b/org.adempiere.base/src/org/compiere/acct/Doc_AssetTransfer.java new file mode 100644 index 0000000000..1506f7d346 --- /dev/null +++ b/org.adempiere.base/src/org/compiere/acct/Doc_AssetTransfer.java @@ -0,0 +1,95 @@ +package org.compiere.acct; + +import java.math.BigDecimal; +import java.sql.ResultSet; +import java.util.ArrayList; + +import org.compiere.model.MAccount; +import org.compiere.model.MAcctSchema; +import org.compiere.model.MAssetTransfer; +import org.compiere.model.MDepreciationWorkfile; +import org.compiere.model.MDocType; +import org.compiere.util.Env; + + +/** + * @author Anca Bradau www.arhipac.ro + * + */ +public class Doc_AssetTransfer extends Doc +{ + + public Doc_AssetTransfer (MAcctSchema as, ResultSet rs, String trxName) + { + super(as, MAssetTransfer.class, rs, MDocType.DOCBASETYPE_GLJournal, trxName); + } + + + protected String loadDocumentDetails() + { + // Fix C_Period_ID +// MAssetTransfer assetTr = getAssetTransfer(); +// assetTr.setC_Period_ID(); +// assetTr.saveEx(); + + return null; + } + + + public BigDecimal getBalance() { + return Env.ZERO; + } + /** + * Produce inregistrarea: + *
+	 *	20.., 21..[A_Asset_New_Acct]			=	23..[A_Asset_Acct]		
+	 * 
+ */ + + public ArrayList createFacts(MAcctSchema as) + { + MAssetTransfer assetTr = getAssetTransfer(); + MDepreciationWorkfile wk = getAssetWorkfile(); + //MDepreciationExp exp = getExpense(); + + ArrayList facts = new ArrayList(); + Fact fact = new Fact(this, as, assetTr.getPostingType()); + facts.add(fact); + // + // Change Asset Account + if (assetTr.getA_Asset_New_Acct() != assetTr.getA_Asset_Acct()) + { + MAccount dr = MAccount.get(getCtx(), assetTr.getA_Asset_New_Acct()); + MAccount cr = MAccount.get(getCtx(), assetTr.getA_Asset_Acct()); + FactUtil.createSimpleOperation(fact, null, dr, cr, as.getC_Currency_ID(), + wk.getA_Asset_Cost(), false); + } + // + // Change Asset Accum. Depr. Account + if (assetTr.getA_Accumdepreciation_New_Acct() != assetTr.getA_Accumdepreciation_Acct()) + { + MAccount cr = MAccount.get(getCtx(), assetTr.getA_Accumdepreciation_New_Acct()); + MAccount dr = MAccount.get(getCtx(), assetTr.getA_Accumdepreciation_Acct()); + FactUtil.createSimpleOperation(fact, null, dr, cr, as.getC_Currency_ID(), + wk.getA_Accumulated_Depr(), false); + //exp.getA_Accumulated_Depr(), false); + } + // + return facts; + } + /*private MDepreciationExp getExpense() { + + return MDepreciationExp.get(getCtx(), 1712112); + }*/ + + private MAssetTransfer getAssetTransfer() + { + return (MAssetTransfer)getPO(); + } + private MDepreciationWorkfile getAssetWorkfile() + { + MAssetTransfer assetTr = getAssetTransfer(); + return MDepreciationWorkfile.get(getCtx(), assetTr.getA_Asset_ID(), assetTr.getPostingType(), getTrxName()); + } + +} diff --git a/org.adempiere.base/src/org/compiere/acct/Doc_DepreciationEntry.java b/org.adempiere.base/src/org/compiere/acct/Doc_DepreciationEntry.java new file mode 100644 index 0000000000..708d18634e --- /dev/null +++ b/org.adempiere.base/src/org/compiere/acct/Doc_DepreciationEntry.java @@ -0,0 +1,90 @@ +package org.compiere.acct; + +import java.math.BigDecimal; +import java.sql.ResultSet; +import java.util.ArrayList; +import java.util.Iterator; + +import org.compiere.model.MAccount; +import org.compiere.model.MAcctSchema; +import org.compiere.model.MDepreciationEntry; +import org.compiere.model.MDepreciationExp; +import org.compiere.util.Env; + + +/** + * @author Teo Sarca, SC ARHIPAC SERVICE SRL + * @version $Id$ + * + */ +public class Doc_DepreciationEntry extends Doc +{ + /** + * Constructor + * @param ass accounting schemata + * @param rs record + * @parem trxName trx + */ + public Doc_DepreciationEntry (MAcctSchema as, ResultSet rs, String trxName) + { + super(as, MDepreciationEntry.class, rs, null, trxName); + } // Doc_A_Depreciation_Entry + + /** Posting Type */ + private String m_PostingType = null; + private int m_C_AcctSchema_ID = 0; + + + protected String loadDocumentDetails () + { + MDepreciationEntry entry = (MDepreciationEntry)getPO(); + m_PostingType = entry.getPostingType(); + m_C_AcctSchema_ID = entry.getC_AcctSchema_ID(); + + return null; + } + + private DocLine createLine(MDepreciationExp depexp) + { + if (!depexp.isProcessed()) + return null; + DocLine docLine = new DocLine (depexp, this); + return docLine; + } + + + public BigDecimal getBalance() + { + BigDecimal retValue = Env.ZERO; + return retValue; + } // getBalance + + + public ArrayList createFacts (MAcctSchema as) + { + ArrayList facts = new ArrayList(); + // Other Acct Schema + if (as.getC_AcctSchema_ID() != m_C_AcctSchema_ID) + return facts; + + // create Fact Header + Fact fact = new Fact (this, as, m_PostingType); + + MDepreciationEntry entry = (MDepreciationEntry)getPO(); + Iterator it = entry.getLinesIterator(false); + while(it.hasNext()) + { + MDepreciationExp depexp = it.next(); + DocLine line = createLine(depexp); + BigDecimal expenseAmt = depexp.getExpense(); + // + MAccount dr_acct = MAccount.get(getCtx(), depexp.getDR_Account_ID()); + MAccount cr_acct = MAccount.get(getCtx(), depexp.getCR_Account_ID()); + FactUtil.createSimpleOperation(fact, line, dr_acct, cr_acct, as.getC_Currency_ID(), expenseAmt, false); + } + // + facts.add(fact); + return facts; + } +} + diff --git a/org.adempiere.base/src/org/compiere/acct/FactUtil.java b/org.adempiere.base/src/org/compiere/acct/FactUtil.java new file mode 100644 index 0000000000..309eb15897 --- /dev/null +++ b/org.adempiere.base/src/org/compiere/acct/FactUtil.java @@ -0,0 +1,65 @@ +/** + * + */ +package org.compiere.acct; + +import java.math.BigDecimal; + +import org.compiere.model.MAccount; + +/** + * @author ancu + * + */ +public final class FactUtil +{ + + /** + * Create a simple acct transaction, as fellows: + *
+	 * if signSensitive == true then
+	 * 	if amt >= 0
+	 * 		account_DR	DR			 amt
+	 * 		account_CR		CR		 amt
+	 *	if amt < 0
+	 * 		account_CR	DR			-amt
+	 * 		account_DR		CR		-amt
+	 * if signSensitive == false then:
+	 *		account_DR	DR			 amt
+	 *		account_CR		CR		-amt
+	 *		(same as when signSensitive==true and amt>=0)
+	 * 
+ * Note: + *
    + *
  • Operation index is automatically incremented + *
+ * @param docLine Document line or null + * @param account_DR DR account + * @param account_CR CR account + * @param C_Currency_ID Currency + * @param Amt amount + * @param signSensitive if true, the DR and CR account will switch when amount is negative + * @return resulting two fact lines + * @category arhipac + */ + public static FactLine[] createSimpleOperation ( + Fact fact, + DocLine docLine, + MAccount account_DR, MAccount account_CR, + int C_Currency_ID, BigDecimal amt, boolean signSensitive) + { + FactLine[] lines = new FactLine[2]; + //newTrxIndex(); + if (signSensitive) { + lines[0] = fact.createLine(docLine, account_DR, C_Currency_ID, amt); + lines[1] = fact.createLine(docLine, account_CR, C_Currency_ID, amt.negate()); + } + else { + lines[0] = fact.createLine(docLine, account_DR, C_Currency_ID, amt, null); + lines[1] = fact.createLine(docLine, account_CR, C_Currency_ID, null, amt); + } + //newTrxIndex(); + // + return lines; + } // createLine +} diff --git a/org.adempiere.base/src/org/compiere/model/MAssetClass.java b/org.adempiere.base/src/org/compiere/model/MAssetClass.java new file mode 100644 index 0000000000..5efa563129 --- /dev/null +++ b/org.adempiere.base/src/org/compiere/model/MAssetClass.java @@ -0,0 +1,210 @@ +package org.compiere.model; + +import java.sql.ResultSet; +import java.sql.Timestamp; +import java.util.Calendar; +import java.util.Properties; + +import org.compiere.model.Query; +import org.compiere.util.CCache; +import org.compiere.util.CLogMgt; +import org.compiere.util.Env; +import org.compiere.util.TimeUtil; +import org.idempiere.fa.feature.UseLifeImpl; + +/** Asset Class + * @author Teo Sarca, SC Arhipac SRL + * @version $Id$ + */ +public class MAssetClass extends X_A_Asset_Class +{ + /** + * + */ + public MAssetClass(Properties ctx, int A_Asset_Class_ID, String trxName) + { + super (ctx, A_Asset_Class_ID, trxName); + } // MAssetClass + + /** + * Load Constructor + * @param ctx context + * @param rs result set record + */ + public MAssetClass (Properties ctx, ResultSet rs, String trxName) + { + super (ctx, rs, trxName); + } // MAssetClass + + /** */ + private static CCache s_cache = new CCache("A_Asset_Class", 20); + + /** Get Asset Class from cache + * @param ctx context + * @param id A_Asset_Class_ID + * @return MAssetClass or null if not found + */ + public static MAssetClass get(Properties ctx, int id) { + if (id <= 0) { + return null; + } + + MAssetClass assetClass = s_cache.get(id); + if (assetClass == null) { + assetClass = new MAssetClass(ctx, id, null); + } + if (assetClass.get_ID() != id) { + return null; + } + s_cache.put(id, assetClass); + return assetClass; + } // get + + /** + * + */ + public static MAssetClass get(Properties ctx, String value) + { + // TODO: maybe logging + final String whereClause = "UPPER(Value)=UPPER(?) AND AD_Client_ID IN (0,?)"; + return new Query(ctx, Table_Name, whereClause, null) + .setParameters(new Object[]{value, Env.getAD_Client_ID(ctx)}) + .setOrderBy("AD_Client_ID DESC") + .firstOnly(); + } // get + + /** + * + */ + public void setDescription() { + StringBuffer description = new StringBuffer(); + String value = getValue(); + if (value != null) { + description.append(value).append(" "); + } + + String name = getName(); + if (name != null) { + description.append(name); + } + super.setDescription(description.toString()); + } + + /** + * + */ + public void setLevels() { + setMFX_Grupa(0); + setMFX_SubGrupa(0); + setMFX_Clasa(0); + setMFX_SubClasa(0); + + String value = getValue(); + if (value == null || value.length() == 0) + return; + + String[] arr = value.split("\\."); + try { + if (arr.length >= 1) + setMFX_Grupa(Integer.valueOf(arr[0])); + if (arr.length >= 2) + setMFX_SubGrupa(Integer.valueOf(arr[1])); + if (arr.length >= 3) + setMFX_Clasa(Integer.valueOf(arr[2])); + if (arr.length >= 4) + setMFX_SubClasa(Integer.valueOf(arr[3])); + } catch (NumberFormatException e) { + log.warning("@Error@ @Value@=" + value); + } + } + + /** + * + */ + public int getA_Life_Period_Min(Timestamp serviceDate) { + Calendar cal = TimeUtil.getCalendar(serviceDate); + if (cal.get(Calendar.YEAR) >= 2004) { + return getA_Life_Period_Min(); + } + else { + return getA_Life_Period_2004(); + } + } + + /** Validate */ + public String validate(boolean saveError, int A_Life_Period, Timestamp serviceDate) { + log.fine("Entering"); + int A_Life_Period_Min = 0; + int A_Life_Period_Max = 1000000; + Calendar cal = TimeUtil.getCalendar(serviceDate); + if (cal.get(Calendar.YEAR) >= 2004) { + A_Life_Period_Min = getA_Life_Period_Min(); + A_Life_Period_Max = getA_Life_Period_Max(); + } + else { + A_Life_Period_Min = getA_Life_Period_2004(); + A_Life_Period_Max = getA_Life_Period_2004(); + } + // logging: + if (CLogMgt.isLevelFine()) { + log.fine("serviceDate=" + serviceDate + ", A_Life_Period_Min=" + A_Life_Period_Min + ", A_Life_Period_Max=" + A_Life_Period_Max + ", A_Life_Period=" + A_Life_Period); + } + + + if (A_Life_Period < A_Life_Period_Min || A_Life_Period > A_Life_Period_Max) { + String errmsg = "@UseLifeMonths@=" + A_Life_Period + " @NotBetween@ " + A_Life_Period_Min + " - " + A_Life_Period_Max; + if (saveError) { + log.saveError("Error", errmsg); + } + if(CLogMgt.isLevelFine()) { + log.fine("Leaving: " + errmsg); + Thread.dumpStack(); + } + return errmsg; + } + + log.fine("Leaving: OK!"); + return ""; + } + + /** Validate UseLifeImpl model + */ + public boolean validate(UseLifeImpl asset) { + if(CLogMgt.isLevelFine()) log.fine("Entering: UseLifeImpl=" + asset); + + if (!asset.isFiscal()) { + log.fine("Leaving: fiscal=false [RETURN TRUE]"); + return true; + } + else { + log.fine("asset is fiscal"); + } + + int A_Life_Period = asset.getUseLifeMonths(); + Timestamp serviceDate = asset.getAssetServiceDate(); + String errmsg = validate(true, A_Life_Period, serviceDate); + boolean ok = (errmsg == null || errmsg.length() == 0); + + log.fine("Leaving: ok=" + ok); + return ok; + } + + /** Depreciated check + * + */ + public boolean isDepreciated() { + return !(getA_Life_Period_Min() == 0 && getA_Life_Period_Max() ==0); + } + + /** + * + */ + public boolean beforeSave (boolean newRecord) { + setDescription(); + if (is_ValueChanged("Value")) { + setValue(getValue().trim()); + setLevels(); + } + return true; + } +} diff --git a/org.adempiere.base/src/org/compiere/model/MAssetDisposed.java b/org.adempiere.base/src/org/compiere/model/MAssetDisposed.java new file mode 100644 index 0000000000..5006b86b36 --- /dev/null +++ b/org.adempiere.base/src/org/compiere/model/MAssetDisposed.java @@ -0,0 +1,438 @@ +package org.compiere.model; + +import java.io.File; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.sql.ResultSet; +import java.sql.Timestamp; +import java.util.List; +import java.util.Properties; + +import org.compiere.model.MClient; +import org.compiere.model.MDocType; +import org.compiere.model.MPeriod; +import org.compiere.model.ModelValidationEngine; +import org.compiere.model.ModelValidator; +import org.compiere.process.DocAction; +import org.compiere.process.DocumentEngine; +import org.compiere.util.Env; +import org.idempiere.fa.exceptions.AssetAlreadyDepreciatedException; +import org.idempiere.fa.exceptions.AssetException; +import org.idempiere.fa.exceptions.AssetNotImplementedException; +import org.idempiere.fa.exceptions.AssetNotSupportedException; +import org.idempiere.fa.exceptions.AssetStatusChangedException; +import org.idempiere.fa.feature.UseLifeImpl; +import org.idempiere.fa.util.POCacheLocal; + +import com.sun.enterprise.connectors.util.SetMethodAction; + + + +/** + * Asset Disposal Model + * @author Teo Sarca, SC ARHIPAC SERVICE SRL + */ +public class MAssetDisposed extends X_A_Asset_Disposed +implements DocAction +{ + /** + * + */ + private static final long serialVersionUID = 1763997880662445638L; + + public MAssetDisposed (Properties ctx, int A_Asset_Disposed_ID, String trxName) + { + super (ctx, A_Asset_Disposed_ID, trxName); + if (A_Asset_Disposed_ID == 0) + { + setProcessed (false); + setProcessing (false); + } + + } + + //@win: autocreate asset disposal from ar invoice + public static MAssetDisposed createAssetDisposed (MInvoiceLine invLine) { + MAssetDisposed assetDisposed = new MAssetDisposed(invLine); + assetDisposed.dump(); + return assetDisposed; + } + + private MAssetDisposed (MInvoiceLine invLine) { + this(invLine.getCtx(),0,invLine.get_TrxName()); + log.finest("Entering: Project=" + invLine); + setAD_Org_ID(invLine.getAD_Org_ID()); + setPostingType(POSTINGTYPE_Actual); + setDateDoc(invLine.getC_Invoice().getDateInvoiced()); + setDateAcct(invLine.getC_Invoice().getDateInvoiced()); + setA_Disposed_Date(invLine.getC_Invoice().getDateInvoiced()); + setA_Disposed_Method(A_DISPOSED_METHOD_Trade); + setA_Asset_ID(invLine.getA_Asset_ID()); + set_ValueNoCheck("C_Invoice_ID", invLine.getC_Invoice_ID()); + setM_InvoiceLine(invLine); + saveEx(invLine.get_TrxName()); + } + + private final POCacheLocal m_cacheInvoiceLine = POCacheLocal.newInstance(this, MInvoiceLine.class); + public MInvoiceLine getM_InvoiceLine(boolean requery) + { + return m_cacheInvoiceLine.get(requery); + } + private void setM_InvoiceLine(MInvoiceLine invLine) + { + set_Value("C_InvoiceLine_ID", invLine.get_ID()); + m_cacheInvoiceLine.set(invLine); + } + //end @win: autocreate asset disposal from ar invoice + + public MAssetDisposed (Properties ctx, ResultSet rs, String trxName) + { + super (ctx, rs, trxName); + } + + public MAsset getAsset() + { + return MAsset.get(getCtx(), getA_Asset_ID(), null); + } + + + public boolean processIt (String processAction) + { + m_processMsg = null; + DocumentEngine engine = new DocumentEngine (this, getDocStatus()); + return engine.processIt (processAction, getDocAction()); + } // processIt + + /** Process Message */ + private String m_processMsg = null; + /** Just Prepared Flag */ + private boolean m_justPrepared = false; + + + public boolean unlockIt() + { + setProcessing(false); + return true; + } // unlockIt + + + public boolean invalidateIt() + { + return false; + } // invalidateIt + + + public String prepareIt() + { + m_processMsg = ModelValidationEngine.get().fireDocValidate(this, ModelValidator.TIMING_BEFORE_PREPARE); + if (m_processMsg != null) + { + return DocAction.STATUS_Invalid; + } + + MPeriod.testPeriodOpen(getCtx(), getDateAcct(), MDocType.DOCBASETYPE_GLDocument, getAD_Org_ID()); + + //saveEx() //commented by @win + updateFromAsset(this); + saveEx(get_TrxName()); //added by @win + if (is_Changed()) + { + throw new AssetStatusChangedException(); + } + + // Check that the FA is not just depreciated + MDepreciationWorkfile assetwk = MDepreciationWorkfile.get(getCtx(), getA_Asset_ID(), getPostingType(), get_TrxName()); + if (assetwk.isDepreciated(getDateAcct())) + { + throw new AssetAlreadyDepreciatedException(); + } + MDepreciationExp.checkExistsNotProcessedEntries(getCtx(), getA_Asset_ID(), getDateAcct(), getPostingType(), get_TrxName()); + + m_processMsg = ModelValidationEngine.get().fireDocValidate(this, ModelValidator.TIMING_AFTER_PREPARE); + if (m_processMsg != null) + { + return DocAction.STATUS_Invalid; + } + // + m_justPrepared = true; + setDocAction(DOCACTION_Complete); + return DocAction.STATUS_InProgress; + } // prepareIt + + + public boolean approveIt() + { + log.info("approveIt - " + toString()); + setIsApproved(true); + return true; + } // approveIt + + + public boolean rejectIt() + { + log.info("rejectIt - " + toString()); + setIsApproved(false); + return true; + } // rejectIt + + + public String completeIt() + { + // Re-Check + if (!m_justPrepared) + { + String status = prepareIt(); + if (!DocAction.STATUS_InProgress.equals(status)) + return status; + } + + String valid = ModelValidationEngine.get().fireDocValidate(this, ModelValidator.TIMING_BEFORE_COMPLETE); + if (valid != null) + { + m_processMsg = valid; + return DocAction.STATUS_Invalid; + } + + // Implicit Approval + if (!isApproved()) + approveIt(); + log.info(toString()); + // + + //loading asset + MAsset asset = getAsset(); + log.fine("asset=" + asset); + + // Activation + if(!isDisposal()) + { + String method = getA_Activation_Method(); + if(method.equals(A_ACTIVATION_METHOD_Activation)) + { // reactivation + asset.changeStatus(MAsset.A_ASSET_STATUS_Activated, getDateDoc()); + } + else + { + throw new AssetNotSupportedException(COLUMNNAME_A_Activation_Method, method); + } + } + // Preservation/Partial Retirement/etc + else + { + String method = getA_Disposed_Method(); + if (A_DISPOSED_METHOD_Preservation.equals(method)) + { + asset.changeStatus(MAsset.A_ASSET_STATUS_Preservation, getDateDoc()); + } + else if (A_DISPOSED_METHOD_Simple.equals(method) + || A_DISPOSED_METHOD_Trade.equals(method) + ) + { + asset.changeStatus(MAsset.A_ASSET_STATUS_Disposed, null); + setA_Disposal_Amt(getA_Asset_Cost()); + setA_Accumulated_Depr_Delta(getA_Accumulated_Depr()); + setExpense(getA_Disposal_Amt().subtract(getA_Accumulated_Depr_Delta())); + createDisposal(); + } + else if (A_DISPOSED_METHOD_PartialRetirement.equals(method)) + { + createDisposal(); + } + else + { + throw new AssetNotSupportedException(COLUMNNAME_A_Disposed_Method, method); + } + } + + asset.saveEx(get_TrxName()); + + + // User Validation + valid = ModelValidationEngine.get().fireDocValidate(this, ModelValidator.TIMING_AFTER_COMPLETE); + if (valid != null) + { + m_processMsg = valid; + return DocAction.STATUS_Invalid; + } + + // Done + setProcessed(true); + setDocAction(DOCACTION_Close); + return DocAction.STATUS_Completed; + } // completeIt + + + public boolean voidIt() + { + throw new AssetNotImplementedException(""); + } // voidIt + + + public boolean closeIt() + { + setDocAction(DOCACTION_None); + return true; + } // closeIt + + + public boolean reverseCorrectIt() + { + throw new AssetNotImplementedException(""); + } // reverseCorrectionIt + + + public boolean reverseAccrualIt() + { + throw new AssetNotImplementedException(""); + } + + + public boolean reActivateIt() + { + throw new AssetNotImplementedException(""); + } + + + + public String getSummary() + { + return new StringBuffer() + .append(getDocumentNo()).append("/").append(getDateDoc()) + .toString(); + } + + + public String getProcessMsg() + { + return m_processMsg; + } // getProcessMsg + + + public int getDoc_User_ID() + { + return getCreatedBy(); + } + + + public BigDecimal getApprovalAmt() + { + return Env.ZERO; + } + + + public int getC_Currency_ID() + { + return MClient.get(getCtx(), getAD_Client_ID()).getAcctSchema().getC_Currency_ID(); + } + + + protected boolean beforeSave (boolean newRecord) + { + if (getDateAcct() == null) + { + setDateAcct(getDateDoc()); + } + if (newRecord || is_ValueChanged(COLUMNNAME_DateAcct)) + { + setC_Period_ID(MPeriod.get(getCtx(), getDateAcct(), getAD_Org_ID()).get_ID()); + } + if (getA_Disposed_Date() == null) + { + setA_Disposed_Date(getDateAcct()); + } + /* commented by @win - asset type + if (!MAssetType.isFixedAsset(getA_Asset_ID())) + { + throw new AssetException("This is not a Fixed Asset!"); + } + */ + return true; + } + + /** + * Copy fields from A_Asset + * @param model + * @param A_Asset_ID + */ + public static void updateFromAsset(I_A_Asset_Disposed bean) + { + int asset_id = bean.getA_Asset_ID(); + SetGetUtil.copyValues( + SetGetUtil.wrap(bean), + MAsset.Table_Name, asset_id, + new String[] { + MAsset.COLUMNNAME_IsDisposed, + MAsset.COLUMNNAME_A_Asset_Status, + "AD_Org_ID", + } + ); + + MDepreciationWorkfile wk = MDepreciationWorkfile.get(Env.getCtx(), asset_id, bean.getPostingType(), null); + if (wk != null) + { + bean.setA_Asset_Cost(wk.getA_Asset_Cost()); + bean.setA_Accumulated_Depr(wk.getA_Accumulated_Depr()); + } + else + { + bean.setA_Asset_Cost(Env.ZERO); + bean.setA_Accumulated_Depr(Env.ZERO); + } + } + + + public File createPDF () + { + return null; + } // createPDF + + + public String getDocumentInfo() + { + return getDocumentNo(); + } // getDocumentInfo + + /** + * Check if this is a disposal (if the asset is not disposed) + * @return true if is disposal + */ + public boolean isDisposal() + { + return !isDisposed(); + } + + public static void setA_Disposal_Amt(I_A_Asset_Disposed bean) + { + int precision = 2; + BigDecimal A_Asset_Cost = bean.getA_Asset_Cost(); + BigDecimal A_Disposal_Amt = bean.getA_Disposal_Amt(); + BigDecimal coef = Env.ZERO; + if (A_Asset_Cost.signum() != 0) + { + coef = A_Disposal_Amt.divide(A_Asset_Cost, 12, RoundingMode.HALF_UP); + } + // + BigDecimal A_Accumulated_Depr = bean.getA_Accumulated_Depr(); + BigDecimal A_Accumulated_Depr_Delta = A_Accumulated_Depr.multiply(coef).setScale(precision, RoundingMode.HALF_UP); + BigDecimal Expense = A_Disposal_Amt.subtract(A_Accumulated_Depr_Delta); + // + bean.setA_Accumulated_Depr_Delta(A_Accumulated_Depr_Delta); + bean.setExpense(Expense); + } + + private void createDisposal() + { + MDepreciationWorkfile assetwk = MDepreciationWorkfile.get(getCtx(), getA_Asset_ID(), getPostingType(), get_TrxName()); + assetwk.adjustCost(getA_Disposal_Amt().negate(), Env.ZERO, false); + assetwk.adjustAccumulatedDepr(getA_Accumulated_Depr_Delta().negate(), getA_Accumulated_Depr_Delta().negate(), false); + assetwk.saveEx(); + assetwk.buildDepreciation(); + // + // Delete not processed expense entries + List list = MDepreciationExp.getNotProcessedEntries(getCtx(), getA_Asset_ID(), getPostingType(), get_TrxName()); + for (MDepreciationExp ex : list) + { + ex.deleteEx(false); + } + } +} diff --git a/org.adempiere.base/src/org/compiere/model/MAssetProduct.java b/org.adempiere.base/src/org/compiere/model/MAssetProduct.java new file mode 100644 index 0000000000..8c5a15e56f --- /dev/null +++ b/org.adempiere.base/src/org/compiere/model/MAssetProduct.java @@ -0,0 +1,93 @@ +package org.compiere.model; + +import java.math.BigDecimal; +import java.sql.ResultSet; +import java.util.Properties; + +import org.compiere.model.Query; + +/** + * Asset Product + * @author Teo Sarca, SC ARHIPAC SERIVCE SRL + */ +public class MAssetProduct extends X_A_Asset_Product +{ + private static final long serialVersionUID = 1L; + + /** Standard Constructor */ + public MAssetProduct (Properties ctx, int A_Asset_Product_ID, String trxName) + { + super (ctx, A_Asset_Product_ID, trxName); + } + + /** Load Constructor */ + public MAssetProduct (Properties ctx, ResultSet rs, String trxName) + { + super (ctx, rs, trxName); + } + + /** + * Set product and ASI + * @param M_Product_ID + * @param M_ASI_ID + */ + public void setProduct(int M_Product_ID, int M_ASI_ID) + { + setM_Product_ID(M_Product_ID); + setM_AttributeSetInstance_ID(M_ASI_ID); + } + + /** + * Get/Create Asset Product. + * Doesn't save newly create one. + * @param ctx + * @param A_Asset_ID + * @param M_Product_ID + * @param M_ASI_ID + * @param trxName + * @return MAssetProduct + */ + public static MAssetProduct getCreate(Properties ctx, + int A_Asset_ID, int M_Product_ID, int M_ASI_ID, + String trxName) + { + if (M_Product_ID <= 0) { + return null; + } + final String whereClause = COLUMNNAME_A_Asset_ID + "=?" + + " AND " + COLUMNNAME_M_Product_ID + "=?" + + " AND " + COLUMNNAME_M_AttributeSetInstance_ID + "=?"; + MAssetProduct ap = new Query(ctx, MAssetProduct.Table_Name, whereClause, trxName) + .setParameters(new Object[]{A_Asset_ID, M_Product_ID, M_ASI_ID}) + .firstOnly(); + // If found, return + if (ap != null) + return ap; + + // Create new + ap = new MAssetProduct(ctx, 0, trxName); + ap.setA_Asset_ID(A_Asset_ID); + ap.setProduct(M_Product_ID, M_ASI_ID); + + return ap; + } // get + + /** + * Add given qty to current qty + * @param qty + */ + public void addA_Qty_Current(BigDecimal qty) + { + setA_QTY_Current(getA_QTY_Current().add(qty)); + } + + /** + * Update given asset. + * Note: does not save asset + */ + public void updateAsset(MAsset asset) + { + asset.setM_Product_ID(getM_Product_ID()); + asset.setM_AttributeSetInstance_ID(getM_AttributeSetInstance_ID()); + } +} diff --git a/org.adempiere.base/src/org/compiere/model/MAssetReval.java b/org.adempiere.base/src/org/compiere/model/MAssetReval.java new file mode 100644 index 0000000000..2241df3cf5 --- /dev/null +++ b/org.adempiere.base/src/org/compiere/model/MAssetReval.java @@ -0,0 +1,258 @@ +/** + * + */ +package org.compiere.model; + +import java.io.File; +import java.math.BigDecimal; +import java.sql.ResultSet; +import java.sql.Timestamp; +import java.util.Properties; + +import org.adempiere.exceptions.AdempiereException; +import org.compiere.model.MDocType; +import org.compiere.model.MPeriod; +import org.compiere.model.ModelValidationEngine; +import org.compiere.model.ModelValidator; +import org.compiere.process.DocAction; +import org.compiere.process.DocumentEngine; +import org.compiere.util.Env; +import org.compiere.util.TimeUtil; + + +/** + * @author Anca Bradau www.arhipac.ro + * + */ +public class MAssetReval extends X_A_Asset_Reval +implements DocAction +{ + private static final long serialVersionUID = 1L; + + private boolean m_justPrepared = false; + + public MAssetReval(Properties ctx, int X_A_Asset_Reval_ID, String trxName) + { + super(ctx, X_A_Asset_Reval_ID, trxName); + if (X_A_Asset_Reval_ID == 0) + { + setDocStatus(DOCSTATUS_Drafted); + setDocAction(DOCACTION_Complete); + setProcessed(false); + } + } + public MAssetReval(Properties ctx, ResultSet rs, String trxName) + { + super (ctx, rs, trxName); + } + + public boolean approveIt() + { + return false; + } + + public boolean closeIt() { + setDocAction(DOCACTION_None); + return true; + } + + public String prepareIt() + { + m_processMsg = ModelValidationEngine.get().fireDocValidate(this, ModelValidator.TIMING_BEFORE_PREPARE); + if (m_processMsg != null) + { + return DocAction.STATUS_Invalid; + } + // test if period is open + MPeriod.testPeriodOpen(getCtx(), getDateAcct(), MDocType.DOCBASETYPE_GLJournal, getAD_Org_ID()); + + // test if asset is already Depreciated + MDepreciationWorkfile assetwk = MDepreciationWorkfile.get(getCtx(), getA_Asset_ID(), getPostingType()); + + if (!assetwk.isDepreciated(getDateAcct())) + { + throw new AdempiereException("Asset is not depreciated at this moment"); + + } + + // test if Asset Cost and Accumulated Depreciation are changed + if (assetwk.getA_Asset_Cost().equals(getA_Asset_Cost_Change()) + && assetwk.getA_Accumulated_Depr().equals(getA_Change_Acumulated_Depr())) + { + throw new AdempiereException("Nothing has changed"); + } + + //test if Asset Cost is changed + if (assetwk.getA_Asset_Cost().equals(getA_Asset_Cost_Change()) + && !assetwk.getA_Accumulated_Depr().equals(getA_Change_Acumulated_Depr())) + { + throw new AdempiereException("It has changed the cost of Asset"); + } + + // test if Accumulated depreciation is changed + if (!assetwk.getA_Asset_Cost().equals(getA_Asset_Cost_Change()) + && assetwk.getA_Accumulated_Depr().equals(getA_Change_Acumulated_Depr())) + { + throw new AdempiereException("It has changed the cumulative depreciation"); + } + + if (!isLastDepreciated(getDateAcct())) + { + throw new AdempiereException("It can only review the last month processed"); + } + + m_processMsg = ModelValidationEngine.get().fireDocValidate(this, ModelValidator.TIMING_AFTER_PREPARE); + if (m_processMsg != null) + return DocAction.STATUS_Invalid; + + m_justPrepared = true; + if (!DOCACTION_Complete.equals(getDocAction())) + setDocAction(DOCACTION_Complete); + return DocAction.STATUS_InProgress; + } + //return true if is last record depreciated + public boolean isLastDepreciated(Timestamp date) + { + MDepreciationWorkfile assetwk = MDepreciationWorkfile.get(getCtx(), getA_Asset_ID(), getPostingType()); + Timestamp lastActionDate = assetwk.getLastActionDate(); + boolean isLastDepr = TimeUtil.getMonthLastDay(date).equals(lastActionDate); + return isLastDepr; + + } + + public String completeIt() { + + if (!m_justPrepared) + { + String status = prepareIt(); + if (!DocAction.STATUS_InProgress.equals(status)) + return status; + } + + + m_processMsg = ModelValidationEngine.get().fireDocValidate(this, ModelValidator.TIMING_BEFORE_COMPLETE); + if (m_processMsg != null) + return DocAction.STATUS_Invalid; + + MDepreciationWorkfile assetwk = MDepreciationWorkfile.get(getCtx(), getA_Asset_ID(), getPostingType(), get_TrxName()); + assetwk.setA_Asset_Cost(getA_Asset_Cost_Change()); + assetwk.setA_Accumulated_Depr(getA_Change_Acumulated_Depr()); + assetwk.saveEx(); + MAsset asset = MAsset.get(getCtx(), getA_Asset_ID(), get_TrxName()); + asset.setA_Asset_RevalDate(this.getDateDoc()); + asset.saveEx(); + //rebuild depreciation + /* commented out by @win, deprecating existing design + assetwk.buildDepreciation(); + */ + + // User Validation + String valid = ModelValidationEngine.get().fireDocValidate(this, ModelValidator.TIMING_AFTER_COMPLETE); + if (valid != null) + { + m_processMsg = valid; + return DocAction.STATUS_Invalid; + } + + // Set the definite document number after completed (if needed) + //setDefiniteDocumentNo(); + + setProcessed(true); + setDocAction(DOCACTION_Close); + return DocAction.STATUS_Completed; + } + + public File createPDF() + { + return null; + } + + public BigDecimal getApprovalAmt() + { + return Env.ZERO; + } + + public int getC_Currency_ID() + { + return 0; + } + + public int getDoc_User_ID() + { + return getCreatedBy(); + } + + public String getDocumentInfo() + { + return getDocumentNo() + "/" + getDateAcct(); + } + + public String getProcessMsg() { + return m_processMsg; + } + private String m_processMsg = null; + + + public String getSummary() + { + StringBuffer sb = new StringBuffer(); + sb.append("@DocumentNo@ #").append(getDocumentNo()); + return sb.toString(); + } + + public boolean invalidateIt() + { + return false; + } + + public boolean processIt(String action) throws Exception + { + m_processMsg = null; + DocumentEngine engine = new DocumentEngine (this, getDocStatus()); + return engine.processIt (action, getDocAction()); + } + + + public boolean reActivateIt() + { + return false; + } + + public boolean rejectIt() + { + return false; + } + + public boolean reverseAccrualIt() + { + return false; + } + + public boolean reverseCorrectIt() + { + return false; + } + + public boolean unlockIt() + { + return false; + } + + public boolean voidIt() + { + return false; + } + public String getDocumentNo() + { + return null; + } + /** Before save + * @param newRecord + * @return true on success + */ + //protected boolean beforeSave (boolean newRecord) + //{ + //return true; + //} + +} diff --git a/org.adempiere.base/src/org/compiere/model/MAssetType.java b/org.adempiere.base/src/org/compiere/model/MAssetType.java new file mode 100644 index 0000000000..e70ed6c7c0 --- /dev/null +++ b/org.adempiere.base/src/org/compiere/model/MAssetType.java @@ -0,0 +1,231 @@ +package org.compiere.model; + +import java.sql.ResultSet; +import java.util.Properties; + +import org.compiere.model.CalloutEngine; +import org.compiere.model.GridField; +import org.compiere.model.GridTab; +import org.compiere.model.Query; +import org.compiere.util.ArhRuntimeException; +import org.compiere.util.CCache; +import org.compiere.util.Env; + +/** + * Asset Type + * @author Teo Sarca, SC ARHIPAC SERVICE SRL + */ +public class MAssetType extends X_A_Asset_Type +{ + private static final long serialVersionUID = 1L; + + public static final String A_ASSET_TYPE_MFX = "MFX"; + public static final String A_ASSET_TYPE_INV = "INV"; + + public static final int A_ASSET_TYPE_ID_MFX = 1; + public static final int A_ASSET_TYPE_ID_INV = 2; + public static final int A_ASSET_TYPE_ID_SUP = 3; + /** Obiecte tert */ + public static final int A_ASSET_TYPE_ID_OIN = 4; + + public static interface Model + { + /** Get Context */ + public Properties getCtx(); + /** Get Asset Type */ + public int getA_Asset_Type_ID(); + /** Get In Possession. The asset is in the possession of the organization */ + public boolean isInPosession(); + /** Get Owned. The asset is owned by the organization */ + public boolean isOwned(); + /** Get Is Depreciated */ + public boolean isDepreciated(); + }; + + /** Static Cache: A_Asset_Type.A_Asset_Type_ID-> MAssetType */ + private static CCache s_cache = new CCache(Table_Name, 10, 0); + + /** Get Asset Type + * @param ctx context + * @param A_Asset_Type_ID + * @return asset type object + */ + public static MAssetType get (Properties ctx, int A_Asset_Type_ID) + { + if (A_Asset_Type_ID <= 0) + return null; + MAssetType o = s_cache.get(A_Asset_Type_ID); + if (o != null) + return o; + o = new MAssetType(ctx, A_Asset_Type_ID, null); + if (o.get_ID() > 0) { + s_cache.put(A_Asset_Type_ID, o); + return o; + } + return null; + } + + /** Get Asset Type + * @param ctx context + * @param id id as Number + * @return asset type object + */ + public static MAssetType get (Properties ctx, Object id) + { + if (id == null) + return null; + return get(ctx, ((Number)id).intValue()); + } + + /** Standard Constructor */ + public MAssetType (Properties ctx, int A_Asset_Type_ID, String trxName) + { + super (ctx, A_Asset_Type_ID, trxName); + } + + /** Load Constructor */ + public MAssetType (Properties ctx, ResultSet rs, String trxName) + { + super (ctx, rs, trxName); + } + + /** Is Fixed Asset + */ + public boolean isFixedAsset() + { + return A_ASSET_TYPE_MFX.equals(getValue()); + } + + public static boolean isFixedAsset(int A_Asset_ID) + { + final String whereClause = MAsset.COLUMNNAME_A_Asset_ID+"=?" + +" AND "+MAsset.COLUMNNAME_A_Asset_Type+"=?"; + + return new Query(Env.getCtx(), MAsset.Table_Name, whereClause, null) + .setParameters(new Object[]{A_Asset_ID, A_ASSET_TYPE_MFX}) + .match(); + } + + public static boolean isFixedAsset(MAsset asset) + { + return asset != null && A_ASSET_TYPE_MFX.equals(asset.getA_Asset_Type()); + } + + public static boolean isFixedAssetGroup(Properties ctx, int A_Asset_Group_ID) + { + if (A_Asset_Group_ID <= 0) + return false; + MAssetGroup assetGroup = MAssetGroup.get(ctx, A_Asset_Group_ID); + // + int assetType_ID = assetGroup.getA_Asset_Type_ID(); + if (assetType_ID <= 0) + return false; + MAssetType assetType = MAssetType.get(ctx, assetType_ID); + // + return assetType.isFixedAsset(); + } + + /** Is Inventory Object + */ + public boolean isInventoryObject() { + return A_ASSET_TYPE_INV.equals(getValue()); + } + + /** Convert an Yes-No-Unknown field to Boolean */ + protected static Boolean getBoolean (String value, boolean useDefaults) + { + if (value == null || value.length() == 0) + return null; + String f = value.substring(0, 1); + if ("N".equals(f)) + return Boolean.FALSE; + else if ("Y".equals(f)) + return Boolean.TRUE; + else if ("X".equals(f) && useDefaults) + return getBoolean(value.substring(1), false); + else + return null; + } + + /** + * Validate a Model + * @param m model + * @thorows ContextUserException + */ + public static void validate(Model m) + { + // Load Asset Type + MAssetType assetType = MAssetType.get(m.getCtx(), m.getA_Asset_Type_ID()); + if (assetType == null) + { + throw new ArhRuntimeException(m.getCtx(), "@NotFound@ @A_Asset_Type_ID@") + .addInfo("@A_Asset_Type_ID", m.getA_Asset_Type_ID()); + } + + ArhRuntimeException err = new ArhRuntimeException(m.getCtx(), ""); + Boolean f = getBoolean(assetType.getIsOwned(), false); + if (f != null && f.booleanValue() != m.isOwned()) { + err.addInfo("@IsOwned@ <> @" + f + "@"); + } + f = getBoolean(assetType.getIsInPosession(), false); + if (f != null && f.booleanValue() != m.isInPosession()) { + err.addInfo("@IsInPosession@ <> @" + f + "@"); + } + f = getBoolean(assetType.getIsDepreciable(), false); + if (f != null && f.booleanValue() != m.isDepreciated()) { + err.addInfo("@IsDepreciated@ <> @" + f + "@"); + } + + if (err.hasInfo()) + throw err; + } + + /** + * Update the given SetGetModel; Does not set A_Asset_Type_ID + * @param model + * @param useDefaults in case is not a concrete value, use defaults + */ + public boolean update(SetGetModel model, boolean useDefaults) + { +// boolean useDefaults = true; + Boolean f = getBoolean(getIsOwned(), useDefaults); + if (f != null) + model.set_AttrValue("IsOwned", f); + f = getBoolean(getIsInPosession(), useDefaults); + if (f != null) + model.set_AttrValue("IsInPosession", f); + f = getBoolean(getIsDepreciable(), useDefaults); + if (f != null) { + model.set_AttrValue("IsDepreciated", f); + } + + if (!isFixedAsset()) { + model.set_AttrValue("A_Asset_Class_ID", null); + } + + model.set_AttrValue("A_Asset_Type", getValue()); + + return true; + } + + /** Callout Class */ + public static class Callout extends CalloutEngine + { + public String assetType(Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value) { + if (isCalloutActive()) + return ""; + + int A_Asset_Type_ID = 0; + if (value != null && value instanceof Number) + A_Asset_Type_ID = ((Number)value).intValue(); + else + return ""; + MAssetType assetType = MAssetType.get(ctx, A_Asset_Type_ID); + if (assetType != null) + assetType.update(SetGetUtil.wrap(mTab), true); + // + return ""; + } + }; + +} // class MAssetType diff --git a/org.adempiere.base/src/org/compiere/model/MConversionRateUtil.java b/org.adempiere.base/src/org/compiere/model/MConversionRateUtil.java new file mode 100644 index 0000000000..7ebf89f471 --- /dev/null +++ b/org.adempiere.base/src/org/compiere/model/MConversionRateUtil.java @@ -0,0 +1,103 @@ +/** + * + */ +package org.compiere.model; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.sql.Timestamp; + +import org.compiere.util.CLogMgt; +import org.compiere.util.CLogger; +import org.compiere.util.Env; +import org.idempiere.exceptions.NoCurrencyConversionException; + +/** + * @author Teo Sarca, SC ARHIPAC SERVICE SRL + */ +public final class MConversionRateUtil +{ + /** Logger */ + private static final CLogger s_log = CLogger.getCLogger (MConversionRateUtil.class); + + private MConversionRateUtil() + { + // nothing + } + + /** + * Convert an amount to base currency and update model fields (CurrencyRate, "AmtName"). + * @param model + * @param DateName conversion date field name + * @param SourceAmtName source amount field name + * @param AmtName converted amount field name (optional); if null then the converted amount field will not be updated + * @param changedColumnName the column that has changed (the controller); optional + * @return converted amount or null if error + */ + public static BigDecimal convertBase(SetGetModel model, String DateName, + String SourceAmtName, String AmtName, String changedColumnName) + { + // If Currency changed, reset rate + if (changedColumnName != null && "C_Currency_ID".equalsIgnoreCase(changedColumnName)) + { + model.set_AttrValue("CurrencyRate", Env.ZERO); + } + + // Source Amount + BigDecimal sourceAmt = SetGetUtil.get_AttrValueAsBigDecimal(model, SourceAmtName); + if (sourceAmt == null || sourceAmt.signum() == 0) + { + if (AmtName != null) + { + model.set_AttrValue(AmtName, Env.ZERO); + } + return Env.ZERO; + } + + // AD_Client_ID + int AD_Client_ID = SetGetUtil.get_AttrValueAsInt(model, "AD_Client_ID"); + + // Currency To + int C_Currency_ID_To = MClient.get(model.getCtx(), AD_Client_ID).getAcctSchema().getC_Currency_ID(); + //~ model.set_AttrValue("C_Currency_ID_To", Integer.valueOf(C_Currency_ID_To)); + + // Get Rate + BigDecimal rate = SetGetUtil.get_AttrValueAsBigDecimal(model, "CurrencyRate"); + if (rate == null || rate.signum() == 0) + { + int AD_Org_ID = SetGetUtil.get_AttrValueAsInt(model, "AD_Client_ID"); + Timestamp ConvDate = SetGetUtil.get_AttrValueAsDate(model, DateName); + int C_Currency_ID = SetGetUtil.get_AttrValueAsInt(model, "C_Currency_ID"); + if (C_Currency_ID == C_Currency_ID_To) + { + rate = Env.ONE; + } + else + { + int C_ConversionType_ID = SetGetUtil.get_AttrValueAsInt(model, "C_ConversionType_ID"); + rate = MConversionRate.getRate (C_Currency_ID, C_Currency_ID_To, + ConvDate, C_ConversionType_ID, + AD_Client_ID, AD_Org_ID); + if (rate == null) + { // NoCurrencyConversion + throw new NoCurrencyConversionException(C_Currency_ID, C_Currency_ID_To, + ConvDate, C_ConversionType_ID, + AD_Client_ID, AD_Org_ID); + } + } + } + model.set_AttrValue("CurrencyRate", rate); + + // Calculate converted amount + BigDecimal amt = sourceAmt.multiply(rate); + int stdPrecision = MCurrency.getStdPrecision(model.getCtx(), C_Currency_ID_To); + amt = amt.setScale(stdPrecision, RoundingMode.HALF_UP); + + // Update model + if (AmtName != null) + model.set_AttrValue(AmtName, amt); + // Return amt + if (CLogMgt.isLevelFine()) s_log.fine("amt=" + sourceAmt + " * " + rate + "=" + amt + ", scale=" + stdPrecision); + return amt; + } // convert +} diff --git a/org.adempiere.base/src/org/compiere/model/MDepreciation.java b/org.adempiere.base/src/org/compiere/model/MDepreciation.java new file mode 100644 index 0000000000..0baf94cd4a --- /dev/null +++ b/org.adempiere.base/src/org/compiere/model/MDepreciation.java @@ -0,0 +1,462 @@ +package org.compiere.model; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.sql.ResultSet; +import java.util.Properties; +import java.util.logging.Logger; + +import org.compiere.model.Query; +import org.compiere.util.CCache; +import org.compiere.util.CLogMgt; +import org.compiere.util.CLogger; +import org.compiere.util.Env; +import org.idempiere.fa.exceptions.AssetNotImplementedException; +import org.idempiere.fa.exceptions.AssetNotSupportedException; + + +/** + * Depreciation Engine (eg. SL, ARH_VAR ...) + * @author Teo Sarca, SC ARHIPAC SERVICE SRL + */ +public class MDepreciation extends X_A_Depreciation +{ + private static final long serialVersionUID = 1L; + + /** Standard Constructor */ + public MDepreciation (Properties ctx, int A_Depreciation_ID, String trxName) + { + super (ctx, A_Depreciation_ID, trxName); + } // MDepreciation + + /** + * Load Constructor + * @param ctx context + * @param rs result set record + */ + public MDepreciation (Properties ctx, ResultSet rs, String trxName) + { + super (ctx, rs, trxName); + } // MDepreciation + + /** Cache */ + private static CCache + s_cache = new CCache(Table_Name, 5); + /** Cache for type */ + private static CCache + s_cache_forType = new CCache(Table_Name+"_DepreciationType", 5); + /** Static logger */ + private static Logger s_log = CLogger.getCLogger(MDepreciation.class); + /** The accuracy of calculation on depreciation */ + private final static int m_precision = 2; + + /* Constrants */ + private static final BigDecimal BD_12 = BigDecimal.valueOf(12); + + private static void addToCache(MDepreciation depr) + { + if (depr == null) + { + return ; + } + + s_cache.put(depr.get_ID(), depr); + String key = "" + depr.getAD_Client_ID() + "_" + depr.getDepreciationType(); + s_cache_forType.put(key, depr); + } + + /** + * Get Depreciation method + * @param ctx + * @param A_Depreciation_ID depreciation id + */ + public static MDepreciation get(Properties ctx, int A_Depreciation_ID) + { + MDepreciation depr = s_cache.get(A_Depreciation_ID); + if (depr != null) + { + return depr; + } + depr = new MDepreciation(ctx, A_Depreciation_ID, null); + if (depr.get_ID() > 0) + { + addToCache(depr); + } + else + { + depr = null; + } + return depr; + } // get + + /** + * Get Depreciation method + * @param ctx + * @param depreciationType depreciation type (e.g. SL) + */ + public static MDepreciation get(Properties ctx, String depreciationType) + { + int AD_Client_ID = Env.getAD_Client_ID(ctx); + String key = "" + AD_Client_ID + "_" + depreciationType; + MDepreciation depr = s_cache_forType.get(key); + if (depr != null) + { + return depr; + } + + final String whereClause = COLUMNNAME_DepreciationType+"=?" + +" AND AD_Client_ID IN (0,?)"; + depr = new Query(ctx, Table_Name, whereClause, null) + .setOrderBy("AD_Client_ID DESC") + .setParameters(new Object[]{depreciationType, AD_Client_ID}) + .firstOnly(); + addToCache(depr); + return depr; + } // get + + /** + * Returns the precision of calculation of depreciation + * @return accuracy of calculation of depreciation + */ + public static int getPrecision() + { + return m_precision; + } + + /** + * Needs to be adjusted in last month's amortization + */ + public boolean requireLastPeriodAdjustment() + { + return !"ARH_ZERO".equals(getDepreciationType()); + } + + /** + * Calculate the value of depreciation over time + * @param assetwk - Fixed Assets worksheet + * @param assetAcct - FA default accounting elements + * @param A_Current_Period - current period + * @param Accum_Dep accumulated depreciation until present period + * @return amortized value + */ + public BigDecimal invoke(MDepreciationWorkfile assetwk, MAssetAcct assetAcct, + int A_Current_Period, BigDecimal Accum_Dep) + { + String depreciationType = getDepreciationType(); + BigDecimal retValue = null; + //~ int offset = getFixMonthOffset(); + //~ A_Current_Period += offset; + + if(CLogMgt.isLevelFinest()) + { + log.fine("Entering: DepreciationType=" + depreciationType + + ", assetwk=" + assetwk+ ", assetacct=" + assetAcct + + ", A_Current_Period=" + A_Current_Period //+ " (offset=" + offset + ")" + + ", Accum_Dep=" + Accum_Dep + ); + } + + if (!canInvoke(assetwk, assetAcct, A_Current_Period, Accum_Dep)) + { + return BigDecimal.ZERO; + } + if (depreciationType.equalsIgnoreCase("SL")) + { + retValue = apply_SL(assetwk, assetAcct, A_Current_Period, Accum_Dep); + } + else if (depreciationType.equalsIgnoreCase("ARH_VAR")) + { + retValue = apply_ARH_VAR(assetwk, assetAcct, A_Current_Period, Accum_Dep); + } + else if (depreciationType.equalsIgnoreCase("ARH_AD1")) + { + retValue = apply_ARH_AD1(assetwk, assetAcct, A_Current_Period, Accum_Dep); + } + else if (depreciationType.equalsIgnoreCase("ARH_AD2")) + { + retValue = apply_ARH_AD2(assetwk, assetAcct, A_Current_Period, Accum_Dep); + } + else if (depreciationType.equalsIgnoreCase("ARH_ZERO")) + { + retValue = apply_ARH_ZERO(assetwk, assetAcct, A_Current_Period, Accum_Dep); + } + else + { + throw new AssetNotSupportedException(COLUMNNAME_DepreciationType, depreciationType); + } + // + if (retValue == null) + { + retValue = BigDecimal.ZERO; + } + retValue = retValue.setScale(getPrecision(), RoundingMode.HALF_UP); + // + if(CLogMgt.isLevelFinest()) log.fine("Leaving: retValue=" + retValue); + return retValue; + } // invoke + + /** + * Check if the method can be invoked to give parameters + * @param assetwk + * @param assetAcct + * @param A_Current_Period between 0 to UseLifeMonths - 1 + * @param Accum_Dep + */ + public boolean canInvoke(MDepreciationWorkfile assetwk, MAssetAcct assetAcct, + int A_Current_Period, BigDecimal Accum_Dep) + { + //~ MDepreciationWorkfile wk = MDepreciationWorkfile.get(getCtx(), A_Asset_ID, PostingType); + if (assetwk == null) + { + log.warning("@NotFound@ @A_Depreciation_Workfile_ID@"); + return false; + } + //TODO review this method - red1 + int offset = 0 ; //getFixMonthOffset(); this field does not exist in AD nor DB but exists in X_. - red1 + int lifePeriods = assetwk.getUseLifeMonths(assetwk.isFiscal()); + boolean ok = (offset <= A_Current_Period); + + if(CLogMgt.isLevelFinest()) log.finest("A_Current_Period=" + A_Current_Period + ", lifePeriods=" + lifePeriods + " (offset=" + offset + ") ==> OK=" + ok); + return ok; + } // canInvoke + + /** + * Without depreciation + * @param A_Asset_ID Assets IDs (ignored) + * @param A_Current_Period current period (in months, between 0 and UseLifeMonths - 1) (ignored) + * @param PostingType posting type (eg. A - Actual, S - Statistics ...) (ignored) + * @param A_Asset_Acct_ID FA accounting IDs (see table A_Asset_Acct) (ignored) + * @param Accum_Dep Accumulated depreciation from this method (ignored) + * @return Env.ZERO + */ + private BigDecimal apply_ARH_ZERO (MDepreciationWorkfile wk, MAssetAcct assetAcct, + int A_Current_Period, BigDecimal Accum_Dep) + { + return Env.ZERO; + } + + /** Linear depreciation regime + * @param A_Asset_ID Assets IDs + * @param A_Current_Period current period (in months, between 0 and UseLifeMonths - 1) + * @param PostingType posting type (eg. A - Actual, S - Statistics ...) + * @param A_Asset_Acct_ID FA accounting IDs (see table A_Asset_Acct) + * @param Accum_Dep Accumulated depreciation from this method + * @return depreciation for the current month + */ + private BigDecimal apply_SL (MDepreciationWorkfile wk, MAssetAcct assetAcct, + int A_Current_Period, BigDecimal Accum_Dep) + { + BigDecimal remainingPeriods = new BigDecimal(wk.getRemainingPeriods(A_Current_Period - 1)); + BigDecimal remainingAmt = wk.getRemainingCost(Accum_Dep); + BigDecimal amtPerPeriod = Env.ZERO; + if (remainingPeriods.signum() != 0) + { + amtPerPeriod = remainingAmt.divide(remainingPeriods, getPrecision(), RoundingMode.HALF_UP); + } + + if(CLogMgt.isLevelFinest()) + { + log.finest("currentPeriod=" + A_Current_Period + ", remainingAmt=" + remainingAmt + ", remainingPeriods=" + remainingPeriods + " => amtPerPeriod=" + amtPerPeriod); + } + + return amtPerPeriod; + } + + /** + * Accelerated depreciation regime + * @param A_Current_Period current period (in months, between 0 and UseLifeMonths - 1) + * @param PostingType posting type (eg. A - Actual, S - Statistics ...) + * @param A_Asset_Acct_ID FA accounting IDs (see table A_Asset_Acct) + * @param Accum_Dep Accumulated depreciation from this method + * @return depreciation for the current month + */ + private BigDecimal apply_ARH_VAR (MDepreciationWorkfile wk, MAssetAcct acct, + int A_Current_Period, BigDecimal Accum_Dep) + { + BigDecimal amt = wk.getActualCost(); + BigDecimal varPercent = acct.getA_Depreciation_Variable_Perc(wk.isFiscal()).setScale(getPrecision(), RoundingMode.HALF_UP); + //~ int lifePeriods = wk.getUseLifeMonths(wk.isFiscal()); + BigDecimal assetExp = BigDecimal.ZERO; + + // First time in first year + if (A_Current_Period == 0) + { + assetExp = amt.multiply(varPercent); + } + // Periods of the first year (without first) + else if (A_Current_Period < 12) + { + // do nothing; + } + // Following periods + else + { + BigDecimal remainingAmt = wk.getRemainingCost(Accum_Dep); + BigDecimal remainingPeriods = new BigDecimal(wk.getRemainingPeriods(A_Current_Period)); + assetExp = remainingAmt.divide(remainingPeriods, getPrecision(), RoundingMode.HALF_UP); + // logging + if (CLogMgt.isLevelFinest()) { + log.fine("remainingAmt=" + remainingAmt + ", remainingPeriods=" + remainingPeriods+ " => assetExp=" + assetExp); + } + } + + return assetExp; + } + + + /** Digressive depreciation regime (AD1) + * @param A_Current_Period current period (in months, between 0 and UseLifeMonths - 1) + * @param PostingType posting type (eg. A - Actual, S - Statistics ...) + * @param A_Asset_Acct_ID FA accounting IDs (see table A_Asset_Acct) + * @param Accum_Dep Accumulated depreciation from this method + * @return depreciation for the current month + * TODO RE TEST IT! + */ + private BigDecimal apply_ARH_AD1(MDepreciationWorkfile wk, MAssetAcct assetAcct, int A_Current_Period,BigDecimal Accum_Dep) + { + //~ /** Current Worksheet */ + //~ MDepreciationWorkfile wk = MDepreciationWorkfile.get(getCtx(), A_Asset_ID, PostingType); + + /** FAs' value = acquisition value - the amount recovered */ + BigDecimal assetAmt = wk.getActualCost(); + /** Life in months */ + int A_Life_Period = wk.getA_Life_Period(); + /** Year = integer part of (current period / 12) => first year will be 0 */ + int A_Current_Year = (int)(A_Current_Period / 12); + /** Life in years = integer part of (the life in months / 12) => first year will be 0 */ + int A_Life_Year = (int)(A_Life_Period / 12); + //~ /** Number of years of use remaining (including current year) */ + //~ int A_RemainingLife_Year = A_Life_Year - A_Current_Year; + + + /** Coefficient K */ + /* @win : looks like a country specific requirement + BigDecimal coef_K = get_AD_K(A_Life_Year); + */ + + /** Linear damping coefficient for one year = 1 / total number of years */ + BigDecimal coef_sl = BigDecimal.ONE.divide(new BigDecimal(A_Life_Year), getPrecision() + 2, RoundingMode.DOWN); + /** Degressive damping coefficient for one year = one-year linear depreciation * coeficient K */ + //BigDecimal coef_ad1 = coef_sl.multiply(coef_K); //commented by @win + BigDecimal coef_ad1 = coef_sl.multiply(new BigDecimal(2.0)); //added by @win + + /** AD2 */ + //~ BigDecimal DUR = BD_100.multiply( + + // logging + if (CLogMgt.isLevelFinest()) { + log.fine("assetAmt=" + assetAmt + ", A_Life_Period=" + A_Life_Period); + log.fine("A_Current_Year=" + A_Current_Year + ", A_Life_Year=" + A_Life_Year); + //log.fine("coef_K=" + coef_K + ", coef_sl=" + coef_sl + ", coef_ad1=" + coef_ad1); //commented out by @win + } + + /** Depreciation for the current year, is calculated below */ + BigDecimal amtPerYear = BigDecimal.ZERO; + /** They went on linear depreciation */ + boolean is_SL = false; + /** Year linear depreciation = depreciation remaining / number of years remaining (including this year) */ + BigDecimal amt_sl = BigDecimal.ZERO; + /** Remaining depreciation */ + BigDecimal amt_r = assetAmt; + + for (int curr_year = 0; curr_year <= A_Current_Year; curr_year++) { + if (!is_SL) { + /** Number of years of use remaining (including current year) */ + int A_RemainingLife_Year = A_Life_Year - curr_year; + /** Degressive current year depreciation */ + BigDecimal amt_ad1 = amt_r.multiply(coef_ad1); + /** Year linear depreciation = depreciation remaining / number of years remaining (including this year) */ + amt_sl = amt_r.divide(new BigDecimal(A_RemainingLife_Year), getPrecision(), RoundingMode.HALF_UP); + // logging + if (CLogMgt.isLevelFinest()) { + s_log.fine("amt_r=" + amt_r + ", amt_ad1=amt_r*coef_ad1=" + amt_ad1 + ", amt_sl=amt_r/A_RemainingLife_Year=" + amt_sl + ", A_Current_Year=" + A_Current_Year + ", A_RemainingLife_Year=" + A_RemainingLife_Year); + } + + /** If the first year or if the value depreciation value depreciation degressive more linear ... */ + if (curr_year == 0 || amt_ad1.compareTo(amt_sl) >= 0) { + amtPerYear = amt_ad1; + } + else { + amtPerYear = amt_sl; + is_SL = true; + s_log.fine("*** PASS IT ON linear amt_sl= " + amt_sl + " ***"); + } + } + else { + amtPerYear = amt_sl; + s_log.fine("* linear *"); + } + + amt_r = amt_r.subtract(amtPerYear); + if (CLogMgt.isLevelFinest()) s_log.fine("year=" + curr_year + ", amtPerYear=" + amtPerYear + ", amt_r=" + amt_r); //logging + } + if (CLogMgt.isLevelFinest()) s_log.fine("amt_r=" + amt_r + ", amtPerYear=" + amtPerYear); //logging + + /** Damping value for the current month */ + BigDecimal assetExp = getPeriodExp(A_Current_Period, amtPerYear); + + /** Depreciation refund */ + if (CLogMgt.isLevelFinest()) log.fine("assetExp=" + assetExp); + return assetExp; + } + + /** + * + */ + private BigDecimal apply_ARH_AD2(MDepreciationWorkfile wk, MAssetAcct assetAcct, int A_Current_Period,BigDecimal Accum_Dep) + { + throw new AssetNotImplementedException("AD2"); + } + + /** For depreciation regime skimmed returns coefficient K depending on the life of FAs + * @param A_Life_Year life in years + * @return coeficient K degressive method for + * @see #apply_ARH_AD1(int, int, String, int, BigDecimal) + */ + private static BigDecimal get_AD_K(int A_Life_Year) + { + if (A_Life_Year < 2) { + throw new IllegalArgumentException("@A_Life_Year@ = " + A_Life_Year + " < 2"); + } + // A_Life_Year in [2, 5] + else if (A_Life_Year <= 5) { + return new BigDecimal(1.5); + } + // A_Life_Year in (5, 10] + else if (A_Life_Year <= 10) { + return new BigDecimal(2.0); + } + // A_Life_Year in (10, infinit) + else { + return new BigDecimal(2.5); + } + } + + /** Calculate the value of depreciation over a month (period). In the last month of the year we add errors from the adjustment calculation + * @param A_Current_Period current month's index + * @param amtPerYear value of depreciation per year + * @return rounded value to the nearest month/decimal getPrecision () + */ + protected BigDecimal getPeriodExp(int A_Current_Period, BigDecimal amtPerYear) + { + /** Monthly amount */ + BigDecimal amtPerMonth = amtPerYear.divide(BD_12, getPrecision(), RoundingMode.HALF_UP); + /** Value adjustment */ + BigDecimal adj = BigDecimal.ZERO; + /** The amount a month (with adjustments) */ + BigDecimal assetExp = amtPerMonth; + + // if last month of the year, calculate the adjustment + // NOTE: All adjusted value shall be rounded to getPrecision () decimal + if (A_Current_Period % 12 == 11) + { + adj = amtPerYear.subtract(amtPerMonth.multiply(BD_12)); + assetExp = assetExp.add(adj).setScale(getPrecision(), RoundingMode.HALF_UP); + } + + if (CLogMgt.isLevelFinest()) + { + log.fine("amtPerYear=" + amtPerYear + ", amtPerMonth=" + amtPerMonth + ", adj=" + adj + " => assetExp=" + assetExp); + } + return assetExp; + } +} diff --git a/org.adempiere.base/src/org/compiere/model/MDepreciationBuild.java b/org.adempiere.base/src/org/compiere/model/MDepreciationBuild.java new file mode 100644 index 0000000000..f1dca0be17 --- /dev/null +++ b/org.adempiere.base/src/org/compiere/model/MDepreciationBuild.java @@ -0,0 +1,28 @@ +package org.compiere.model; + +import java.sql.ResultSet; +import java.util.Properties; + + +/** Depreciation Build + * @author Teo Sarca, SC ARHIPAC SRL + * @version $Id$ -- Release 2.5.3a - 2006-06-22 18:03:22.896 + */ +public class MDepreciationBuild extends X_A_Depreciation_Build +{ + /** Standard Constructor */ + public MDepreciationBuild (Properties ctx, int A_Depreciation_Build_ID, String trxName) + { + super (ctx, A_Depreciation_Build_ID, trxName); + /** if (A_Depreciation_Build_ID == 0) + { + setA_Depreciation_Build_ID (0); + } + */ + } + /** Load Constructor */ + public MDepreciationBuild (Properties ctx, ResultSet rs, String trxName) + { + super (ctx, rs, trxName); + } +} diff --git a/org.adempiere.base/src/org/compiere/model/MDepreciationConvention.java b/org.adempiere.base/src/org/compiere/model/MDepreciationConvention.java new file mode 100644 index 0000000000..e05c82ebfc --- /dev/null +++ b/org.adempiere.base/src/org/compiere/model/MDepreciationConvention.java @@ -0,0 +1,116 @@ +package org.compiere.model; +import java.sql.*; +import java.math.*; +import java.util.*; +import java.util.logging.*; +import org.compiere.model.*; +import org.compiere.util.*; + +/** Convention for the first year of depreciation (ex. FMCON, FYCON ...) + * @author Teo Sarca, SC Arhipac SRL + * @version $Id$ + */ +public class MDepreciationConvention extends X_A_Depreciation_Convention +{ + /** + * Default Constructor + * @param ctx context + * @param A_Depreciation_Convention_ID id + * @param trxName transaction name + */ + public MDepreciationConvention(Properties ctx, int A_Depreciation_Convention_ID, String trxName) + { + super (ctx, A_Depreciation_Convention_ID, trxName); + //~ if (A_Depreciation_Convention_ID == 0) + //~ { + //~ } + } // MDepreciationConvention + + /** + * Load Constructor + * @param ctx context + * @param rs result set record + */ + public MDepreciationConvention (Properties ctx, ResultSet rs, String trxName) + { + super (ctx, rs, trxName); + } // MDepreciationConvention + + /** Cache */ + private static CCache s_cache = new CCache("A_Depreciation_Convention", 5); + //~ /** Static logger */ + //~ private static Logger s_log = CLogger.getCLogger(MDepreciationConvention.class); + + public static MDepreciationConvention get(Properties ctx, int A_Depreciation_Convention_ID) { + Integer key = Integer.valueOf(A_Depreciation_Convention_ID); + MDepreciationConvention conv = s_cache.get(key); + if (conv != null) { + return conv; + } + conv = new MDepreciationConvention(ctx, A_Depreciation_Convention_ID, null); + if (conv.get_ID() > 0) { + s_cache.put(key, conv); + } else { + conv = null; + } + return conv; + } // get + + /** */ + public BigDecimal invoke (MDepreciationWorkfile assetwk, MAssetAcct assetAcct, int Flag, int Period) { + return invoke(assetwk.getA_Asset_ID(), assetAcct.getPostingType(), assetAcct.get_ID(), Flag, Period); + } + + /** */ + public BigDecimal invoke (int A_Asset_ID, String PostingType, int A_Asset_Acct_ID, int Flag, int Period) { + String conventionType = getConventionType(); + BigDecimal retValue = null; + + if(CLogMgt.isLevelFine()) + log.fine("Entering: ConventionType=" + conventionType + + "A_Asset_ID=" + A_Asset_ID + ", PostingType=" + PostingType + ", A_Asset_Acct_ID=" + A_Asset_Acct_ID + + ", Flag=" + Flag + ", Period=" + Period + ); + + if (conventionType.equalsIgnoreCase("FMCON")) { + return apply_FMCON(A_Asset_ID, PostingType, A_Asset_Acct_ID, Flag, Period); + } + else { + String sql = "{ ? = call "+ conventionType + "(?, ?, ?, ?, ?) }"; + CallableStatement cs = null; + try { + cs = DB.prepareCall(sql); + cs.registerOutParameter(1, java.sql.Types.DECIMAL); + cs.setInt(2, A_Asset_ID); + cs.setString(3, PostingType); + cs.setInt(4, A_Asset_Acct_ID); + cs.setInt(5, Flag); + cs.setInt(6, Period); + cs.execute(); + retValue = cs.getBigDecimal(1); + cs.close(); + } catch (Exception e) { + log.log(Level.SEVERE, sql, e); + } + finally { + try { + if (cs != null) cs.close(); + } catch (SQLException e) { + log.log(Level.FINEST, "Error", e); + } + cs = null; + } + } + // + if (retValue == null) { + retValue = BigDecimal.ZERO; + } + // + if(CLogMgt.isLevelFine()) log.fine("Leaving: retValue=" + retValue); + return retValue; + } + + public BigDecimal apply_FMCON(int A_Asset_ID, String PostingType, int A_Asset_Acct_ID, int Flag, int Period) { + return BigDecimal.ONE; + } +} diff --git a/org.adempiere.base/src/org/compiere/model/MDepreciationEntry.java b/org.adempiere.base/src/org/compiere/model/MDepreciationEntry.java new file mode 100644 index 0000000000..ba31fcca2c --- /dev/null +++ b/org.adempiere.base/src/org/compiere/model/MDepreciationEntry.java @@ -0,0 +1,373 @@ +package org.compiere.model; + +import java.io.File; +import java.math.BigDecimal; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Properties; +import java.util.logging.Level; + +import org.adempiere.exceptions.AdempiereException; +import org.compiere.model.MAcctSchema; +import org.compiere.model.MClient; +import org.compiere.model.MPeriod; +import org.compiere.model.ModelValidationEngine; +import org.compiere.model.ModelValidator; +import org.compiere.model.Query; +import org.compiere.process.DocAction; +import org.compiere.process.DocumentEngine; +import org.compiere.util.DB; +import org.compiere.util.Env; +import org.compiere.util.TimeUtil; +import org.compiere.util.Trx; +import org.compiere.util.TrxRunnable; +import org.idempiere.fa.exceptions.AssetArrayException; +import org.idempiere.fa.exceptions.AssetException; + + +/** + * Depreciation Entry + * @author Teo Sarca, SC ARHIPAC SERVICE SRL + */ +public class MDepreciationEntry extends X_A_Depreciation_Entry +implements DocAction +{ + private static final long serialVersionUID = 1L; + + /** Standard Constructor */ + public MDepreciationEntry(Properties ctx, int A_Depreciation_Entry_ID, String trxName) + { + super (ctx, A_Depreciation_Entry_ID, trxName); + if (A_Depreciation_Entry_ID == 0) + { + MAcctSchema acctSchema = MClient.get(getCtx()).getAcctSchema(); + setC_AcctSchema_ID(acctSchema.get_ID()); + setC_Currency_ID(acctSchema.getC_Currency_ID()); + setA_Entry_Type (A_ENTRY_TYPE_Depreciation); // TODO: workaround + setPostingType (POSTINGTYPE_Actual); // A + setProcessed (false); + setProcessing (false); + setPosted(false); + } + } + + /** Load Constructor */ + public MDepreciationEntry (Properties ctx, ResultSet rs, String trxName) + { + super (ctx, rs, trxName); + } + + + protected boolean beforeSave(boolean newRecord) + { + setC_Period_ID(); + return true; + } + + + protected boolean afterSave(boolean newRecord, boolean success) + { + if (!success) + { + return false; + } + if (!isProcessed() && (newRecord || is_ValueChanged(COLUMNNAME_DateAcct))) + { + selectLines(); + } + return true; + } + + + protected boolean afterDelete(boolean success) + { + if (!success) + { + return false; + } + + unselectLines(); + return true; + } + + public void setC_Period_ID() + { + MPeriod period = MPeriod.get(getCtx(), getDateAcct(), getAD_Org_ID()); + if (period == null) + { + throw new AdempiereException("@NotFound@ @C_Period_ID@"); + } + setC_Period_ID(period.get_ID()); + } + + private void unselectLines() + { + String sql = "UPDATE " + MDepreciationExp.Table_Name + " SET " + + MDepreciationExp.COLUMNNAME_A_Depreciation_Entry_ID + "=NULL " + + " WHERE " + + MDepreciationExp.COLUMNNAME_A_Depreciation_Entry_ID + "=?"; + int id = get_ID(); + if (id <= 0) + { // Use old ID is current ID is missing (i.e. object was deleted) + id = get_IDOld(); + } + int no = DB.executeUpdateEx(sql, new Object[]{id}, get_TrxName()); + log.fine("Updated #" + no); + } + + private void selectLines() + { + // Reset selected lines: + unselectLines(); + // Select lines: + final String sql = "UPDATE " + MDepreciationExp.Table_Name + " SET " + + MDepreciationExp.COLUMNNAME_A_Depreciation_Entry_ID + "=?" + + " WHERE " + + MDepreciationExp.COLUMNNAME_A_Depreciation_Entry_ID + " IS NULL" + + " AND TRUNC("+MDepreciationExp.COLUMNNAME_DateAcct+",'MONTH') = ?" + + " AND AD_Client_ID=? AND AD_Org_ID=?"; + ; + Timestamp dateAcct = TimeUtil.trunc(getDateAcct(), TimeUtil.TRUNC_MONTH); + int no = DB.executeUpdateEx(sql, new Object[]{get_ID(), dateAcct, getAD_Client_ID(), getAD_Org_ID()}, get_TrxName()); + log.fine("Updated #" + no); + } + + /** + * Get Lines + */ + public Iterator getLinesIterator(boolean onlyNotProcessed) + { + final String trxName = get_TrxName(); + final List params = new ArrayList(); + String whereClause = MDepreciationExp.COLUMNNAME_A_Depreciation_Entry_ID+"=?"; + params.add(get_ID()); + + if (onlyNotProcessed) + { + whereClause += " AND "+MDepreciationExp.COLUMNNAME_Processed+"=?"; + params.add(false); + } + + // ORDER BY clause - very important + String orderBy = MDepreciationExp.COLUMNNAME_A_Asset_ID + +","+MDepreciationExp.COLUMNNAME_PostingType + +","+MDepreciationExp.COLUMNNAME_A_Period + +","+MDepreciationExp.COLUMNNAME_A_Entry_Type; + + Iterator it = new Query(getCtx(), MDepreciationExp.Table_Name, whereClause, trxName) + .setOrderBy(orderBy) + .setParameters(params) + .iterate(); + return it; + } + + + public boolean processIt (String processAction) + { + m_processMsg = null; + DocumentEngine engine = new DocumentEngine (this, getDocStatus()); + return engine.processIt (processAction, getDocAction()); + } // processIt + + /** Process Message */ + private String m_processMsg = null; + /** Just Prepared Flag */ + private boolean m_justPrepared = false; + + + public boolean unlockIt() + { + log.info("unlockIt - " + toString()); + // setProcessing(false); + return true; + } // unlockIt + + + public boolean invalidateIt() + { + return false; + } + + + public String prepareIt() + { + log.info(toString()); + m_processMsg = ModelValidationEngine.get().fireDocValidate(this, ModelValidator.TIMING_BEFORE_PREPARE); + if (m_processMsg != null) + { + return DocAction.STATUS_Invalid; + } + + MPeriod.testPeriodOpen(getCtx(), getDateAcct(), getC_DocType_ID(), getAD_Org_ID()); + + m_justPrepared = true; + + m_processMsg = ModelValidationEngine.get().fireDocValidate(this, ModelValidator.TIMING_AFTER_PREPARE); + if (m_processMsg != null) + { + return DocAction.STATUS_Invalid; + } + + setDocAction(DOCACTION_Complete); + return DocAction.STATUS_InProgress; + } + + + public boolean approveIt() + { + log.info("approveIt - " + toString()); + setIsApproved(true); + return true; + } + + + public boolean rejectIt() + { + log.info("rejectIt - " + toString()); + setIsApproved(false); + return true; + } // rejectIt + + + public String completeIt() + { + // Re-Check + if (!m_justPrepared) + { + String status = prepareIt(); + if (!DocAction.STATUS_InProgress.equals(status)) + return status; + } + // Implicit Approval + if (!isApproved()) + { + approveIt(); + } + + final MPeriod period = MPeriod.get(getCtx(), getC_Period_ID()); + + final ArrayList errors = new ArrayList(); + final Iterator it = getLinesIterator(true); + // + while(it.hasNext()) + { + try + { + Trx.run(get_TrxName(), new TrxRunnable(){ + + public void run(String trxName) + { + MDepreciationExp depexp = it.next(); + // Check if is in Period + if (!period.isInPeriod(depexp.getDateAcct())) + { + throw new AssetException("The date is not within this Period" + +" ("+depexp+", Data="+depexp.getDateAcct()+", Period="+period.getName()+")"); // TODO: translate + } + depexp.process(); + }}); + } + catch (Exception e) + { + log.log(Level.SEVERE, e.getLocalizedMessage(), e); + errors.add(e); + } + } + // + if (errors.size() > 0) + { + throw new AssetArrayException(errors); + } + + // User Validation + String valid = ModelValidationEngine.get().fireDocValidate(this, ModelValidator.TIMING_AFTER_COMPLETE); + if (valid != null) + { + m_processMsg = valid; + return DocAction.STATUS_Invalid; + } + + setProcessed(true); + setDocAction(DOCACTION_Close); + return DocAction.STATUS_Completed; + } // completeIt + + + public boolean voidIt() + { + return false; + } + + + public boolean closeIt() + { + setDocAction(DOCACTION_None); + return true; + } + + + public boolean reverseCorrectIt() + { + return false; + } + + + public boolean reverseAccrualIt() + { + return false; + } + + + public boolean reActivateIt() + { + return false; + } // reActivateIt + + + + public String getSummary() + { + return toString(); + } + + + public String getProcessMsg() + { + return m_processMsg; + } + + + public int getDoc_User_ID() + { + return getCreatedBy(); + } + + + public BigDecimal getApprovalAmt() + { + return null; + } + + + public File createPDF () + { + return null; + } + + + public String getDocumentInfo() + { + return getDocumentNo(); + } + + public static void deleteFacts(MDepreciationExp depexp) + { + final String sql = "DELETE FROM Fact_Acct WHERE AD_Table_ID=? AND Record_ID=? AND Line_ID=?"; + Object[] params = new Object[]{Table_ID, depexp.getA_Depreciation_Entry_ID(), depexp.get_ID()}; + DB.executeUpdateEx(sql, params, depexp.get_TrxName()); + } +} diff --git a/org.adempiere.base/src/org/compiere/model/MDepreciationExp.java b/org.adempiere.base/src/org/compiere/model/MDepreciationExp.java new file mode 100644 index 0000000000..3ceb11a6d0 --- /dev/null +++ b/org.adempiere.base/src/org/compiere/model/MDepreciationExp.java @@ -0,0 +1,301 @@ +package org.compiere.model; + +import java.math.BigDecimal; +import java.sql.ResultSet; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Properties; + +import org.compiere.model.MDocType; +import org.compiere.model.MPeriod; +import org.compiere.model.Query; +import org.compiere.util.CLogger; +import org.compiere.util.DB; +import org.compiere.util.Msg; +import org.compiere.util.TimeUtil; +import org.idempiere.fa.exceptions.AssetException; +import org.idempiere.fa.exceptions.AssetNotActiveException; + + +public class MDepreciationExp extends X_A_Depreciation_Exp +{ + private static final long serialVersionUID = 1L; + + private static CLogger s_log = CLogger.getCLogger(MDepreciationExp.class); + private CLogger log = CLogger.getCLogger(this.getClass()); + + /** Standard Constructor */ + public MDepreciationExp(Properties ctx, int A_Depreciation_Exp_ID, String trxName) + { + super (ctx, A_Depreciation_Exp_ID, trxName); + /** + if (A_Depreciation_Exp_ID == 0) + { + setA_Account_Number (0); + setA_Asset_ID (0); + setA_Depreciation_Exp_ID (0); + setA_Entry_Type (null); + setA_Period (0); + setDescription (null); + setExpense (Env.ZERO); + setIsDepreciated (false); + setProcessed (false); + } + */ + } + + /** Load Constructor */ + public MDepreciationExp (Properties ctx, ResultSet rs, String trxName) + { + super (ctx, rs, trxName); + } + + /** Gets depreciation expense + * @param ctx context + * @param A_Depreciation_Exp_ID depreciation expense id + * @return depreciation expense or null if A_Depreciation_Exp_ID=0 or not found + */ + public static MDepreciationExp get(Properties ctx, int A_Depreciation_Exp_ID) { + if (A_Depreciation_Exp_ID <= 0) { + return null; + } + MDepreciationExp depexp = new MDepreciationExp(ctx, A_Depreciation_Exp_ID, null); + if (depexp.get_ID() != A_Depreciation_Exp_ID) { + depexp = null; + } + return depexp; + } + + /** Create entry + */ + public static MDepreciationExp createEntry (Properties ctx, String entryType, int A_Asset_ID + , int A_Period, Timestamp DateAcct, String postingType + , int drAcct, int crAcct, BigDecimal expense + , String description + , MDepreciationWorkfile assetwk) + { + MDepreciationExp depexp = new MDepreciationExp(ctx, 0, null); + depexp.setA_Entry_Type(entryType); + depexp.setA_Asset_ID(A_Asset_ID); + depexp.setDR_Account_ID(drAcct); + depexp.setCR_Account_ID(crAcct); + depexp.setA_Account_Number_Acct(drAcct); // TODO: DELETEME + depexp.setPostingType(postingType); + depexp.setExpense(expense); + depexp.setDescription(Msg.parseTranslation(ctx, description)); + depexp.setA_Period(A_Period); + depexp.setIsDepreciated(true); + depexp.setDateAcct(DateAcct); + // + depexp.updateFrom(assetwk); + // + s_log.fine("depexp=" + depexp); + return depexp; + } + + /** + * Update fields from asset workfile + * @param wk asset workfile + */ + public void updateFrom(MDepreciationWorkfile wk) + { + setA_Asset_Cost(wk.getA_Asset_Cost()); + setA_Accumulated_Depr(wk.getA_Accumulated_Depr()); + setA_Accumulated_Depr_F(wk.getA_Accumulated_Depr_F()); + setUseLifeMonths(wk.getUseLifeMonths()); + setUseLifeMonths_F(wk.getUseLifeMonths_F()); + setA_Asset_Remaining(wk.getA_Asset_Remaining()); + setA_Asset_Remaining_F(wk.getA_Asset_Remaining_F()); + } + + private MDepreciationWorkfile getA_Depreciation_Workfile() + { + return MDepreciationWorkfile.get(getCtx(), getA_Asset_ID(), getPostingType(), get_TrxName()); + } + + /** Create Depreciation Entries + * Produce record: + *
+	 *		68.. = 28..   depreciation value
+	 *	
+ */ + public static Collection createDepreciation ( + MDepreciationWorkfile assetwk, + int PeriodNo, Timestamp dateAcct, + BigDecimal amt, BigDecimal amt_F, + BigDecimal accumAmt, BigDecimal accumAmt_F, + String help, String trxName) + { + ArrayList list = new ArrayList(); + Properties ctx = assetwk.getCtx(); + MAssetAcct assetAcct = assetwk.getA_AssetAcct(dateAcct, trxName); + MDepreciationExp depexp = null; + + depexp = createEntry (ctx, A_ENTRY_TYPE_Depreciation, assetwk.getA_Asset_ID(), PeriodNo, dateAcct, assetwk.getPostingType() + , assetAcct.getA_Depreciation_Acct(), assetAcct.getA_Accumdepreciation_Acct() + , amt + , "@AssetDepreciationAmt@" + , assetwk); + if(depexp != null) { + depexp.setAD_Org_ID(assetwk.getA_Asset().getAD_Org_ID()); // added by zuhri + if (accumAmt != null) + depexp.setA_Accumulated_Depr(accumAmt); + if (accumAmt_F != null) + depexp.setA_Accumulated_Depr_F(accumAmt_F); + if (help != null && help.length() > 0) + depexp.setHelp(help); + depexp.setExpense_F(amt_F); + depexp.setA_Accumulated_Depr_Delta(amt); + depexp.setA_Accumulated_Depr_F_Delta(amt_F); + depexp.saveEx(assetwk.get_TrxName()); + list.add(depexp); + } + return list; + } + + /** + * Process this entry and save the modified workfile. + */ + public void process() + { + if(isProcessed()) + { + log.fine("@AlreadyProcessed@"); + return; + } + + // + MDepreciationWorkfile assetwk = getA_Depreciation_Workfile(); + if (assetwk == null) + { + throw new AssetException("@NotFound@ @A_Depreciation_Workfile_ID@"); + } + // + String entryType = getA_Entry_Type(); + if (MDepreciationExp.A_ENTRY_TYPE_Depreciation.equals(entryType)) + { + checkExistsNotProcessedEntries(getCtx(), getA_Asset_ID(), getDateAcct(), getPostingType(), get_TrxName()); + // + // Check if the asset is Active: + if (!assetwk.getAsset().getA_Asset_Status().equals(MAsset.A_ASSET_STATUS_Activated)) + { + throw new AssetNotActiveException(assetwk.getAsset().get_ID()); + } + // + setDateAcct(assetwk.getDateAcct()); + assetwk.adjustAccumulatedDepr(getExpense(), getExpense_F(), false); + } + else + { + // nothing to do for other entry types + } + // + setProcessed(true); + updateFrom(assetwk); + saveEx(); + + // + // Update workfile + assetwk.setA_Current_Period(); + assetwk.saveEx(); + } + + + protected boolean beforeDelete() + { + if (isProcessed()) + { + // TODO : check if we can reverse it (check period, check dateacct etc) + MDepreciationWorkfile assetwk = getA_Depreciation_Workfile(); + assetwk.adjustAccumulatedDepr(getA_Accumulated_Depr().negate(), getA_Accumulated_Depr_F().negate(), false); + assetwk.saveEx(); + } + // Try to delete postings + if (isPosted()) + { + MPeriod.testPeriodOpen(getCtx(), getDateAcct(), MDocType.DOCBASETYPE_GLDocument, getAD_Org_ID()); + MDepreciationEntry.deleteFacts(this); + } + return true; + } + + + protected boolean afterDelete(boolean success) + { + if (!success) + { + return false; + } + // + // If it was processed, we need to update workfile's current period + if (isProcessed()) + { + MDepreciationWorkfile wk = getA_Depreciation_Workfile(); + wk.setA_Current_Period(); + wk.saveEx(); + } + // + return true; + } + + protected boolean isPosted() + { + return isProcessed() && getA_Depreciation_Entry_ID() > 0; + } + + public static void checkExistsNotProcessedEntries(Properties ctx, + int A_Asset_ID, Timestamp dateAcct, String postingType, + String trxName) + { + final String whereClause = MDepreciationExp.COLUMNNAME_A_Asset_ID+"=?" + +" AND TRUNC("+MDepreciationExp.COLUMNNAME_DateAcct+",'MONTH') getNotProcessedEntries(Properties ctx, + int A_Asset_ID, String postingType, + String trxName) + { + final String whereClause = MDepreciationExp.COLUMNNAME_A_Asset_ID+"=?" + +" AND "+MDepreciationExp.COLUMNNAME_PostingType+"=?" + +" AND "+MDepreciationExp.COLUMNNAME_Processed+"=?"; + List list = new Query(ctx, MDepreciationExp.Table_Name, whereClause, trxName) + .setParameters(new Object[]{A_Asset_ID, postingType, false}) + .list(); + return list; +} + + + public void setProcessed(boolean Processed) + { + super.setProcessed(Processed); + // + if (get_ID() > 0) + { + final String sql = "UPDATE "+Table_Name+" SET Processed=? WHERE "+COLUMNNAME_A_Depreciation_Exp_ID+"=?"; + DB.executeUpdateEx(sql, new Object[]{Processed, get_ID()}, get_TrxName()); + } + } + + + public String toString() + { + return getClass().getSimpleName()+"["+get_ID() + +",A_Asset_ID="+getA_Asset_ID() + +",A_Period="+getA_Period() + +",DateAcct="+getDateAcct() + +",Expense="+getExpense() + +",Entry_ID="+getA_Depreciation_Entry_ID() + +"]"; + } +} diff --git a/org.adempiere.base/src/org/compiere/model/MDepreciationMethod.java b/org.adempiere.base/src/org/compiere/model/MDepreciationMethod.java new file mode 100644 index 0000000000..c1fc145cf0 --- /dev/null +++ b/org.adempiere.base/src/org/compiere/model/MDepreciationMethod.java @@ -0,0 +1,245 @@ +package org.compiere.model; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.sql.CallableStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Properties; + +import org.adempiere.exceptions.DBException; +import org.compiere.model.Query; +import org.compiere.util.CCache; +import org.compiere.util.CLogMgt; +import org.compiere.util.DB; + +/** + * Method of adjusting the difference between depreciation (Calculated) and registered as (booked). + * ex. MDI, LDI, YDI ... + * @author Teo Sarca, SC ARHIPAC SERVICE SRL + */ +public class MDepreciationMethod extends X_A_Depreciation_Method +{ + /** Standard Constructor */ + public MDepreciationMethod (Properties ctx, int A_Depreciation_Method_ID, String trxName) + { + super (ctx, A_Depreciation_Method_ID, trxName); + } // MDepreciationMethod + + /** + * Load Constructor + * @param ctx context + * @param rs result set record + */ + public MDepreciationMethod (Properties ctx, ResultSet rs, String trxName) + { + super (ctx, rs, trxName); + } // MDepreciationMethod + + /** Cache */ + private static CCache + s_cache = new CCache(Table_Name, 5); + /** Cache for type */ + private static CCache + s_cache_forType = new CCache(Table_Name+"_DepreciationType", 5); + + /** + * + */ + private static void addToCache(MDepreciationMethod depr) + { + if (depr == null) + { + return; + } + s_cache.put(depr.get_ID(), depr); + s_cache_forType.put(depr.getDepreciationType(), depr); + } + + /** + * + */ + private static int getPrecision() + { + return 2; + } + + /** + * + */ + public static MDepreciationMethod get(Properties ctx, int A_Depreciation_Method_ID) + { + MDepreciationMethod depr = s_cache.get(A_Depreciation_Method_ID); + if (depr != null) + { + return depr; + } + depr = new MDepreciationMethod(ctx, A_Depreciation_Method_ID, null); + if (depr.get_ID() > 0) + { + addToCache(depr); + } + else + { + depr = null; + } + return depr; + } // get + + /** + * + */ + public static MDepreciationMethod get(Properties ctx, String depreciationType) + { + String key = depreciationType; + MDepreciationMethod depr = s_cache_forType.get(key); + if (depr != null) + { + return depr; + } + depr = new Query(ctx, Table_Name, COLUMNNAME_DepreciationType+"=?", null) + .setParameters(new Object[]{depreciationType}) + .firstOnly(); + addToCache(depr); + return depr; + } + + + /** + * + */ + public static BigDecimal invoke (Properties ctx, String depreciationType, + int A_Asset_ID, BigDecimal A_Asset_Adjustment, + int A_PeriodNo, String PostingType, int A_Asset_Acct_ID) + { + MDepreciationMethod depr = get(ctx, depreciationType); + if (depr == null) + { + throw new IllegalArgumentException("@NotFound@ @DepreciationType@ " + depreciationType); + } + return depr.invoke(A_Asset_ID, A_Asset_Adjustment, A_PeriodNo, PostingType, A_Asset_Acct_ID); + } + + /** + * Calculate adjustment + * @return adjustment to be applied in the specified period + */ + public BigDecimal invoke (MDepreciationWorkfile assetwk, + MAssetAcct assetAcct, BigDecimal A_Asset_Adjustment, + int A_PeriodNo) + { + return invoke(assetwk.getA_Asset_ID(), A_Asset_Adjustment, A_PeriodNo, assetAcct.getPostingType(), assetAcct.get_ID()); + } + + /** + * Calculate adjustment + * @return adjustment to be applied in the specified period + */ + public BigDecimal invoke (int A_Asset_ID, BigDecimal A_Asset_Adjustment, + int A_PeriodNo, String PostingType, int A_Asset_Acct_ID) + { + String depreciationType = getDepreciationType(); + BigDecimal retValue = null; + + if(CLogMgt.isLevelFine()) + log.fine("Entering: DepreciationMethodType=" + depreciationType + + ", A_Asset_ID=" + A_Asset_ID + ", A_Asset_Adjustment=" + A_Asset_Adjustment + + ", A_PeriodNo=" + A_PeriodNo + ", PostingType=" + PostingType + ", A_Asset_Acct_ID=" + A_Asset_Acct_ID + ); + + if (depreciationType.equalsIgnoreCase("MDI")) + { + retValue = apply_MDI(A_Asset_ID, A_Asset_Adjustment, A_PeriodNo, PostingType, A_Asset_Acct_ID); + } + else if (depreciationType.equalsIgnoreCase("YDI")) + { + retValue = apply_YDI(A_Asset_ID, A_Asset_Adjustment, A_PeriodNo, PostingType, A_Asset_Acct_ID); + } + else if (depreciationType.equalsIgnoreCase("LDI")) + { + retValue = apply_LDI(A_Asset_ID, A_Asset_Adjustment, A_PeriodNo, PostingType, A_Asset_Acct_ID); + } + else + { + String sql = "{ ? = call "+ depreciationType + "(?, ?, ?, ?, ?) }"; + CallableStatement cs = null; + try + { + cs = DB.prepareCall(sql); + cs.registerOutParameter(1, java.sql.Types.DECIMAL); + cs.setInt(2, A_Asset_ID); + cs.setBigDecimal(3, A_Asset_Adjustment); + cs.setInt(4, A_PeriodNo); + cs.setString(5, PostingType); + cs.setInt(6, A_Asset_Acct_ID); + cs.execute(); + retValue = cs.getBigDecimal(1); + cs.close(); + } + catch (SQLException e) + { + throw new DBException(e); + } + finally + { + DB.close(cs); + cs = null; + } + } + // + if (retValue == null) + { + retValue = BigDecimal.ZERO; + } + // + if(CLogMgt.isLevelFine()) log.fine("Leaving: retValue=" + retValue); + return retValue; + } + + /** MDI - adjustment is made ​​in the current month + * + */ + public BigDecimal apply_MDI (int A_Asset_ID, BigDecimal A_Asset_Adjustment, int A_PeriodNo, String PostingType, int A_Asset_Acct_ID) + { + return A_Asset_Adjustment; + } + + /** YDI -adjustment is made ​​for periods of the year remains + * + */ + public BigDecimal apply_YDI (int A_Asset_ID, BigDecimal A_Asset_Adjustment, int A_PeriodNo, String PostingType, int A_Asset_Acct_ID) + { + BigDecimal remainingPeriods = new BigDecimal(12 - A_PeriodNo); + if (remainingPeriods.signum() == 0) { + log.warning("A_PeriodNo=" + A_PeriodNo + " => remainingPeriods=" + remainingPeriods); + } + BigDecimal periodAdjustment = A_Asset_Adjustment.divide(remainingPeriods, getPrecision(), RoundingMode.HALF_UP); + + if(CLogMgt.isLevelFine()) { + log.fine("A_Asset_Adjustment=" + A_Asset_Adjustment + ", remainingPeriods=" + remainingPeriods + " => periodAdjustment=" + periodAdjustment); + } + return periodAdjustment; + } + + /** LDI - adjustment is made ​​on the remaining life + * + */ + public BigDecimal apply_LDI (int A_Asset_ID, BigDecimal A_Asset_Adjustment, int A_PeriodNo, String PostingType, int A_Asset_Acct_ID) + { + MDepreciationWorkfile wk = MDepreciationWorkfile.get(getCtx(), A_Asset_ID, PostingType); + + int A_Life_Period = wk.getA_Life_Period(); + int A_Period_Posted = wk.getA_Period_Posted(); + BigDecimal remainingPeriods = new BigDecimal(A_Life_Period - A_Period_Posted + 1); + if (remainingPeriods.signum() == 0) { + log.warning("A_Life_Period=" + A_Life_Period + ", A_Period_Posted=" + A_Period_Posted + " => remainingPeriods=" + remainingPeriods); + return BigDecimal.ZERO; + } + + BigDecimal periodAdjustment = A_Asset_Adjustment.divide(remainingPeriods, getPrecision(), RoundingMode.HALF_UP); + + if(CLogMgt.isLevelFine()) { + log.fine("A_Asset_Adjustment=" + A_Asset_Adjustment + ", remainingPeriods=" + remainingPeriods + " => periodAdjustment=" + periodAdjustment); + } + return periodAdjustment; + } +} diff --git a/org.adempiere.base/src/org/compiere/model/MIFixedAsset.java b/org.adempiere.base/src/org/compiere/model/MIFixedAsset.java new file mode 100644 index 0000000000..b6186c4cb0 --- /dev/null +++ b/org.adempiere.base/src/org/compiere/model/MIFixedAsset.java @@ -0,0 +1,330 @@ +package org.compiere.model; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.sql.ResultSet; +import java.sql.Timestamp; +import java.util.Properties; + +import org.adempiere.exceptions.FillMandatoryException; +import org.compiere.model.MClient; +import org.compiere.model.MProduct; +import org.compiere.model.MUOM; +import org.compiere.util.CLogMgt; +import org.compiere.util.DB; +import org.compiere.util.DisplayType; +import org.compiere.util.Env; +import org.compiere.util.Msg; +import org.compiere.util.Util; + +/** + * @author Teo Sarca, SC ARHIPAC SRL + * @version $Id + */ +public class MIFixedAsset extends X_I_FixedAsset +{ + private static final long serialVersionUID = 1L; + + /** Default depreciation method */ + private static final String s_defaultDepreciationType = "SL"; + + /** Standard Constructor */ + public MIFixedAsset (Properties ctx, int I_FixedAsset_ID, String trxName) + { + super (ctx, I_FixedAsset_ID, trxName); + } // MIFixedAsset + + /** + * Load Constructor + * @param ctx context + * @param rs result set record + */ + public MIFixedAsset (Properties ctx, ResultSet rs, String trxName) + { + super (ctx, rs, trxName); + } // MIFixedAsset + + /** Create / Load product + * @return product + */ + public MProduct getCreateProduct() + { + Properties ctx = getCtx(); + String trxName = get_TrxName(); + + int M_Product_ID = getM_Product_ID(); + if (M_Product_ID <= 0) { + StringBuffer whereClause = new StringBuffer(); + String key = getProductValue(); + if (key == null || key.trim().length() == 0) { + key = getName(); + whereClause.append("UPPER(Name)="); + } + else { + whereClause.append("UPPER(Value)="); + } + if (key == null || key.trim().length() == 0) { + throw new FillMandatoryException(COLUMNNAME_ProductValue, COLUMNNAME_Name); + } + key = key.toUpperCase(); + whereClause.append(DB.TO_STRING(key)); + whereClause.append(" AND AD_Client_ID=").append(getAD_Client_ID()); + String sql = "SELECT M_Product_ID FROM M_Product WHERE " + whereClause.toString(); + M_Product_ID = DB.getSQLValueEx(trxName, sql); + log.fine("M_Product_ID=" + M_Product_ID + " -- sql=" + sql); + } + + MProduct prod = null; + // Create MProduct: + if (M_Product_ID <= 0) + { + prod = new MProduct(ctx, 0, trxName); + prod.setName(getName()); + String value = getProductValue(); + if (value != null && value.trim().length() > 0) { + prod.setValue(value); + } + + prod.setM_Product_Category_ID(m_M_Product_Category_ID); + if (getC_UOM_ID() > 0) + { + prod.setC_UOM_ID(getC_UOM_ID()); + } + else + { + prod.setC_UOM_ID(MUOM.getDefault_UOM_ID(ctx)); + } + // Default Tax Category: + String sql = "SELECT C_TaxCategory_ID FROM C_TaxCategory WHERE AD_Client_ID IN (0,?) ORDER BY IsDefault DESC, AD_Client_ID DESC, C_TaxCategory_ID"; + int C_TaxCategory_ID = DB.getSQLValueEx(null, sql, Env.getAD_Client_ID(ctx)); + prod.setC_TaxCategory_ID(C_TaxCategory_ID); + // + prod.saveEx(trxName); + } + else { + prod = new MProduct(ctx, M_Product_ID, trxName); + } + + setProduct(prod); + return prod; + } // getCreateProduct + + /** + */ + private void fixAmount(int idx) { + //~ try { + BigDecimal amt = (BigDecimal)get_Value(idx); + if (amt == null) + return; + + int precision = getStdPrecision(); + BigDecimal newAmt = amt.setScale(getStdPrecision(), RoundingMode.HALF_UP); + set_Value(idx, newAmt); + if(CLogMgt.isLevelFine()) log.fine(getInventoryNo() + ": " + get_ColumnName(idx) + "=" + amt + "->" + newAmt + " (precision=" + precision + ")"); + //~ } catch (Exception e) {} + } + + /** + */ + private void fixKeyValue(int idx) { + //~ try { + String name = (String)get_Value(idx); + if (name == null) + return; + String newName = name.trim().replaceAll("[ ]+", " "); + if(CLogMgt.isLevelFine()) log.fine(getInventoryNo() + ": " + get_ColumnName(idx) + "=[" + name + "]->[" + newName + "]"); + set_Value(idx, newName); + //~ } catch (Exception e) {} + } + + /** + * + */ + public void process() + { + if (isProcessed()) { + return ; + } + try { + if (getUseLifeMonths() <= 0) + { + throw new FillMandatoryException(COLUMNNAME_UseLifeMonths); + } + /*//comment by @win + if (getA_Asset_Class_ID() <= 0) + { + throw new FillMandatoryException(COLUMNNAME_A_Asset_Class_ID); + } + + // Fix Asset Class + MAssetClass assetClass = MAssetClass.get(getCtx(), getA_Asset_Class_ID()); + setA_Asset_Class_Value(assetClass.getValue()); + */ //end comment by @win + + // Round amounts: + int col_count = get_ColumnCount(); + for (int idx = 0; idx < col_count; idx++) + { + int dt = get_ColumnDisplayType(idx); + if (DisplayType.Amount == dt) + fixAmount(idx); + else if (DisplayType.isText(dt)) + fixKeyValue(idx); + } + + // Create/Set Product + MProduct product = getCreateProduct(); + log.fine("product=" + product); + if (getM_Product_ID() <= 0) { + throw new FillMandatoryException(COLUMNNAME_M_Product_ID); + } + + // Check Asset Group + int A_Asset_Group_ID = getA_Asset_Group_ID(); + if (A_Asset_Group_ID <= 0) + { + if (m_A_Asset_Group_ID > 0) { + A_Asset_Group_ID = m_A_Asset_Group_ID; + } + else { + A_Asset_Group_ID = product.getA_Asset_Group_ID(); + } + } + if (A_Asset_Group_ID > 0) + { + setA_Asset_Group_ID(A_Asset_Group_ID); + } + else + { + throw new FillMandatoryException(COLUMNNAME_A_Asset_Group_ID); + } + + // Set DateAcct + if (getA_Remaining_Period() == 0) + { + setDateAcct(getAssetDepreciationDate()); + } + else + { + Timestamp dateAcct = getDateAcct(); + if (dateAcct == null) + { + dateAcct = Env.getContextAsDate(getCtx(), "#Date"); + setDateAcct(dateAcct); + } + } + if (getDateAcct() == null) + { + throw new FillMandatoryException(COLUMNNAME_DateAcct); + } + + // Set Processed + setProcessed(true); + setI_ErrorMsg(null); + + // Save + saveEx(); + } + catch (Exception e) + { + setError(e.getLocalizedMessage()); + saveEx(); + } + } + + /** + * @return Este MF-ul depreciat integral + */ + public boolean isFullyDepreciated() + { + BigDecimal cost = getA_Asset_Cost(); + BigDecimal depr_c = getA_Accumulated_Depr(); + BigDecimal depr_f = getA_Accumulated_Depr_F(); + + return cost.compareTo(depr_c) == 0 && cost.compareTo(depr_f) == 0; + } + + /** + * @return Asset is Depreciating + */ + public boolean isDepreciating() + { + /* commented by @win + MAssetClass assetClass = MAssetClass.get(getCtx(), getA_Asset_Class_ID()); + if (assetClass == null) + return false; + return assetClass.isDepreciated(); + */ + //change logic to assetGroup + MAssetGroup assetGroup = MAssetGroup.get(getCtx(), getA_Asset_Group_ID()); + if (assetGroup == null) + return false; + return assetGroup.isDepreciated(); + //end modify by @win + } + + /** + * @return + */ + public int getA_Last_Period() + { + int life = getUseLifeMonths(); + int life_f = getUseLifeMonths_F(); + return life > life_f ? life : life_f; + } + + /** */ + private int m_M_Product_Category_ID = 0; + public void setDefault_Product_Category_ID(int M_Product_Category_ID) { + m_M_Product_Category_ID = M_Product_Category_ID; + } + + /** */ + private int m_A_Asset_Group_ID = 0; + public void setDefault_Asset_Group_ID(int A_Asset_Group_ID) { + m_A_Asset_Group_ID = A_Asset_Group_ID; + } + + /** Product */ + private MProduct m_product = null; + public void setProduct(MProduct product) { + m_product = product; + setM_Product_ID(product.get_ID()); + setProductValue(product.getValue()); + if (Util.isEmpty(getName())) + setName(product.getName()); + } + public MProduct getProduct() { + if (m_product == null && getM_Product_ID() > 0) { + m_product = new MProduct(getCtx(), getM_Product_ID(), get_TrxName()); + } + return m_product; + } + + /** Depreciation Method */ + public int getA_Depreciation_ID() { + MDepreciation depr = MDepreciation.get(getCtx(), s_defaultDepreciationType); + return depr != null ? depr.get_ID() : 0; + } + public int getA_Depreciation_F_ID() { + return getA_Depreciation_ID(); + } + + /** Currency */ + public int getStdPrecision() { + return MClient.get(getCtx()).getAcctSchema().getStdPrecision(); + } + + /** String representation */ + public String getSummary() { + return getInventoryNo() + " - " + getName(); + } + + /** Sets custom error + * + */ + public void setError(String msg) { + String msg_trl = Msg.parseTranslation(getCtx(), msg); + setI_ErrorMsg(msg_trl); + } +} diff --git a/org.adempiere.base/src/org/compiere/model/SetGetModel.java b/org.adempiere.base/src/org/compiere/model/SetGetModel.java new file mode 100644 index 0000000000..6eb3e126a4 --- /dev/null +++ b/org.adempiere.base/src/org/compiere/model/SetGetModel.java @@ -0,0 +1,20 @@ +package org.compiere.model; + +import java.util.Properties; + +/** + * Set Get Object interface + * @author Teo Sarca, SC ARHIPAC SERVICE SRL + */ +public interface SetGetModel +{ + public Properties getCtx(); + public String get_TrxName(); + // + public int get_Table_ID(); + public String get_TableName(); + // + public boolean set_AttrValue(String name, Object value); + public Object get_AttrValue(String name); + public boolean is_AttrValueChanged(String ColumnName); +} diff --git a/org.adempiere.base/src/org/compiere/model/SetGetUtil.java b/org.adempiere.base/src/org/compiere/model/SetGetUtil.java new file mode 100644 index 0000000000..f79584f6cd --- /dev/null +++ b/org.adempiere.base/src/org/compiere/model/SetGetUtil.java @@ -0,0 +1,796 @@ +/****************************************************************************** + * Product: Adempiere ERP & CRM Smart Business Solution * + * Copyright (C) 1999-2006 ComPiere, Inc. All Rights Reserved. * + * This program is free software; you can redistribute it and/or modify it * + * under the terms version 2 of the GNU General Public License as published * + * by the Free Software Foundation. This program is distributed in the hope * + * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied * + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + * See the GNU General Public License for more details. * + * You should have received a copy of the GNU General Public License along * + * with this program; if not, write to the Free Software Foundation, Inc., * + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * + * For the text or an alternative of this public license, you may reach us * + * ComPiere, Inc., 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA * + * or via info@compiere.org or http://www.compiere.org/license.html * + * Contributor(s): Teo Sarca, (tentative) * + *****************************************************************************/ + +package org.compiere.model; + +import java.lang.reflect.Proxy; +import java.math.BigDecimal; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Properties; + +import org.adempiere.exceptions.AdempiereException; +import org.adempiere.exceptions.DBException; +import org.compiere.util.CLogMgt; +import org.compiere.util.CLogger; +import org.compiere.util.DB; +import org.compiere.util.Env; +import org.compiere.util.Language; +import org.compiere.util.Util; + + +public class SetGetUtil +{ + /** Static logger */ + private static CLogger s_log = CLogger.getCLogger(SetGetUtil.class); + + /** + * Update columns from the result of the given query. + *

If the query returns more than one row, only the first row will be used. + *

This is a simplified version of {@link #updateColumns(SetGetModel[], String[], String, String)} + * which calls: + *

updateColumns(new SetGetModel[]{model}, columnNames, query, trxName);
+ * + * @param model + * @param columnNames + * column names; if null, all columns from given query are used; + * if a columnName from array is null it will be ignored + * @param sql sql query + * @param params sql parameters + * @param trxName + * + * @see #updateColumns(SetGetModel[], String[], String, String) + */ + public static void updateColumns(SetGetModel model, String[] columnNames, String sql, Object[] params, String trxName) + { + updateColumns(new SetGetModel[]{model}, columnNames, sql, params, trxName); + } + public static void updateColumns(SetGetModel model, String[] columnNames, String sql, String trxName) + { + updateColumns(new SetGetModel[]{model}, columnNames, sql, null, trxName); + } + + /** + * Update columns from the result of the given query. + * + * @param models + * @param columnNames + * @param sql + * @param params + * @param trxName + * + * @see #updateColumns(SetGetModel[], String[], ResultSet) + */ + public static void updateColumns(SetGetModel[] models, String[] columnNames, + String sql, Object[] params, + String trxName) + { + PreparedStatement pstmt = null; + ResultSet rs = null; + try + { + pstmt = DB.prepareStatement(sql, trxName); + DB.setParameters(pstmt, params); + rs = pstmt.executeQuery(); + updateColumns(models, columnNames, rs); + } + catch (SQLException e) + { + throw new DBException(e, sql); + } + finally + { + DB.close(rs, pstmt); + rs = null; pstmt = null; + } + } // updateColumns + + /** + * Update columns from the result of the given query. + * + * @param models + * @param columnNames + * column names; if null, all columns from given query are used; + * if a columnName from array is null it will be ignored + * @param rs + * @throws SQLException + */ + public static void updateColumns(SetGetModel[] models, String[] columnNames, ResultSet rs) + throws SQLException + { + for (SetGetModel model : models) + { + if(CLogMgt.isLevelFinest()) s_log.finest("Model: " + model); + if (rs.next()) + { + if (columnNames == null) + { + columnNames = getColumnNames(rs); + } + for(String columnName : columnNames) + { + if (Util.isEmpty(columnName)) + continue; + // + Object obj = null; + boolean ok = false; + obj = rs.getObject(columnName); + // + // Date Columns are retuned as Date -> convert to java.sql.Timestamp + if (obj instanceof java.sql.Date) + { + obj = new java.sql.Timestamp(((java.sql.Date)obj).getTime()); + } + // + // ID Columns (integer) are returned as BigDecimal -> convert to Integer + else if (obj instanceof BigDecimal && columnName.endsWith("_ID")) + { + obj = ((BigDecimal)obj).intValue(); + } + // + ok = model.set_AttrValue(columnName, obj); + if (CLogMgt.isLevelFinest()) s_log.finest("columnName=" + columnName + ", value=[" + obj + "][" + (obj != null ? obj.getClass().getName() : "null") + "], ok=" + ok); + } + } + else + { + s_log.finest("@NoResult@"); + break; + } + } + } // updateColumns + + public static void updateColumns(SetGetModel model, String[] columnNames, ResultSet rs) + throws SQLException + { + updateColumns(new SetGetModel[]{model}, columnNames, rs); + } + + + /** + * Get Array of Column Names (String) for given ResultSet + * @param rs + * @return column names (upper case) + * @throws SQLException + */ + private static final String[] getColumnNames(ResultSet rs) + throws SQLException + { + if (rs == null) + { + return new String[0]; + } + ResultSetMetaData rsmd = rs.getMetaData(); + int no = rsmd.getColumnCount(); + String[] columnNames = new String[no]; + for (int i = 1; i <= no; i++) + { + columnNames[i - 1] = rsmd.getColumnName(i).toUpperCase(); + } + // + return columnNames; + } // getColumnName + + /** + * Copy from the fields to. + * The second object is not required to be in the same table. + * The following fields are not copied: AD_Client_ID, AD_Org_ID, Created% Updated% IsActive. + * If excludeFields includeFields and are null, then it will copy all the fields (which can be copied). + * @ param to destination object + * @ param object from source + * @ param includeFields name fields to be excluded; null will be interpreted as String [0]; + * excludeFields includeFields and mutually exclusive, priority being includeFields; + * If includeFields excludeFields are null and then copy all fields + * @ param excludeFields name fields to be excluded, null will be interpreted as String [0] + * @return false if "to" or "from" is null, true otherwise + */ + public static boolean copyValues(PO to, PO from, String[] includeFields, String[] excludeFields) + { + int no = copyValues(to, from, includeFields, excludeFields, false); + return no >= 0; + } + + /** + * Copy all values from "from" to "to" + * @return number of columns that were copied and were were also changed in object "from" + * @see #copyValues(PO, PO, String[], String[]) + */ + public static int copyChangedValues(PO to, PO from) + { + return copyValues(to, from, null, null, true); + } + /** + * + * @param to + * @param from + * @param includeFields + * @param excludeFields + * @param trackOnlyChanges counts only the fields that were changed from + * (from.is_ValueChanged(int idx)) + * @return -1 the error or the number of heads that have been copied; + * if trackOnlyChanges = true then copied and include only the columns that have changed and "from" + */ + private static int copyValues(PO to, PO from, + String[] includeFields, String[] excludeFields, + boolean trackOnlyChanges) + { + if (CLogMgt.isLevelFinest()) + { + s_log.finest("Entering: From=" + from+ " - To=" + to); +// s_log.finest("includeFields=" + ARHIPAC.toString(includeFields)); +// s_log.finest("excludeFields=" + ARHIPAC.toString(excludeFields)); + } + // + if (to == null || from == null) + { + if (CLogMgt.isLevelFinest()) + { + s_log.finest("Leaving: to == null || from == null"); + Thread.dumpStack(); + } + return -1; + } + // + if(includeFields != null) + { + excludeFields = null; + } + if (includeFields == null && excludeFields == null) + { + excludeFields = new String[]{"#"}; // dummy value + } + // + int copiedFields = 0; + for (int idx_from = 0; idx_from < from.get_ColumnCount(); idx_from++) + { + String colName = from.p_info.getColumnName(idx_from); + boolean isExcluded = false; + // + // Ignore Standard Values + if ("Created".equals(colName) + || "CreatedBy".equals(colName) + || "Updated".equals(colName) + || "UpdatedBy".equals(colName) + || "IsActive".equals(colName) + || "AD_Client_ID".equals(colName) + || "AD_Org_ID".equals(colName) + ) + { + isExcluded = true; + } + // + // Include Policy + else if (includeFields != null) + { + isExcluded = true; + for(String incl : includeFields) + { + if (incl.equalsIgnoreCase(colName)) + { + isExcluded = false; + break; + } + } + } + // + // Exclude Policy + else if (excludeFields != null) + { + for(String excl : excludeFields) + { + if (excl.equalsIgnoreCase(colName)) + { + isExcluded = true; + break; + } + } + } + //- + if (isExcluded) + { + if (CLogMgt.isLevelFinest()) s_log.finest("Field " + colName + " [SKIP:excluded]"); + continue; + } + + int idx_to = to.get_ColumnIndex(colName); + if (idx_to < 0) + { + if (CLogMgt.isLevelFinest()) s_log.finest("Field " + colName + " [SKIP:idx_to < 0]"); + continue; + } + if (to.p_info.isVirtualColumn(idx_to) || to.p_info.isKey(idx_to)) + { // KeyColumn + if (CLogMgt.isLevelFinest()) s_log.finest("Field " + colName + " [SKIP:virtual or key]"); + continue; + } + + Object value = from.get_Value(idx_from); + to.set_Value(idx_to, value); + + if (!trackOnlyChanges || from.is_ValueChanged(idx_from)) + { + copiedFields++; + } + if (CLogMgt.isLevelFinest()) s_log.finest("Field " + colName + "=[" + value + "], idx=" + idx_from + "->" + idx_to); + } + // + if (CLogMgt.isLevelFinest()) s_log.finest("Leaving: to=" + to); + return copiedFields; + } // copyValues + + /** + * Copy from the fields to the. + * The two objects do not need to be in the same table. + * @param to destination object + * @param from_tableName source object table + * @param from_id source object ID + * @param includeFields name fields to be excluded, null will be interpreted as String[0]; + * @see #updateColumns(SetGetModel, String[], String, String) + */ + public static boolean copyValues(SetGetModel to, String from_tableName, int from_id, String[] includeFields) + { + if (to == null || from_tableName == null || from_id <= 0 + || includeFields == null || includeFields.length == 0) + { + return false; + } + + StringBuffer sql = new StringBuffer(); + for (String f : includeFields) + { + if (sql.length() > 0) + sql.append(","); + sql.append(f); + } + sql.insert(0, "SELECT "); + sql.append(" FROM ").append(from_tableName) + .append(" WHERE ").append(from_tableName).append("_ID=").append(from_id); + + updateColumns(to, includeFields, sql.toString(), null); + return true; + } + + /** + * Get Value as integer + * @param model + * @param name + * @return int value + */ + public static int get_AttrValueAsInt(SetGetModel model, String name) + { + Object o = model.get_AttrValue(name); + if (o instanceof Number) + return ((Number)o).intValue(); + return 0; + } // get_AttrValueAsInt + + /** + * Get Value as Timestamp + * @param model + * @param name + * @return Timestamp value + */ + public static Timestamp get_AttrValueAsDate(SetGetModel model, String name) + { + Object o = model.get_AttrValue(name); + if (o instanceof Timestamp) + return (Timestamp)o; + return null; + } // get_AttrValueAsDate + + /** + * Get Value as BigDecimal + * @param model + * @param name + * @return BigDecimal or {@link BigDecimal#ZERO} + */ + public static BigDecimal get_AttrValueAsBigDecimal(SetGetModel model, String name) + { + Object o = model.get_AttrValue(name); + if (o instanceof BigDecimal) + return (BigDecimal)o; + return BigDecimal.ZERO; + } // get_AttrValueAsBigDecimal + + /** + * Get Value as Boolean + * @param model + * @param name + * @return boolean value + */ + public static boolean get_AttrValueAsBoolean(SetGetModel model, String name) + { + Object o = model.get_AttrValue(name); + if (o != null) { + if (o instanceof Boolean) + return ((Boolean)o).booleanValue(); + else + return "Y".equals(o); + } + return false; + } + + /** + * Get Value as String + * @param model + * @param name + * @param valueIfNull value that will be returned if the value is null + * @return String value + */ + public static String get_AttrValueAsString(SetGetModel model, String name, String valueIfNull) + { + Object o = model.get_AttrValue(name); + if (o == null) + return valueIfNull; + return o.toString(); + } + + /** + * Set Attribute Value + * @param model + * @param name + * @param value + * @throws AdempiereException if it can not be set (error setting, attribute/column name not found). + */ + public static void set_AttrValueEx(SetGetModel model, String name, Object value) + { + if (!model.set_AttrValue(name, value)) + throw new AdempiereException("Value not set "+name+"="+value); + } + + /** + * @param model + * @param propertyNames + * @return true if ANY of given properties had changed + */ + public static boolean is_ValueChanged(SetGetModel model, String ... propertyNames) + { + for (String name : propertyNames) + { + if (model.is_AttrValueChanged(name)) + { + return true; + } + } + return false; + } + + /** + * Get TrxName for given object. + * @param o + * @return trxName or null + */ + public static String getTrxName(Object o) + { + if (o == null) + { + return null; + } + else if (o instanceof SetGetModel) + { + return ((SetGetModel)o).get_TrxName(); + } + else if (o instanceof PO) + { + return ((PO)o).get_TrxName(); + } + else + { + return null; + } + } + + /** + * Check if given object was produced by used entry (i.e. created from a window) + * @param o object + * @return If object is instanceof PO then {@link PO#is_UserEntry()} will be checked. + * If object is null then false will be returned. + * Else true will be returned. + */ + public static boolean isUserEntry(Object o) + { + if (o == null) + { + return false; + } + else if (o instanceof PO) + { +// return ((PO)o).is_UserEntry(); + return false; // TODO + } + else + { + return true; + } + } + + + /** + * Set model's Line# + * @param model + * @param parentColumnName parent column name; if null then it won't be used + * @param lineColumnName line column name; if null "Line" will be used + */ + public static void setLineNo(SetGetModel model, String parentColumnName, String lineColumnName) + { + if (lineColumnName == null) + { + lineColumnName = "Line"; + } + int lineNo = get_AttrValueAsInt(model, lineColumnName); + if (lineNo != 0) + { + return; + } + // + String tableName = model.get_TableName(); + String idColumnName = tableName+"_ID"; + // + Collection params = new ArrayList(); + StringBuffer sql = new StringBuffer("SELECT COALESCE(MAX("+lineColumnName+"),0)+10"); + sql.append(" FROM ").append(tableName); + // Only active records + sql.append(" WHERE IsActive=?"); + params.add(true); + // Client Security Check + sql.append(" AND AD_Client_ID IN (0,?)"); + params.add(SetGetUtil.get_AttrValueAsInt(model, "AD_Client_ID")); + // Ignore this record + sql.append(" AND ").append(idColumnName).append("<>?"); + params.add(get_AttrValueAsInt(model, idColumnName)); + // With same parent (if defined) + if (parentColumnName != null) + { + sql.append(" AND ").append(parentColumnName).append("=?"); + params.add(get_AttrValueAsInt(model, parentColumnName)); + } + // + // Set LineNo + lineNo = DB.getSQLValueEx(model.get_TrxName(), sql.toString(), params); + model.set_AttrValue(lineColumnName, lineNo); + } + + /** + * Get Table_Name for given PO class + * @param clazz + * @return tableName + * @throws AdempiereException if no table name found or any other exception occurs + */ + public static String getTableName(Class clazz) + { + try + { + return (String) clazz.getField("Table_Name").get(null); + } + catch (Exception e) + { + throw new AdempiereException(e); + } + } + + /** + * Check if given object is persistent object + * @param o object + * @return true if is persistent (i.e. instanceof PO) + */ + public static final boolean isPersistent(Object o) + { + return o != null && o instanceof PO; + } + + /** + * Get Context from given object. + * If object is null, null will be returned. + * If object does not have getCtx() support then Env.getCtx() will be returned. + * @param o object + * @return context or null(if object is null) + */ + public static Properties getCtx(Object o) + { + if(o == null) + { + return null; + } + else if (o instanceof SetGetModel) + { + return ((SetGetModel)o).getCtx(); + } + if (o instanceof PO) + { + return ((PO)o).getCtx(); + } + return Env.getCtx(); + } + + /** + * Wrap given object (if possible) to SetGetModel + * @param o object + * @return object wrapped to SetGetModel + */ + public static SetGetModel wrap(Object o) + { + if (o == null) + { + return null; + } + else if (o instanceof SetGetModel && !(o instanceof Proxy)) + { + return (SetGetModel)o; + } + else if (o instanceof Proxy + && Proxy.getInvocationHandler(o) instanceof org.adempiere.model.GridTabWrapper) + { + org.adempiere.model.GridTabWrapper gtw = (org.adempiere.model.GridTabWrapper)Proxy.getInvocationHandler(o); + return new GridTab2SetGetModelWrapper(gtw.getGridTab()); + } + else if (o instanceof GridTab) + { + return new GridTab2SetGetModelWrapper((GridTab)o); + } + else if (o instanceof PO) + { + final PO po = (PO)o; + return new SetGetModel() { + public boolean set_AttrValue(String name, Object value) { + return po.set_Value(name, value); + } + public boolean is_AttrValueChanged(String ColumnName) { + return po.is_ValueChanged(ColumnName); + } + public String get_TrxName() { + return po.get_TrxName(); + } + public int get_Table_ID() { + return po.get_Table_ID(); + } + public String get_TableName() { + return po.get_TableName(); + } + public Object get_AttrValue(String name) { + return po.get_Value(name); + } + public Properties getCtx() { + return po.getCtx(); + } + }; + } + else + { + throw new IllegalArgumentException("Can not wrap to SetGetModel - "+o.getClass()); + } + } + + public static T newInstance(Properties ctx, Class clazz, String trxName) + { + try + { + return clazz.getConstructor(Properties.class, int.class, String.class) + .newInstance(ctx, 0, trxName); + } + catch(Exception e) + { + throw new AdempiereException(e); + } + } + + public static void appendValue(SetGetModel model, String columnName, String value) + { + if (Util.isEmpty(value, true)) + { + return; + } + // + final String valueToAppend = value.trim(); + final String valueOld = get_AttrValueAsString(model, columnName, null); + final String valueNew; + if (Util.isEmpty(valueOld, true)) + { + valueNew = value; + } + else + { + valueNew = valueOld + " | " + valueToAppend; + } + // + model.set_AttrValue(columnName, valueNew); + } + + /** + * Get Info for given table and ID. + * This method calls {@link MLookupFactory#getLookup_TableDirEmbed(Language, String, String, String) to + * generate the info string. + * @param ctx context + * @param tableName tablename + * @param id record id + * @param trxName + * @return record description + */ + public static String getInfoString(Properties ctx, String tableName, int id, String trxName) + { + Language language = Env.getLanguage(ctx); + String sql = MLookupFactory.getLookup_TableDirEmbed(language, tableName+"_ID", "[?","?]") + .replace("[?.?]", "?"); + String docInfo = DB.getSQLValueStringEx(trxName, sql, id); + if (Util.isEmpty(docInfo)) + { + docInfo = "<"+tableName+":"+id+">"; + } + return docInfo; + } + + private static class GridTab2SetGetModelWrapper implements SetGetModel + { + private final GridTab tab; + GridTab2SetGetModelWrapper(GridTab tab) + { + this.tab = tab; + } + + public Properties getCtx() + { + return Env.getCtx(); + } + + public Object get_AttrValue(String name) + { + return tab.getValue(name); + } + + public String get_TableName() + { + return tab.getTableName(); + } + + public int get_Table_ID() + { + return tab.getAD_Table_ID(); + } + + public String get_TrxName() + { + return null; + } + /** + * Is Attribute value changed (SetGetModel.is_AttrValueChanged) + * NOT SUPPORTED + * @param ColumnName + * @return ALWAYS RETURN FALSE + */ + + public boolean is_AttrValueChanged(String ColumnName) + { + return false; // TODO: implement it + } + + public boolean set_AttrValue(String name, Object value) + { + String errmsg = tab.setValue(name, value); + if (errmsg != null && errmsg.length() > 0) + { + //~ log.saveError("Error", errmsg); + return false; + } + return true; + } + } +} diff --git a/org.adempiere.base/src/org/compiere/util/ArhRuntimeException.java b/org.adempiere.base/src/org/compiere/util/ArhRuntimeException.java new file mode 100644 index 0000000000..a1dc5c4978 --- /dev/null +++ b/org.adempiere.base/src/org/compiere/util/ArhRuntimeException.java @@ -0,0 +1,186 @@ +/** + * + */ +package org.compiere.util; + +import java.sql.Timestamp; +import java.text.SimpleDateFormat; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Properties; + +import org.adempiere.exceptions.AdempiereException; + +/** + * Arhipac Runtime exception + * @author Teo_Sarca, SC ARHIPAC SERVICE SRL + * + */ +public class ArhRuntimeException + extends AdempiereException +{ + /** + * + */ + private static final long serialVersionUID = -100343773302909791L; + /** Additional attributes */ + private HashMap m_info = new HashMap(); + + /** + * Default Constructor (logger error will be used as message) + */ + public ArhRuntimeException() { + super(); + } + + /** + * Constructor + * @param message error message or "" if you don't need a message + */ + public ArhRuntimeException(String message) { + super(message); + } + + /** + * Constructor + * @param ctx + * @param message + */ + public ArhRuntimeException(Properties ctx, String message) { + this(message); + } + + /** + * @param cause + */ + public ArhRuntimeException(Throwable cause) { + super(cause); + } + + /** + * @param message + * @param cause + */ + public ArhRuntimeException(String message, Throwable cause) { + super(message, cause); + } + + /* (non-Javadoc) + * @see java.lang.Throwable#getLocalizedMessage() + */ + + public String getLocalizedMessage() { + StringBuffer sb = new StringBuffer(); + Properties ctx = Env.getCtx(); + // Message + String msg = getMessage(); + if (msg != null && msg.length() > 0) { + sb.append(Msg.parseTranslation(ctx, msg)); + } + else { + msg = null; + } + // Additional info: + if (m_info.size() > 0) { + Iterator it = m_info.keySet().iterator(); + int cnt = 0; + while(it.hasNext()) { + String name = it.next(); + Object value = m_info.get(name); + if (cnt == 0) { + if (msg != null) + sb.append(" ("); + } + else { + sb.append(", "); + } + sb.append(Msg.parseTranslation(ctx, name)); + String svalue = getStringValue(value); + if (value != null && svalue.length() > 0) + sb.append(" ").append(svalue); + cnt++; + } + if (cnt > 0 && msg != null) { + sb.append(")"); + } + } + // + return sb.toString(); + } + + /** + * Save error + */ + public void saveError(CLogger log) { + log.saveError("Error", getLocalizedMessage()); + } + + /** + * + */ + public ArhRuntimeException addInfo(String name, boolean value) { + return addInfo(name, Boolean.valueOf(value)); + } + + /** + * + */ + public ArhRuntimeException addInfo(String name) { + return addInfo(name, ""); + } + + /** + * + */ + public ArhRuntimeException addInfo(String name, Object value) { + if (name == null) + return this; + m_info.put(name, value); + return this; + } + + public ArhRuntimeException addField(String fieldName, Object value) { + addInfo("@" + fieldName + "@ =", value); + return this; + } + + /** + * + */ + public boolean hasInfo() { + return !m_info.isEmpty(); + } + + /** + * Translated string representation of the provided value + * @param value + * @return + */ + private String getStringValue(Object value) { + String svalue = null; + if (value == null) { + svalue = "-"; + } + else if (value instanceof Boolean) { + svalue = Msg.getMsg(Env.getCtx(), ((Boolean)value).booleanValue() ? "Yes" : "No"); + } + else if (value instanceof Timestamp) { + SimpleDateFormat df = DisplayType.getDateFormat(); + svalue = df.format((Timestamp)value); + } + else { + svalue = value.toString(); + } + return svalue; + } + + /* (non-Javadoc) + * @see java.lang.Throwable#toString() + */ + + public String toString() { + return getLocalizedMessage(); + } + + +} diff --git a/org.adempiere.base/src/org/idempiere/exceptions/NoCurrencyConversionException.java b/org.adempiere.base/src/org/idempiere/exceptions/NoCurrencyConversionException.java new file mode 100644 index 0000000000..4327b4bd31 --- /dev/null +++ b/org.adempiere.base/src/org/idempiere/exceptions/NoCurrencyConversionException.java @@ -0,0 +1,86 @@ +/****************************************************************************** + * Product: Adempiere ERP & CRM Smart Business Solution * + * Copyright (C) 2008 SC ARHIPAC SERVICE SRL. All Rights Reserved. * + * This program is free software; you can redistribute it and/or modify it * + * under the terms version 2 of the GNU General Public License as published * + * by the Free Software Foundation. This program is distributed in the hope * + * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied * + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + * See the GNU General Public License for more details. * + * You should have received a copy of the GNU General Public License along * + * with this program; if not, write to the Free Software Foundation, Inc., * + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * + *****************************************************************************/ +package org.idempiere.exceptions; + +import java.sql.Timestamp; +import java.text.DateFormat; + +import org.adempiere.exceptions.AdempiereException; +import org.compiere.model.MConversionType; +import org.compiere.model.MCurrency; +import org.compiere.util.DB; +import org.compiere.util.DisplayType; +import org.compiere.util.Env; + +/** + * Any exception that occurs when no currency conversion rate was found + * @author Teo Sarca, http://www.arhipac.ro + */ +public class NoCurrencyConversionException extends AdempiereException +{ + private static final long serialVersionUID = 1L; + + /** + * + * @param C_Currency_ID + * @param C_Currency_ID_To + * @param ConvDate + * @param C_ConversionType_ID + * @param AD_Client_ID + * @param AD_Org_ID + */ + public NoCurrencyConversionException (int C_Currency_ID, int C_Currency_ID_To, + Timestamp ConvDate, + int C_ConversionType_ID, + int AD_Client_ID, int AD_Org_ID) + { + super(buildMessage(C_Currency_ID, C_Currency_ID_To, + ConvDate, + C_ConversionType_ID, + AD_Client_ID, AD_Org_ID)); + } + + private static final String buildMessage(int C_Currency_ID, int C_Currency_ID_To, + Timestamp ConvDate, + int C_ConversionType_ID, + int AD_Client_ID, int AD_Org_ID) + { + DateFormat df = DisplayType.getDateFormat(DisplayType.Date); + + StringBuffer sb = new StringBuffer("@NoCurrencyConversion@ ") + .append(MCurrency.getISO_Code(Env.getCtx(), C_Currency_ID)) + .append("->") + .append(MCurrency.getISO_Code(Env.getCtx(), C_Currency_ID_To)); + // + sb.append(", @Date@: "); + if (ConvDate != null) + sb.append(df.format(ConvDate)); + else + sb.append("*"); + // + sb.append(", @C_ConversionType_ID@: "); + if (C_ConversionType_ID > 0) + { + final String sql = "SELECT "+MConversionType.COLUMNNAME_Name+" FROM "+MConversionType.Table_Name + +" WHERE "+MConversionType.COLUMNNAME_C_ConversionType_ID+"=?"; + String name = DB.getSQLValueString(null, sql, C_ConversionType_ID); + sb.append(name); + } + else + { + sb.append("*"); + } + return sb.toString(); + } +} diff --git a/org.adempiere.base/src/org/idempiere/fa/exceptions/AssetAlreadyDepreciatedException.java b/org.adempiere.base/src/org/idempiere/fa/exceptions/AssetAlreadyDepreciatedException.java new file mode 100644 index 0000000000..09a7a34ea6 --- /dev/null +++ b/org.adempiere.base/src/org/idempiere/fa/exceptions/AssetAlreadyDepreciatedException.java @@ -0,0 +1,20 @@ +/** + * + */ +package org.idempiere.fa.exceptions; + + +/** + * Asset is already depreciated and this is an issue for the action that invoked this exception + * @author Teo Sarca, SC ARHIPAC SERVICE SRL + * + */ +public class AssetAlreadyDepreciatedException extends AssetException +{ + private static final long serialVersionUID = 1L; + + public AssetAlreadyDepreciatedException() + { + super("@AssetAlreadyDepreciated@"); + } +} diff --git a/org.adempiere.base/src/org/idempiere/fa/exceptions/AssetArrayException.java b/org.adempiere.base/src/org/idempiere/fa/exceptions/AssetArrayException.java new file mode 100644 index 0000000000..aa21a23a08 --- /dev/null +++ b/org.adempiere.base/src/org/idempiere/fa/exceptions/AssetArrayException.java @@ -0,0 +1,33 @@ +/** + * + */ +package org.idempiere.fa.exceptions; + +import java.util.List; + +/** + * @author Teo Sarca, www.arhipac.ro + * + */ +public class AssetArrayException extends AssetException +{ + /** + * + */ + private static final long serialVersionUID = -6145405299338077726L; + + public AssetArrayException(List errors) + { + super(buildMessage(errors)); + } + + private static String buildMessage(List errors) + { + StringBuffer sb = new StringBuffer("The following errors were encountered: "); // TODO: translate + for (Exception e : errors) + { + sb.append("\n"+e.getLocalizedMessage()); + } + return sb.toString(); + } +} diff --git a/org.adempiere.base/src/org/idempiere/fa/exceptions/AssetCheckDocumentException.java b/org.adempiere.base/src/org/idempiere/fa/exceptions/AssetCheckDocumentException.java new file mode 100644 index 0000000000..3b87d551ff --- /dev/null +++ b/org.adempiere.base/src/org/idempiere/fa/exceptions/AssetCheckDocumentException.java @@ -0,0 +1,19 @@ +/** + * + */ +package org.idempiere.fa.exceptions; + + +/** + * @author Teo Sarca, SC ARHIPAC SERVICE SRL + * + */ +public class AssetCheckDocumentException extends AssetException +{ + private static final long serialVersionUID = 1L; + + public AssetCheckDocumentException(String additionalMessage) + { + super ("@CheckDocument@ - "+additionalMessage); // TODO: AD_Message + } +} diff --git a/org.adempiere.base/src/org/idempiere/fa/exceptions/AssetException.java b/org.adempiere.base/src/org/idempiere/fa/exceptions/AssetException.java new file mode 100644 index 0000000000..fb0f6c2619 --- /dev/null +++ b/org.adempiere.base/src/org/idempiere/fa/exceptions/AssetException.java @@ -0,0 +1,35 @@ +/** + * + */ +package org.idempiere.fa.exceptions; + +import org.adempiere.exceptions.AdempiereException; + +/** + * Asset Related General Exception. This is the root of all Asset Related Exceptions. + * @author Teo Sarca, SC ARHIPAC SERVICE SRL + */ +public class AssetException extends AdempiereException +{ + private static final long serialVersionUID = 1L; + + public AssetException() + { + super(); + } + + public AssetException(String message) + { + super(message); + } + + public AssetException(Throwable cause) + { + super(cause); + } + + public AssetException(String message, Throwable cause) + { + super(message, cause); + } +} diff --git a/org.adempiere.base/src/org/idempiere/fa/exceptions/AssetInvalidTransitionException.java b/org.adempiere.base/src/org/idempiere/fa/exceptions/AssetInvalidTransitionException.java new file mode 100644 index 0000000000..055bf78436 --- /dev/null +++ b/org.adempiere.base/src/org/idempiere/fa/exceptions/AssetInvalidTransitionException.java @@ -0,0 +1,40 @@ +/** + * + */ +package org.idempiere.fa.exceptions; + +import org.compiere.model.MAsset; +import org.compiere.model.MRefList; + + +/** + * @author Teo Sarca, SC ARHIPAC SERVICE SRL + * + */ +public class AssetInvalidTransitionException extends AssetException +{ + /** + * + */ + private static final long serialVersionUID = -4356632909207763285L; + + private String oldStatus = null; + private String newStatus = null; + + public AssetInvalidTransitionException(String oldStatus, String newStatus) + { + super("@AssetInvalidTransition@ @"+oldStatus+"@ -> @"+newStatus+"@"); + this.oldStatus = oldStatus; + this.newStatus = newStatus; + } + + + public String getLocalizedMessage() + { + String msg = super.getLocalizedMessage(); + return msg.replace("@"+this.oldStatus+"@", MRefList.getListName(getCtx(), MAsset.A_ASSET_STATUS_AD_Reference_ID, this.oldStatus)) + .replace("@"+this.newStatus+"@",MRefList.getListName(getCtx(), MAsset.A_ASSET_STATUS_AD_Reference_ID, this.newStatus)); + } + + +} diff --git a/org.adempiere.base/src/org/idempiere/fa/exceptions/AssetInvoiceWithMixedLines_LRO.java b/org.adempiere.base/src/org/idempiere/fa/exceptions/AssetInvoiceWithMixedLines_LRO.java new file mode 100644 index 0000000000..6ff23f592d --- /dev/null +++ b/org.adempiere.base/src/org/idempiere/fa/exceptions/AssetInvoiceWithMixedLines_LRO.java @@ -0,0 +1,17 @@ +/** + * + */ +package org.idempiere.fa.exceptions; + + +/** + * @author Teo Sarca, SC ARHIPAC SERVICE SRL + * + */ +public class AssetInvoiceWithMixedLines_LRO extends AssetException { + private static final long serialVersionUID = 1L; + + public AssetInvoiceWithMixedLines_LRO() { + super("No new bills that contain both fixed and normal products"); + } +} diff --git a/org.adempiere.base/src/org/idempiere/fa/exceptions/AssetNotActiveException.java b/org.adempiere.base/src/org/idempiere/fa/exceptions/AssetNotActiveException.java new file mode 100644 index 0000000000..f690ca11ba --- /dev/null +++ b/org.adempiere.base/src/org/idempiere/fa/exceptions/AssetNotActiveException.java @@ -0,0 +1,18 @@ +/** + * + */ +package org.idempiere.fa.exceptions; + +/** + * @author Teo Sarca, www.arhipac.ro + * + */ +public class AssetNotActiveException extends AssetException +{ + private static final long serialVersionUID = 1L; + + public AssetNotActiveException(int A_Asset_ID) + { + super("@AssetNotActive@ (ID="+A_Asset_ID+")"); + } +} diff --git a/org.adempiere.base/src/org/idempiere/fa/exceptions/AssetNotImplementedException.java b/org.adempiere.base/src/org/idempiere/fa/exceptions/AssetNotImplementedException.java new file mode 100644 index 0000000000..e895538d1b --- /dev/null +++ b/org.adempiere.base/src/org/idempiere/fa/exceptions/AssetNotImplementedException.java @@ -0,0 +1,20 @@ +/** + * + */ +package org.idempiere.fa.exceptions; + + +/** + * Throwed when an asset related functionality is not yet implemented + * @author Teo Sarca, SC ARHIPAC SERVICE SRL + * + */ +public class AssetNotImplementedException extends AssetException +{ + private static final long serialVersionUID = 1L; + + public AssetNotImplementedException(String additionalMessage) + { + super("@NotImplemented@ "+additionalMessage); + } +} diff --git a/org.adempiere.base/src/org/idempiere/fa/exceptions/AssetNotSupportedException.java b/org.adempiere.base/src/org/idempiere/fa/exceptions/AssetNotSupportedException.java new file mode 100644 index 0000000000..3486889b69 --- /dev/null +++ b/org.adempiere.base/src/org/idempiere/fa/exceptions/AssetNotSupportedException.java @@ -0,0 +1,18 @@ +package org.idempiere.fa.exceptions; + + +/** + * Throwed when a specific functionality is not supported. + * Please don't confunde with {@link AssetNotImplementedException}. + * @author Teo Sarca, SC ARHIPAC SERVICE SRL + * + */ +public class AssetNotSupportedException extends AssetException +{ + private static final long serialVersionUID = 1L; + + public AssetNotSupportedException (String funcName, String actualValue) + { + super("@NotSupported@ @"+funcName+"@ "+actualValue); + } +} diff --git a/org.adempiere.base/src/org/idempiere/fa/exceptions/AssetProductStockedException.java b/org.adempiere.base/src/org/idempiere/fa/exceptions/AssetProductStockedException.java new file mode 100644 index 0000000000..bf5d05f837 --- /dev/null +++ b/org.adempiere.base/src/org/idempiere/fa/exceptions/AssetProductStockedException.java @@ -0,0 +1,20 @@ +/** + * + */ +package org.idempiere.fa.exceptions; + +import org.compiere.model.MProduct; + +/** + * @author Teo Sarca, SC ARHIPAC SERVICE SRL + * + */ +public class AssetProductStockedException extends AssetException +{ + private static final long serialVersionUID = 1L; + + public AssetProductStockedException(MProduct product) + { + super("Product "+product.getName()+" is the asset type, but is stocked!"); + } +} diff --git a/org.adempiere.base/src/org/idempiere/fa/exceptions/AssetStatusChangedException.java b/org.adempiere.base/src/org/idempiere/fa/exceptions/AssetStatusChangedException.java new file mode 100644 index 0000000000..a0580ba89c --- /dev/null +++ b/org.adempiere.base/src/org/idempiere/fa/exceptions/AssetStatusChangedException.java @@ -0,0 +1,33 @@ +/** + * + */ +package org.idempiere.fa.exceptions; + +import org.compiere.util.Util; + +/** + * Threw when asset status has changed + * @author Teo Sarca, SC ARHIPAC SERVICE SRL + */ +public class AssetStatusChangedException extends AssetException +{ + private static final long serialVersionUID = 1L; + + public AssetStatusChangedException() + { + this(null); + } + + public AssetStatusChangedException(String msg) + { + super(buildMsg(msg)); + } + + private static String buildMsg(String msg) + { + StringBuffer sb = new StringBuffer("@AssetStatusChanged@"); + if (!Util.isEmpty(msg)) + sb.append(" ").append(msg); + return sb.toString(); + } +} diff --git a/org.adempiere.base/src/org/idempiere/fa/exceptions/DepreciationNoInPeriodException.java b/org.adempiere.base/src/org/idempiere/fa/exceptions/DepreciationNoInPeriodException.java new file mode 100644 index 0000000000..77a9f6b09c --- /dev/null +++ b/org.adempiere.base/src/org/idempiere/fa/exceptions/DepreciationNoInPeriodException.java @@ -0,0 +1,21 @@ +/** + * + */ +package org.idempiere.fa.exceptions; + +/** + * @author teo_sarca + * + */ +public class DepreciationNoInPeriodException extends AssetException +{ + private static final long serialVersionUID = 1L; + + public DepreciationNoInPeriodException(int A_Asset_ID, int Workfile_Period_ID, int DepExp_Period_ID) + { + super("Registration is not in balance (ID Asset="+A_Asset_ID + +", WK Period="+Workfile_Period_ID+", DepExp Period="+DepExp_Period_ID + +")"); + } + +} diff --git a/org.adempiere.base/src/org/idempiere/fa/feature/UseLife.java b/org.adempiere.base/src/org/idempiere/fa/feature/UseLife.java new file mode 100644 index 0000000000..c42d07c309 --- /dev/null +++ b/org.adempiere.base/src/org/idempiere/fa/feature/UseLife.java @@ -0,0 +1,35 @@ +/** + * + */ +package org.idempiere.fa.feature; + +import java.sql.Timestamp; +import java.util.Properties; +import org.compiere.model.SetGetModel; + + + /** Describe Use life Feature + * @author Teo Sarca, SC Arhipac SRL + * @version $Id$ + */ + public interface UseLife extends SetGetModel { + public Properties getCtx(); + + //~ public void setUseLifeMonths(int value); + //~ public int getUseLifeMonths(); + + //~ public void setUseLifeYears(int value); + //~ public int getUseLifeYears(); + + //~ public void setUseLifeMonths_F(int value); + //~ public int getUseLifeMonths_F(); + + //~ public void setUseLifeYears_F(int value); + //~ public int getUseLifeYears_F(); + + public Timestamp getAssetServiceDate(); + + /* commented out by @win + public int getA_Asset_Class_ID(); + */ + } \ No newline at end of file diff --git a/org.adempiere.base/src/org/idempiere/fa/feature/UseLifeImpl.java b/org.adempiere.base/src/org/idempiere/fa/feature/UseLifeImpl.java new file mode 100644 index 0000000000..be12b9e4ee --- /dev/null +++ b/org.adempiere.base/src/org/idempiere/fa/feature/UseLifeImpl.java @@ -0,0 +1,425 @@ +/** + * + */ +package org.idempiere.fa.feature; + +import java.sql.Timestamp; +import java.util.Properties; + +import org.compiere.model.GridField; +import org.compiere.model.GridTab; +//import org.compiere.model.MAssetClass; //commented by @win +import org.compiere.model.MAssetGroup; +import org.compiere.model.PO; +import org.compiere.model.SetGetModel; +import org.compiere.model.SetGetUtil; +import org.compiere.util.CLogMgt; +import org.compiere.util.CLogger; +import org.compiere.util.Msg; +import org.compiere.util.TimeUtil; + + + + /** + * Asset properties - classification of assets, service period, life use. + * @author Teo Sarca, SC ARHIPAC SERVICE SRL + * @version $Id$ + */ +public class UseLifeImpl + implements UseLife +{ + private final static String FIELD_UseLifeYears = "UseLifeYears"; + private final static String FIELD_UseLifeMonths = "UseLifeMonths"; + private final static String FIELD_FiscalPostfix = "_F"; + + private SetGetModel m_obj = null; + private CLogger log = CLogger.getCLogger(getClass()); + private boolean fiscal = false; + + /** + */ + public static UseLifeImpl get(SetGetModel obj) { + return new UseLifeImpl(obj, false); + } + + /** + */ + public static UseLifeImpl get(SetGetModel obj, boolean fiscal) { + return new UseLifeImpl(obj, fiscal); + } + + /** + */ + public UseLifeImpl(SetGetModel obj, boolean fiscal) { + m_obj = obj; + this.fiscal = fiscal; + } + + /** + */ + public Properties getCtx() { + return m_obj.getCtx(); + } + + public int get_Table_ID() { + return m_obj.get_Table_ID(); + } + + public String get_TableName() { + return m_obj.get_TableName(); + } + + /** + */ + private final static String getFieldName(String fieldName, boolean fiscal) { + String field = fieldName; + if (fiscal) { + field += FIELD_FiscalPostfix; + } + return field; + } + + /** + */ + public boolean isFiscal() { + return fiscal; + } + + /** + */ + public boolean set_AttrValue(String name, Object value) { + return m_obj.set_AttrValue(name, value); + } + + /** + */ + public Object get_AttrValue(String name) { + return m_obj.get_AttrValue(name); + } + + /** + */ + public boolean is_AttrValueChanged(String name) { + return m_obj.is_AttrValueChanged(name); + } + + /** + * @return transaction name for decorated object + */ + public String get_TrxName() { + return m_obj.get_TrxName(); + } + + /** Set UseLifeMonths and UseLifeYears + * @param value use life months + */ + public void setUseLifeMonths(int value) { + if(CLogMgt.isLevelFine()) log.fine("Entering: value=" + value + ", " + this); + m_obj.set_AttrValue(getFieldName(FIELD_UseLifeMonths, fiscal), Integer.valueOf(value)); + m_obj.set_AttrValue(getFieldName(FIELD_UseLifeYears, fiscal), Integer.valueOf(value/12)); + if(CLogMgt.isLevelFine()) log.fine("Leaving: value=" + value + ", " + this); + } + + /** + * @return use life months + */ + public int getUseLifeMonths() { + Object obj = m_obj.get_AttrValue(getFieldName(FIELD_UseLifeMonths, fiscal)); + if (obj != null && obj instanceof Number) { + return ((Number)obj).intValue(); + } + return 0; + } + + /** Set UseLifeYears and UseLifeMonths + * @param value use life years + */ + public void setUseLifeYears(int value) { + if(CLogMgt.isLevelFine()) log.fine("Entering: value=" + value + ", " + this); + m_obj.set_AttrValue(getFieldName(FIELD_UseLifeYears, fiscal), Integer.valueOf(value)); + m_obj.set_AttrValue(getFieldName(FIELD_UseLifeMonths, fiscal), Integer.valueOf(value*12)); + if(CLogMgt.isLevelFine()) log.fine("Leaving: value=" + value + ", " + this); + } + + /** + * @return use life years + */ + public int getUseLifeYears() { + Object obj = m_obj.get_AttrValue(getFieldName(FIELD_UseLifeYears, fiscal)); + if (obj != null && obj instanceof Number) { + return ((Number)obj).intValue(); + } + return 0; + } + + /** + * Adjust use life years + * @param deltaUseLifeYears + * @param reset + */ + public void adjustUseLifeYears(int deltaUseLifeYears, boolean reset) + { + int uselife = (reset ? 0 : getUseLifeYears()); + int new_uselife = uselife + deltaUseLifeYears; + setUseLifeYears(new_uselife); + if(CLogMgt.isLevelFine()) + log.fine("UseLifeYears=" + uselife + ", delta=" + deltaUseLifeYears + " => new UseLifeYears=" + new_uselife + " (isFiscal=" + isFiscal() + ")"); + } + + /** + * @return Asset Service Date (PIF) + */ + public Timestamp getAssetServiceDate() { + if (m_obj instanceof UseLife) { + return ((UseLife)m_obj).getAssetServiceDate(); + } else { + Object obj = m_obj.get_AttrValue("AssetServiceDate"); + if (obj != null && obj instanceof Timestamp) { + return (Timestamp)obj; + } + } + return null; + } + + /** + * @return asset class ID + */ + /* commented out by @win + public int getA_Asset_Class_ID() + { + if (m_obj instanceof UseLife) + { + return ((UseLife)m_obj).getA_Asset_Class_ID(); + } + else + { + Object obj = m_obj.get_AttrValue("A_Asset_Class_ID"); + if (obj != null && obj instanceof Number) + { + return ((Number)obj).intValue(); + } + } + return 0; + } + */ // end comment by @win + + /** + * Copy UseLifeMonths, UseLifeMonths_F, UseLifeYears, UseLifeYears_F fields from "from" to "to" + * @param to destination model + * @param from source model + */ + public static void copyValues(PO to, PO from) { + SetGetUtil.copyValues(to, from, new String[]{"UseLifeMonths", "UseLifeYears", "UseLifeMonths_F", "UseLifeYears_F"}, null); + } + + /** Validates and corrects errors in model */ + public boolean validate() { + return validate(true); + } + + /** Validates and corrects errors in model */ + public boolean validate(boolean saveError) { + if(CLogMgt.isLevelFine()) log.fine("Entering: " + this); + + int useLifeYears = 0; + int useLifeMonths = 0; + useLifeYears = getUseLifeYears(); + useLifeMonths = getUseLifeMonths(); + + if (useLifeMonths == 0) { + useLifeMonths = useLifeYears * 12; + } + if (useLifeMonths % 12 != 0) { + if(saveError) log.saveError("Error", "@Invalid@ @UseLifeMonths@=" + useLifeMonths + "(@Diff@=" + (useLifeMonths % 12) + ")" ); + return false; + } + if (useLifeYears == 0) { + useLifeYears = (int)(useLifeMonths / 12); + } + /* commented out by @win + int A_Asset_Class_ID = getA_Asset_Class_ID(); + if (A_Asset_Class_ID > 0 && (useLifeMonths == 0 || useLifeYears == 0)) { + if(saveError) log.saveError("Error", "@Invalid@ @UseLifeMonths@=" + useLifeMonths + ", @UseLifeYears@=" + useLifeYears); + return false; + } + */ //commented out by @win + + setUseLifeMonths(useLifeMonths); + setUseLifeYears(useLifeYears); + + /* commented by @win + MAssetClass assetClass = MAssetClass.get(getCtx(), A_Asset_Class_ID); + if (assetClass != null && !assetClass.validate(this)) { + log.fine("Leaving [RETURN FALSE]"); + return false; + } + */ //end comment by @win + + log.fine("Leaving [RETURN TRUE]"); + return true; + } + + /** String representation (intern) + */ + public String toString() + { + return + "UseLifeImpl[UseLife=" + getUseLifeYears() + "|" + getUseLifeMonths() + + ", isFiscal=" + isFiscal() + + ", AssetServiceDate=" + getAssetServiceDate() + //+ ", A_Asset_Class=" + getA_Asset_Class_ID() //commented by @win + + ", m_obj=" + m_obj + + "]" + ; + } + + /** Calculate date accounting for = assetServiceDate + A_Current_Period + * @param assetServiceDate data PIF + * @param A_Current_Period (displacement) + * @return assetServiceDate + A_Current_Period + */ + public static Timestamp getDateAcct(Timestamp assetServiceDate, int A_Current_Period) { + if (assetServiceDate == null) + return null; + return TimeUtil.addMonths(assetServiceDate, A_Current_Period); + } + + + + /** + * Callout Class + */ + public static class Callout extends org.compiere.model.CalloutEngine { + /** */ + private String validate(Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value, Object oldValue) { + /* commented out by @win + Integer A_Asset_Class_ID = (Integer)mTab.getValue("A_Asset_Class_ID"); + if (A_Asset_Class_ID == null || A_Asset_Class_ID == 0) { + return NO_ERROR; + } + */ //end commented by @win + Timestamp AssetServiceDate = (Timestamp)mTab.getValue("AssetServiceDate"); + if (AssetServiceDate == null) { + return NO_ERROR; + } + /* commented out by @win + MAssetClass assetClass = MAssetClass.get(ctx, A_Asset_Class_ID); + if (assetClass == null) { + return NO_ERROR; + } + */ // end comment by @win + + Integer UseLifeMonths = (Integer)mTab.getValue("UseLifeMonths"); + if (UseLifeMonths == null) { + UseLifeMonths = 0; + } + /* commented out by @win + String errmsg = assetClass.validate(false, UseLifeMonths, AssetServiceDate); + if(CLogMgt.isLevelFine()) log.fine("assetClass=" + assetClass + ", UseLifeMonths=" + UseLifeMonths + ", AssetServiceDate=" + AssetServiceDate + ", errmsg=" + errmsg); + return errmsg; + */ // end comment by @win + return NO_ERROR; //added by @win + } + + /** */ + public String assetServiceDate(Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value, Object oldValue) { + if (isCalloutActive() || value == null) { + return NO_ERROR; + } + return validate(ctx, WindowNo, mTab, mField, value, oldValue); + } + + /** */ + public String useLife(Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value, Object oldValue) { + if (isCalloutActive()) { + return NO_ERROR; + } + + String sufix = ""; + int ivalue = 0; + int UseLifeYears = 0; + int UseLifeMonths = 0; + String errmsg = ""; + if (value != null) { + ivalue = ((Integer)value).intValue(); + } + + String columnName = mField.getColumnName().toUpperCase(); + if (columnName.endsWith(FIELD_FiscalPostfix)) { + sufix = FIELD_FiscalPostfix; + columnName = columnName.substring(0, columnName.length() - FIELD_FiscalPostfix.length()); + } + + if (columnName.equalsIgnoreCase("UseLifeMonths")) { + //~ UseLifeMonths = ivalue; + if (ivalue % 12 != 0) { + errmsg = "@Invalid@ @UseLifeMonths " + sufix + "@=" + ivalue; + } else { + UseLifeYears = (int)(ivalue / 12); + mTab.setValue("UseLifeYears" + sufix, Integer.valueOf(UseLifeYears)); + } + } + else if (columnName.equalsIgnoreCase("UseLifeYears")) { + UseLifeMonths = ivalue * 12; + //~ UseLifeYears = ivalue; + mTab.setValue("UseLifeMonths" + sufix, Integer.valueOf(UseLifeMonths)); + } + + if (errmsg.length() > 0) { + errmsg = Msg.parseTranslation(ctx, errmsg); + } + return errmsg; + } + + /** + */ + public String assetGroup(Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value, Object oldValue) { + if (isCalloutActive()) { + return NO_ERROR; + } + + int A_Asset_Group_ID = -1; + if (value != null && value instanceof Number) { + A_Asset_Group_ID = ((Number)value).intValue(); + } + MAssetGroup.updateAsset(SetGetUtil.wrap(mTab), A_Asset_Group_ID); + return NO_ERROR; + } + + /** */ + /* commented by @win + public String assetClass(Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value, Object oldValue) { + if (isCalloutActive()) { + return NO_ERROR; + } + + String errmsg = NO_ERROR; + int A_Asset_Class_ID = -1; + String columnName = mField.getColumnName(); + if(CLogMgt.isLevelFine()) log.fine("Entering: columnName: " + columnName + ", value=" + value); + + if (value != null && value instanceof Number) { + A_Asset_Class_ID = ((Number)value).intValue(); + } + if(CLogMgt.isLevelFine()) log.fine("A_Asset_Class_ID=" + A_Asset_Class_ID); + + if (A_Asset_Class_ID > 0) { + MAssetClass assetClass = MAssetClass.get(ctx, A_Asset_Class_ID); + Integer UseLifeMonths = (Integer)mTab.getValue("UseLifeMonths_F"); + Timestamp AssetServiceDate = (Timestamp)mTab.getValue("AssetServiceDate"); + if (UseLifeMonths == null || UseLifeMonths == 0) { + UseLifeMonths = assetClass.getA_Life_Period_Min(AssetServiceDate); + mTab.setValue("UseLifeMonths", UseLifeMonths); + } + else { + errmsg = assetClass.validate(false, UseLifeMonths, AssetServiceDate); + } + if(CLogMgt.isLevelFine()) log.fine("assetClass=" + assetClass + ", UseLifeMonths=" + UseLifeMonths + ", AssetServiceDate=" + AssetServiceDate + ", errmsg=" + errmsg); + } + + if(CLogMgt.isLevelFine()) log.fine("Leaving: errmsg=" + errmsg); + return errmsg; + } + */ // end commented by @win + } // class Callout + } \ No newline at end of file diff --git a/org.adempiere.base/src/org/idempiere/fa/model/CalloutA_Asset_Addition.java b/org.adempiere.base/src/org/idempiere/fa/model/CalloutA_Asset_Addition.java new file mode 100644 index 0000000000..54a5461d08 --- /dev/null +++ b/org.adempiere.base/src/org/idempiere/fa/model/CalloutA_Asset_Addition.java @@ -0,0 +1,131 @@ +package org.idempiere.fa.model; + +import java.math.BigDecimal; +import java.util.Properties; + +import org.adempiere.model.GridTabWrapper; +import org.compiere.model.CalloutEngine; +import org.compiere.model.GridField; +import org.compiere.model.GridTab; +import org.compiere.model.I_A_Asset_Addition; +import org.compiere.model.MAsset; +import org.compiere.model.MAssetAddition; +import org.compiere.model.MConversionRateUtil; +import org.compiere.model.MProject; +import org.compiere.model.SetGetUtil; +import org.compiere.util.Env; +import org.compiere.util.TimeUtil; + + +/** + * @author Teo Sarca, http://www.arhipac.ro + */ +public class CalloutA_Asset_Addition extends CalloutEngine +{ + public String matchInv(Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value) + { + if (isCalloutActive() || value == null) + return ""; + + int M_MatchInv_ID = ((Number)value).intValue(); + if (M_MatchInv_ID > 0) + { + MAssetAddition.setM_MatchInv(SetGetUtil.wrap(mTab), M_MatchInv_ID); + } + // + return amt(ctx, WindowNo, mTab, mField, value); + } + + public String project(Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value) + { + if (isCalloutActive()) + return ""; + // + int project_id = 0; + if (value != null && value instanceof Number) + project_id = ((Number)value).intValue(); + else + return ""; + // + BigDecimal amt = Env.ZERO; + if (project_id > 0) { + MProject prj = new MProject(ctx, project_id, null); + amt = prj.getProjectBalanceAmt(); + mTab.setValue(MAssetAddition.COLUMNNAME_C_Currency_ID, prj.getC_Currency_ID()); + } + mTab.setValue(MAssetAddition.COLUMNNAME_AssetSourceAmt, amt); + return amt(ctx, WindowNo, mTab, mField, value); + } + + public String amt(Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value) + { + if (isCalloutActive()) + return ""; + // + String columnName = mField.getColumnName(); + if (MAssetAddition.COLUMNNAME_A_Accumulated_Depr.equals(columnName)) + { + mTab.setValue(MAssetAddition.COLUMNNAME_A_Accumulated_Depr_F, value); + } + else + { + BigDecimal amtEntered = (BigDecimal) mTab.getValue(MAssetAddition.COLUMNNAME_AssetAmtEntered); + mTab.setValue(MAssetAddition.COLUMNNAME_AssetSourceAmt, amtEntered); + MConversionRateUtil.convertBase(SetGetUtil.wrap(mTab), + MAssetAddition.COLUMNNAME_DateAcct, + MAssetAddition.COLUMNNAME_AssetSourceAmt, + MAssetAddition.COLUMNNAME_AssetValueAmt, + mField.getColumnName()); + } + // + return ""; + } + + public String dateDoc(Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value) + { + if (isCalloutActive() || value == null) + return ""; + + mTab.setValue(MAssetAddition.COLUMNNAME_DateAcct, value); + return ""; + } + + public String uselife(Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value) + { + if (MAssetAddition.COLUMNNAME_DeltaUseLifeYears.equals(mField.getColumnName())) + { + mTab.setValue(MAssetAddition.COLUMNNAME_DeltaUseLifeYears_F, value); + } + return ""; + } + + + public String periodOffset(Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value) + { + I_A_Asset_Addition aa = GridTabWrapper.create(mTab, I_A_Asset_Addition.class); + if (!aa.isA_Accumulated_Depr_Adjust()) + { + return ""; + } + + int periods = TimeUtil.getMonthsBetween(aa.getDateDoc(), aa.getDateAcct()); + if (periods <= 0) + { + return ""; + } + + int uselifeMonths = aa.getDeltaUseLifeYears() * 12; + if (uselifeMonths == 0) + { + return ""; + } + double monthlyExpenseSL = aa.getAssetValueAmt().doubleValue() / uselifeMonths * periods; + + aa.setA_Period_Start(periods + 1); + aa.setA_Accumulated_Depr(BigDecimal.valueOf(monthlyExpenseSL)); + aa.setA_Accumulated_Depr_F(BigDecimal.valueOf(monthlyExpenseSL)); + + return ""; + } + +} diff --git a/org.adempiere.base/src/org/idempiere/fa/model/CalloutA_Asset_Disposed.java b/org.adempiere.base/src/org/idempiere/fa/model/CalloutA_Asset_Disposed.java new file mode 100644 index 0000000000..53ff8a47bd --- /dev/null +++ b/org.adempiere.base/src/org/idempiere/fa/model/CalloutA_Asset_Disposed.java @@ -0,0 +1,86 @@ +/** + * + */ +package org.idempiere.fa.model; + +import java.math.BigDecimal; +import java.sql.Timestamp; +import java.util.Properties; + +import org.adempiere.model.GridTabWrapper; +import org.compiere.model.CalloutEngine; +import org.compiere.model.GridField; +import org.compiere.model.GridTab; +import org.compiere.model.I_A_Asset_Disposed; +import org.compiere.model.MAssetDisposed; +import org.compiere.util.Env; + + + +/** + * + * @author Teo Sarca, SC ARHIPAC SERVICE SRL + */ +public class CalloutA_Asset_Disposed extends CalloutEngine +{ + public String asset(Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value) + { + I_A_Asset_Disposed bean = GridTabWrapper.create(mTab, I_A_Asset_Disposed.class); + MAssetDisposed.updateFromAsset(bean); + bean.setA_Disposal_Amt(bean.getA_Asset_Cost().subtract(bean.getA_Accumulated_Depr())); + // + return ""; + } + + public String date(Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value) + { + if (isCalloutActive()) + { + return ""; + } + String columnName = mField.getColumnName(); + // + if (MAssetDisposed.COLUMNNAME_DateDoc.equals(columnName)) + { + I_A_Asset_Disposed bean = GridTabWrapper.create(mTab, I_A_Asset_Disposed.class); + Timestamp dateDoc = (Timestamp)value; + bean.setDateAcct(dateDoc); + bean.setA_Disposed_Date(dateDoc); + } + // + return ""; + } + + public String amt(Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value) + { + String columnName = mField.getColumnName(); + + I_A_Asset_Disposed bean = GridTabWrapper.create(mTab, I_A_Asset_Disposed.class); + // + int asset_id = bean.getA_Asset_ID(); + if (asset_id <= 0) + { + bean.setA_Disposal_Amt(Env.ZERO); + bean.setA_Accumulated_Depr_Delta(Env.ZERO); + bean.setExpense(Env.ZERO); + } + else if (MAssetDisposed.COLUMNNAME_A_Disposal_Amt.equals(columnName)) + { + MAssetDisposed.setA_Disposal_Amt(bean); + } + else if (MAssetDisposed.COLUMNNAME_Expense.equals(columnName)) + { + BigDecimal disposalAmt = bean.getA_Disposal_Amt(); + BigDecimal expenseAmt = bean.getExpense(); + bean.setA_Accumulated_Depr_Delta(disposalAmt.subtract(expenseAmt)); + } + else if (MAssetDisposed.COLUMNNAME_A_Accumulated_Depr.equals(columnName)) + { + BigDecimal disposalAmt = bean.getA_Disposal_Amt(); + BigDecimal accumDepr = bean.getA_Accumulated_Depr_Delta(); + bean.setExpense(disposalAmt.subtract(accumDepr)); + } + return ""; + } + +} diff --git a/org.adempiere.base/src/org/idempiere/fa/model/CalloutA_Asset_Reval.java b/org.adempiere.base/src/org/idempiere/fa/model/CalloutA_Asset_Reval.java new file mode 100644 index 0000000000..5e9b388172 --- /dev/null +++ b/org.adempiere.base/src/org/idempiere/fa/model/CalloutA_Asset_Reval.java @@ -0,0 +1,56 @@ +/** + * + */ +package org.idempiere.fa.model; + +import java.util.Properties; + +import org.adempiere.model.GridTabWrapper; +import org.compiere.model.CalloutEngine; +import org.compiere.model.GridField; +import org.compiere.model.GridTab; +import org.compiere.model.I_A_Asset_Reval; +import org.compiere.model.MAssetReval; +import org.compiere.model.MDepreciationWorkfile; + + +/** + * @author Anca Bradau www.arhipac.ro + * + */ +public class CalloutA_Asset_Reval extends CalloutEngine +{ + public String asset(Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value) + { + if (isCalloutActive()) + return ""; + // + I_A_Asset_Reval model = GridTabWrapper.create(mTab, I_A_Asset_Reval.class); + if (model.getA_Asset_ID() <= 0) + { + return ""; + } + MDepreciationWorkfile amount = MDepreciationWorkfile.get(ctx, model.getA_Asset_ID(), model.getPostingType(), null); + if (amount == null) + { + return "@NotFound@ @A_Asset_ID@"; + } + // + model.setA_Asset_Cost(amount.getA_Asset_Cost()); + model.setA_Asset_Cost_Change(amount.getA_Asset_Cost()); + + model.setA_Accumulated_Depr(amount.getA_Accumulated_Depr()); + model.setA_Change_Acumulated_Depr(amount.getA_Accumulated_Depr()); + + return ""; + } + public String dateDoc(Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value) + { + if (isCalloutActive() || value == null) + return ""; + + mTab.setValue(MAssetReval.COLUMNNAME_DateAcct, value); + return ""; + } +} + diff --git a/org.adempiere.base/src/org/idempiere/fa/model/CalloutA_Asset_Transfer.java b/org.adempiere.base/src/org/idempiere/fa/model/CalloutA_Asset_Transfer.java new file mode 100644 index 0000000000..01bcade2ab --- /dev/null +++ b/org.adempiere.base/src/org/idempiere/fa/model/CalloutA_Asset_Transfer.java @@ -0,0 +1,72 @@ +/** + * + */ +package org.idempiere.fa.model; + +import java.util.Properties; + +import org.adempiere.model.GridTabWrapper; +import org.compiere.model.CalloutEngine; +import org.compiere.model.GridField; +import org.compiere.model.GridTab; +import org.compiere.model.I_A_Asset_Transfer; +import org.compiere.model.MAssetAcct; +import org.compiere.model.MAssetTransfer; + + + +/** + * @author Anca Bradau, www.arhipac.ro + * + */ +public class CalloutA_Asset_Transfer extends CalloutEngine +{ + + public String asset(Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value) + { + if (isCalloutActive()) + return ""; + // + I_A_Asset_Transfer model = GridTabWrapper.create(mTab, I_A_Asset_Transfer.class); + if (model.getA_Asset_ID() <= 0) + { + return ""; + } + MAssetAcct acct = MAssetAcct.forA_Asset_ID(ctx, model.getA_Asset_ID(), model.getPostingType(), model.getDateAcct(), null); + if (acct == null) + { + return "@NotFound@ @A_Asset_Acct_ID@"; + } + // Asset Acct + model.setA_Asset_Acct(acct.getA_Asset_Acct()); + model.setA_Asset_New_Acct(acct.getA_Asset_Acct()); + + //Accumulated Depreciation Account + model.setA_Accumdepreciation_Acct(acct.getA_Accumdepreciation_Acct()); + model.setA_Accumdepreciation_New_Acct(acct.getA_Accumdepreciation_Acct()); + + //Depreciation Account + model.setA_Depreciation_Acct(acct.getA_Depreciation_Acct()); + model.setA_Depreciation_New_Acct(acct.getA_Depreciation_Acct()); + + //Disposal revenue + model.setA_Disposal_Revenue_Acct(acct.getA_Disposal_Revenue_Acct()); + model.setA_Disposal_Revenue_New_Acct(acct.getA_Disposal_Revenue_Acct()); + + //Disposal Loss Account + model.setA_Disposal_Loss_Acct(acct.getA_Disposal_Loss_Acct()); + model.setA_Disposal_Loss_New_Acct(acct.getA_Disposal_Loss_Acct()); + + + return ""; + } + public String dateDoc(Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value) + { + if (isCalloutActive() || value == null) + return ""; + + mTab.setValue(MAssetTransfer.COLUMNNAME_DateAcct, value); + return ""; + } +} + diff --git a/org.adempiere.base/src/org/idempiere/fa/model/CalloutA_Depreciation_Workfile.java b/org.adempiere.base/src/org/idempiere/fa/model/CalloutA_Depreciation_Workfile.java new file mode 100644 index 0000000000..2bf64a0c04 --- /dev/null +++ b/org.adempiere.base/src/org/idempiere/fa/model/CalloutA_Depreciation_Workfile.java @@ -0,0 +1,63 @@ +package org.idempiere.fa.model; + +import java.math.BigDecimal; +import java.util.Properties; + +import org.compiere.model.CalloutEngine; +import org.compiere.model.GridField; +import org.compiere.model.GridTab; +import org.compiere.model.MAsset; +import org.compiere.model.MAssetAddition; +import org.compiere.model.MDepreciationWorkfile; +import org.compiere.model.SetGetUtil; +import org.compiere.util.Env; + +import com.sun.corba.ee.spi.servicecontext.ServiceContextsCache.CASE; + + +/** + * @author Teo Sarca, http://www.arhipac.ro + */ +public class CalloutA_Depreciation_Workfile extends CalloutEngine +{ + public String A_Valoare_Cofinantare (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value) + { + if (isCalloutActive()) + return ""; + MDepreciationWorkfile.updateFinantare(SetGetUtil.wrap(mTab), mField.getColumnName()); + return ""; + } + + public String uselifeyear(Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value) + { + BigDecimal uselife = null; + if (MDepreciationWorkfile.COLUMNNAME_UseLifeYears.equals(mField.getColumnName())) + { + uselife = new BigDecimal(value.toString()).multiply(new BigDecimal(12.0)); + mTab.setValue(MDepreciationWorkfile.COLUMNNAME_UseLifeYears_F, value); + mTab.setValue(MDepreciationWorkfile.COLUMNNAME_UseLifeMonths, uselife); + mTab.setValue(MDepreciationWorkfile.COLUMNNAME_UseLifeMonths_F, uselife); + + } else if (MDepreciationWorkfile.COLUMNNAME_UseLifeMonths.equals(mField.getColumnName())) + { + uselife = new BigDecimal(value.toString()).divide(new BigDecimal(12.0)); + mTab.setValue(MDepreciationWorkfile.COLUMNNAME_UseLifeYears, uselife); + mTab.setValue(MDepreciationWorkfile.COLUMNNAME_UseLifeYears_F, uselife); + mTab.setValue(MDepreciationWorkfile.COLUMNNAME_UseLifeMonths_F, value); + + } else if (MDepreciationWorkfile.COLUMNNAME_UseLifeYears_F.equals(mField.getColumnName())) + { + uselife = new BigDecimal(value.toString()).multiply(new BigDecimal(12.0)); + mTab.setValue(MDepreciationWorkfile.COLUMNNAME_UseLifeMonths_F, uselife); + + } else if (MDepreciationWorkfile.COLUMNNAME_UseLifeMonths_F.equals(mField.getColumnName())) + { + uselife = new BigDecimal(value.toString()).divide(new BigDecimal(12.0)); + mTab.setValue(MDepreciationWorkfile.COLUMNNAME_UseLifeYears_F, uselife); + + } + return ""; + + } + +} \ No newline at end of file diff --git a/org.adempiere.base/src/org/idempiere/fa/model/CalloutAsset.java b/org.adempiere.base/src/org/idempiere/fa/model/CalloutAsset.java new file mode 100644 index 0000000000..4632f2eb72 --- /dev/null +++ b/org.adempiere.base/src/org/idempiere/fa/model/CalloutAsset.java @@ -0,0 +1,196 @@ +/** + * + */ +package org.idempiere.fa.model; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Properties; + +import org.compiere.model.CalloutEngine; +import org.compiere.model.GridField; +import org.compiere.model.GridTab; +import org.compiere.model.MAsset; +import org.compiere.util.DB; +import org.compiere.util.Env; + +/** + * @category STUB for upgrading to 361 + * + */ +public class CalloutAsset extends CalloutEngine { + + public String location (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value, Object oldValue) + { + Integer locator = (Integer)value; + if (locator == null || locator <= 0) + return ""; + if (isCalloutActive()) + return ""; + // + //TODO - found missing but MAsset table is asking for this in 3 location fields. + // + return ""; + } + public String locator (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value, Object oldValue) + + { + Integer locator = (Integer)value; + if (locator == null || locator <= 0) + return ""; + if (isCalloutActive()) + return ""; + // + //TODO - found missing but MAsset table is asking for this in 3 location fields. + // + return ""; + } + + + public String asset(Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value) + { + if (MAsset.COLUMNNAME_A_Asset_ID.equals(mField.getColumnName())) + { + MAsset asset = new MAsset(ctx, (Integer) value, null); + mTab.setValue(MAsset.COLUMNNAME_M_Product_ID, asset.getM_Product_ID()); + } + + return ""; + + } + + + /** + * Table_Period. Used to set the Manual Period Field. This allows + * the Spread Field to be displayed when there is a code that + * has been setup as Yearly. + * The string in the Callout field is: + * com.compiere.custom.CalloutEngine.Table_Period + * + * @param ctx Context + * @param WindowNo current Window No + * @param mTab Model Tab + * @param mField Model Field + * @param value The new value + * @param oldValue The old value + * @return error message or "" if OK + */ + public String Table_Period (Properties ctx, int WindowNo, + GridTab mTab, GridField mField, Object value, Object oldValue) + { + Integer A_Depreciation_Table_Header_ID = (Integer)value; + + try + { + if (A_Depreciation_Table_Header_ID != null){ + String SQL = "SELECT A_Term " + + "FROM A_Depreciation_Table_Header " + + "WHERE A_Depreciation_Table_Header_ID='" + +A_Depreciation_Table_Header_ID + +"'"; + + PreparedStatement pstmt = DB.prepareStatement(SQL, null); // arhipac: compatibility + ResultSet rs = pstmt.executeQuery(); + if (rs.next()) + { +// Charges - Set Context + Env.setContext(ctx, WindowNo, "A_DEPRECIATION_MANUAL_PERIOD", rs.getString("A_Term")); + mTab.setValue ("A_DEPRECIATION_MANUAL_PERIOD", rs.getString("A_Term")); + + } + rs.close(); + pstmt.close(); + } + } + catch (SQLException e) + { + log.info("PeriodType "+ e); + return e.getLocalizedMessage(); + } + return ""; + } // Period Type + + /** + * Field_Clear. Used to set the Manual Period Field. This allows + * the Spread Field to be displayed when there is a code that + * has been setup as Yearly. + * The string in the Callout field is: + * com.compiere.custom.CalloutEngine.Table_Period + * + * @param ctx Context + * @param WindowNo current Window No + * @param mTab Model Tab + * @param mField Model Field + * @param value The new value + * @param oldValue The old value + * @return error message or "" if OK + */ + public String Field_Clear (Properties ctx, int WindowNo, + GridTab mTab, GridField mField, Object value, Object oldValue) + { + Object A_Depreciation_ID = value; + + try + { + String SQL = "SELECT DepreciationType " + + "FROM A_Depreciation " + + "WHERE A_Depreciation_ID=" + + A_Depreciation_ID; + + PreparedStatement pstmt = DB.prepareStatement(SQL, null); // arhipac: compatibility + ResultSet rs = pstmt.executeQuery(); + if (rs.next()) + { +// Charges - Set Context + String depType = rs.getString("DepreciationType"); + if ("TAB".equals(depType) || "MAN".equals(depType)) + { + Env.setContext(ctx, WindowNo, "A_DEPRECIATION_MANUAL_PERIOD", ""); + mTab.setValue ("A_Depreciation_Manual_Period", null); + mTab.setValue ("A_Depreciation_Manual_Amount", null); + mTab.setValue ("A_Depreciation_Table_Header_ID", null); + } + if (rs.getString("DepreciationType")== "TAB") + { + mTab.setValue ("A_Depreciation_Manual_Amount", null); + } + if (rs.getString("DepreciationType")== "MAN") + { + mTab.setValue ("A_Depreciation_Table_Header_ID", null); + } + } + rs.close(); + pstmt.close(); + } + catch (SQLException e) + { + log.info("PeriodType "+ e); + return e.getLocalizedMessage(); + } + return ""; + } // Period Type + + /** ARHIPAC: TEO: BEGIN ------------------------------------------------------------------------------------------------------------------------------ */ + /* commented by @win - no necessary code + public String invoiceLineProduct(Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value, Object oldValue) { + if (isCalloutActive()) { + return ""; + } + ro.arhipac.adempiere.fa.ModelValidator.modelChange_InvoiceLine( + SetGetUtil.wrap(mTab), + -1); + return ""; + } + + public String inventoryLineProduct(Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value, Object oldValue) { + if (isCalloutActive()) { + return ""; + } + ro.arhipac.adempiere.fa.ModelValidator.modelChange_InventoryLine( + SetGetUtil.wrap(mTab), + -1); + return ""; + } + */ +} diff --git a/org.adempiere.base/src/org/idempiere/fa/model/ModelValidator.java b/org.adempiere.base/src/org/idempiere/fa/model/ModelValidator.java new file mode 100644 index 0000000000..dac94b09c8 --- /dev/null +++ b/org.adempiere.base/src/org/idempiere/fa/model/ModelValidator.java @@ -0,0 +1,284 @@ +/** + * + */ +package org.idempiere.fa.model; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.List; + +import org.adempiere.exceptions.AdempiereException; +import org.adempiere.exceptions.FillMandatoryException; +import org.compiere.acct.Fact; +import org.compiere.model.MAcctSchema; +import org.compiere.model.MAsset; +import org.compiere.model.MAssetAddition; +//import org.compiere.model.MAssetType; //commented by @win +import org.compiere.model.MAssetDisposed; +import org.compiere.model.MAttributeSetInstance; +import org.compiere.model.MClient; +import org.compiere.model.MCostDetail; +import org.compiere.model.MDocType; +import org.compiere.model.MInventory; +import org.compiere.model.MInventoryLine; +import org.compiere.model.MInvoice; +import org.compiere.model.MInvoiceLine; +import org.compiere.model.MMatchInv; +import org.compiere.model.MPayment; +import org.compiere.model.MPaymentAllocate; +import org.compiere.model.MProduct; +import org.compiere.model.MProject; +import org.compiere.model.ModelValidationEngine; +import org.compiere.model.PO; +import org.compiere.model.SetGetModel; +import org.compiere.model.SetGetUtil; +import org.compiere.util.ArhRuntimeException; +import org.compiere.util.CLogMgt; +import org.compiere.util.CLogger; +import org.compiere.util.DB; +import org.compiere.util.Env; +import org.idempiere.fa.exceptions.AssetInvoiceWithMixedLines_LRO; +import org.idempiere.fa.exceptions.AssetNotImplementedException; +import org.idempiere.fa.exceptions.AssetProductStockedException; + + + +/** + * Fixed Assets Model Validator + * @author Teo_Sarca, SC ARHIPAC SERVICE SRL + * + */ +public class ModelValidator +implements org.compiere.model.ModelValidator, org.compiere.model.FactsValidator +{ + /** Logger */ + private static CLogger log = CLogger.getCLogger(ModelValidator.class); + /** Client */ + private int m_AD_Client_ID = -1; + + + public int getAD_Client_ID() { + return m_AD_Client_ID; + } + + + public void initialize(ModelValidationEngine engine, MClient client) + { + if (client != null) + { + m_AD_Client_ID = client.getAD_Client_ID(); + } + + engine.addModelChange(MInvoiceLine.Table_Name, this); + engine.addDocValidate(MInvoice.Table_Name, this); + engine.addModelChange(MMatchInv.Table_Name, this); + // +// engine.addFactsValidate(MDepreciationEntry.Table_Name, this); + } + + public String login(int AD_Org_ID, int AD_Role_ID, int AD_User_ID) + { + return null; + } + + public String modelChange(PO po, int type) throws Exception + { + if (po instanceof MMatchInv + && (TYPE_AFTER_NEW == type + || (TYPE_AFTER_CHANGE == type && po.is_ValueChanged(MMatchInv.COLUMNNAME_Processed)))) + { + MMatchInv mi = (MMatchInv)po; + if (mi.isProcessed()) + { + MInvoiceLine invoiceLine = new MInvoiceLine(mi.getCtx(), mi.getC_InvoiceLine_ID(), mi.get_TrxName()); + if (invoiceLine.isA_CreateAsset() + && !invoiceLine.isA_Processed() + /* commented by @win + && MAssetType.isFixedAssetGroup(mi.getCtx(), invoiceLine.getA_Asset_Group_ID()) + */ + ) + { + MAssetAddition.createAsset(mi); + } + } + } + // + // Invoice Line + else if (po instanceof MInvoiceLine) + { + modelChange_InvoiceLine(SetGetUtil.wrap(po), type); + } + return null; + + } + + public String docValidate(PO po, int timing) + { + + log.info(po.get_TableName() + " Timing: " + timing); + String result = null; + + // TABLE C_Invoice + String tableName = po.get_TableName(); + if(tableName.equals(MInvoice.Table_Name)){ + // Invoice - Validate Fixed Assets Invoice (LRO) + if (timing==TIMING_AFTER_PREPARE) + { + MInvoice invoice = (MInvoice)po; + validateFixedAssetsInvoice_LRO(invoice); + } + + if(timing==TIMING_AFTER_COMPLETE){ + MInvoice mi = (MInvoice)po; + if (mi.isSOTrx()) { + MInvoiceLine[] mils = mi.getLines(); + for (MInvoiceLine mil: mils) { + if (mil.isA_CreateAsset() && !mil.isA_Processed()) { + MAssetDisposed.createAssetDisposed(mil); + } + } + } + } //end MInvoice TIMING_AFTER_COMPLETE + } + + return result; + } // docValidate + + /** + * Model Change Invoice Line + * @param ctx + * @param m model + * @param changeType set when called from model validator (See TYPE_*); else -1, when called from callout + */ + public static void modelChange_InvoiceLine(SetGetModel m, int changeType) { + // + // Set Asset Related Fields: + if (-1 == changeType || TYPE_BEFORE_NEW == changeType || TYPE_BEFORE_CHANGE == changeType) { + int invoice_id = SetGetUtil.get_AttrValueAsInt(m, MInvoiceLine.COLUMNNAME_C_Invoice_ID); + boolean isSOTrx = DB.isSOTrx(MInvoice.Table_Name, MInvoice.COLUMNNAME_C_Invoice_ID+"="+invoice_id); + boolean isAsset = false; + /* comment by @win + boolean isFixedAsset = false; + */ + int assetGroup_ID = 0; + //@win commenting this out to enable relating AR Invoice to Asset Disposal + /* + if (!isSOTrx) { + int product_id = SetGetUtil.get_AttrValueAsInt(m, MInvoiceLine.COLUMNNAME_M_Product_ID); + if (product_id > 0) { + MProduct prod = MProduct.get(m.getCtx(), product_id); + isAsset = (prod != null && prod.get_ID() > 0 && prod.isCreateAsset()); + assetGroup_ID = prod.getA_Asset_Group_ID(); + + //isFixedAsset = MAssetType.isFixedAssetGroup(m.getCtx(), assetGroup_ID); //commented by @win - remove asset type + + } + } + */ + int product_id = SetGetUtil.get_AttrValueAsInt(m, MInvoiceLine.COLUMNNAME_M_Product_ID); + if (product_id > 0) { + MProduct prod = MProduct.get(m.getCtx(), product_id); + isAsset = (prod != null && prod.get_ID() > 0 && prod.isCreateAsset()); + assetGroup_ID = prod.getA_Asset_Group_ID(); + } + + // end modification by @win + + m.set_AttrValue(MInvoiceLine.COLUMNNAME_A_CreateAsset, isAsset); + if (isAsset) { + m.set_AttrValue(MInvoiceLine.COLUMNNAME_A_Asset_Group_ID, assetGroup_ID); + /* comment by @win + m.set_AttrValue(MInvoiceLine.COLUMNNAME_IsFixedAssetInvoice, isFixedAsset); + */ + m.set_AttrValue("IsFixedAssetInvoice", isAsset); + m.set_AttrValue(MInvoiceLine.COLUMNNAME_A_CreateAsset, "Y"); + + } + else { + m.set_AttrValue(MInvoiceLine.COLUMNNAME_A_Asset_Group_ID, null); + m.set_AttrValue(MInvoiceLine.COLUMNNAME_A_Asset_ID, null); + m.set_AttrValue("IsFixedAssetInvoice", false); + } + // + // Validate persistent object: + if (isAsset && (m instanceof MInvoiceLine)) { + MInvoiceLine line = (MInvoiceLine)m; + // + // If is expense, then asset is mandatory + if (MInvoiceLine.A_CAPVSEXP_Expense.equals(line.getA_CapvsExp()) && line.getA_Asset_ID() <= 0) { + throw new FillMandatoryException(MInvoiceLine.COLUMNNAME_A_Asset_ID); + } + // + // Check Amounts & Qty + if (line.getLineNetAmt().signum() == 0) { + throw new FillMandatoryException(MInvoiceLine.COLUMNNAME_QtyEntered, MInvoiceLine.COLUMNNAME_PriceEntered); + } + // + // Check Product - fixed assets products shouldn't be stocked (but inventory objects are allowed) + MProduct product = line.getProduct(); + if (product.isStocked() && line.get_ValueAsBoolean("IsFixedAssetInvoice")) { + throw new AssetProductStockedException(product); + } + } + } + + // + // Update Invoice Header: + if (TYPE_AFTER_NEW == changeType || TYPE_AFTER_CHANGE == changeType || TYPE_AFTER_DELETE == changeType) { + int invoice_id = SetGetUtil.get_AttrValueAsInt(m, MInvoiceLine.COLUMNNAME_C_Invoice_ID); + String sql = + "UPDATE C_Invoice i SET IsFixedAssetInvoice" + +"=(SELECT COALESCE(MAX(il.IsFixedAssetInvoice),'N')" + +" FROM C_InvoiceLine il" + +" WHERE il.C_Invoice_ID=i.C_Invoice_ID" + +" AND il."+MInvoiceLine.COLUMNNAME_IsDescription+"='N'" + +")" + +" WHERE C_Invoice_ID=?"; + DB.executeUpdateEx(sql, new Object[]{invoice_id}, m.get_TrxName()); + } + } + + /** + * Check if is a valid fixed asset related invoice (LRO) + * @param invoice + */ + private void validateFixedAssetsInvoice_LRO(MInvoice invoice) + { + if (invoice.get_ValueAsBoolean("IsFixedAssetInvoice")) + { + boolean hasFixedAssetLines = false; + boolean hasNormalLines = false; + for (MInvoiceLine line : invoice.getLines()) + { + if (line.get_ValueAsBoolean("IsFixedAssetInvoice")) + { + hasFixedAssetLines = true; + } + else if (line.getM_Product_ID() > 0) + { + MProduct product = MProduct.get(line.getCtx(), line.getM_Product_ID()); + if (product.isItem()) + { + // Only items are forbiden for FA invoices because in Romania these should use + // V_Liability vendor account and not V_Liability_FixedAssets vendor account + hasNormalLines = true; + } + } + // + // No mixed lines are allowed + if (hasFixedAssetLines && hasNormalLines) + { + throw new AssetInvoiceWithMixedLines_LRO(); + } + } + } + } + + + + + public String factsValidate(MAcctSchema schema, List facts, PO po) { + // TODO: implement it + return null; + } +} diff --git a/org.adempiere.base/src/org/idempiere/fa/process/A_Asset_Addition_ProcessAll.java b/org.adempiere.base/src/org/idempiere/fa/process/A_Asset_Addition_ProcessAll.java new file mode 100644 index 0000000000..42487e4cc7 --- /dev/null +++ b/org.adempiere.base/src/org/idempiere/fa/process/A_Asset_Addition_ProcessAll.java @@ -0,0 +1,44 @@ +package org.idempiere.fa.process; + +import org.compiere.model.MAssetAddition; +import org.compiere.model.POResultSet; +import org.compiere.model.Query; +import org.compiere.process.SvrProcess; + + +/** + * Process All (not processed) Additions + * @author Teo Sarca, SC ARHIPAC SERVICE SRL + */ +public class A_Asset_Addition_ProcessAll extends SvrProcess +{ + + protected void prepare() { + } + + protected String doIt() throws Exception { + int cnt_ok = 0, cnt_err = 0; + // + String whereClause = "AD_Client_ID=? AND IsActive=?" + +" AND "+MAssetAddition.COLUMNNAME_Processed+"=?"; + POResultSet + rs = new Query(getCtx(), MAssetAddition.Table_Name, whereClause, get_TrxName()) + .setParameters(new Object[]{getAD_Client_ID(), "N", "N"}) + .scroll(); + try { + while (rs.hasNext()) { + MAssetAddition a = rs.next(); + boolean ret = a.processIt(MAssetAddition.DOCACTION_Complete); + if (ret) + cnt_ok++; + else + cnt_err++; + } + } + finally { + rs.close(); rs = null; + } + // + return "OK/Error: "+cnt_ok+"/"+cnt_err; + } +} diff --git a/org.adempiere.base/src/org/idempiere/fa/process/A_Asset_CreateFromMatchInv.java b/org.adempiere.base/src/org/idempiere/fa/process/A_Asset_CreateFromMatchInv.java new file mode 100644 index 0000000000..cdafbb7602 --- /dev/null +++ b/org.adempiere.base/src/org/idempiere/fa/process/A_Asset_CreateFromMatchInv.java @@ -0,0 +1,48 @@ +package org.idempiere.fa.process; + +import java.util.logging.Level; + +import org.compiere.model.MAssetAddition; +import org.compiere.model.MMatchInv; +import org.compiere.process.ProcessInfoParameter; +import org.compiere.process.SvrProcess; +import org.idempiere.fa.exceptions.AssetException; + + + +/** + * Create asset from match invoice process + * @author Teo Sarca, SC ARHIPAC SERVICE SRL + */ +public class A_Asset_CreateFromMatchInv extends SvrProcess { + private int p_M_MatchInv_ID = -1; + + /** + * Prepare - e.g., get Parameters. + */ + protected void prepare() + { + ProcessInfoParameter[] para = getParameter(); + for (int i = 0; i < para.length; i++) + { + String name = para[i].getParameterName(); + if (para[i].getParameter() == null) + ; + else if (name.equals("M_MatchInv_ID")) + p_M_MatchInv_ID = para[i].getParameterAsInt(); + else + log.log(Level.SEVERE, "@UnknownParameter@ " + name); + } + } // prepare + + protected String doIt() throws Exception + { + MMatchInv match = new MMatchInv(getCtx(), p_M_MatchInv_ID, get_TrxName()); + if (match == null || match.get_ID() <= 0) { + throw new AssetException("@NotFound@ @M_MatchInv_ID@=" + match + "(ID="+p_M_MatchInv_ID+")"); + } + MAssetAddition assetAdd = MAssetAddition.createAsset(match); + + return "@A_Asset_Addition_ID@ - " + assetAdd; + } +} diff --git a/org.adempiere.base/src/org/idempiere/fa/process/A_Depreciation_Exp_Check.java b/org.adempiere.base/src/org/idempiere/fa/process/A_Depreciation_Exp_Check.java new file mode 100644 index 0000000000..829d24e401 --- /dev/null +++ b/org.adempiere.base/src/org/idempiere/fa/process/A_Depreciation_Exp_Check.java @@ -0,0 +1,171 @@ +/** + * + */ +package org.idempiere.fa.process; + +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.List; + +import org.compiere.model.MAsset; +import org.compiere.model.MDepreciationEntry; +import org.compiere.model.MDepreciationExp; +import org.compiere.model.MDepreciationWorkfile; +import org.compiere.model.MPeriod; +import org.compiere.model.Query; +import org.compiere.process.ProcessInfoParameter; +import org.compiere.process.SvrProcess; +import org.compiere.util.DB; +import org.compiere.util.TimeUtil; + + +/** + * @author Anca Bradau www.arhipac.ro + * + */ +public class A_Depreciation_Exp_Check extends SvrProcess +{ + private boolean p_IsTest = true; + private int p_A_Asset_ID = -1; + private String p_WhereClause = null; + + + protected void prepare() + { + ; + for (ProcessInfoParameter para : getParameter()) + { + String name = para.getParameterName(); + if (para.getParameter() == null) + ; + else if (name.equals("IsTest")) + { + p_IsTest = para.getParameterAsBoolean(); + } + else if (name.equals("A_Asset_ID")) + { + p_A_Asset_ID = para.getParameterAsInt(); + } + else if (name.equals("WhereClause")) + { + p_WhereClause = (String)para.getParameter(); + } + else + { + } + } + } + + + protected String doIt() throws Exception + { +// ARHIPAC.assertDebugging(); + + for (int A_Asset_ID : getAsset_IDs()) + { + fixDepreciation(A_Asset_ID); + if (p_IsTest) + { + rollback(); + } + } + + return "Ok"; + } + + private int[] getAsset_IDs() + { + ArrayList params = new ArrayList(); + String whereClause = null; + if (p_A_Asset_ID > 0) + { + whereClause = "A_Asset_ID=?"; + params.add(p_A_Asset_ID); + } + else + { + whereClause = p_WhereClause; + } + + return new Query(getCtx(), MAsset.Table_Name, whereClause, get_TrxName()) + .setParameters(params) + .setOrderBy("A_Asset_ID") + .getIDs(); + } + + private void fixDepreciation(int A_Asset_ID) + { + MAsset asset = MAsset.get(getCtx(), A_Asset_ID, get_TrxName()); + List depreciations = getDepreciation(asset); + // if exist depreciations with period 0 + if (depreciations.get(0).getA_Period()==0) + { + fixDepreciationExp(depreciations.get(0), TimeUtil.getMonthLastDay(asset.getAssetServiceDate())); + Timestamp tms = depreciations.get(0).getDateAcct(); + for (int i=1; i 0) + { + int C_Period_ID = DB.getSQLValueEx(exp.get_TrxName(), + "SELECT C_Period_ID FROM A_Depreciation_Entry WHERE A_Depreciation_Entry_ID=?", + exp.getA_Depreciation_Entry_ID()); + MPeriod period = MPeriod.get(exp.getCtx(), C_Period_ID); + if (!period.isInPeriod(exp.getDateAcct())) + { + addLog("OLD2: "+exp); + MDepreciationEntry.deleteFacts(exp); + exp.setA_Depreciation_Entry_ID(0); + exp.saveEx(); + addLog("NEW2: "+exp); + } + } + } + + private List getDepreciation(MAsset asset) + { + String whereClause = "A_Asset_ID=?"; + return new Query(getCtx(), MDepreciationExp.Table_Name, whereClause, get_TrxName()) + .setParameters(new Object[]{asset.get_ID()}) + .setOrderBy(MDepreciationExp.COLUMNNAME_A_Period) + .list(); + } + +} diff --git a/org.adempiere.base/src/org/idempiere/fa/process/A_Depreciation_Exp_Modify.java b/org.adempiere.base/src/org/idempiere/fa/process/A_Depreciation_Exp_Modify.java new file mode 100644 index 0000000000..98333c561c --- /dev/null +++ b/org.adempiere.base/src/org/idempiere/fa/process/A_Depreciation_Exp_Modify.java @@ -0,0 +1,86 @@ +/** + * + */ +package org.idempiere.fa.process; + +import org.adempiere.exceptions.AdempiereException; +import org.adempiere.exceptions.FillMandatoryException; +import org.compiere.model.MDepreciationEntry; +import org.compiere.model.MDepreciationExp; +import org.compiere.process.ProcessInfoParameter; +import org.compiere.process.SvrProcess; + + +/** + * WARNING: INTERNAL PROCESS + * @author Anca Bradau www.arhipac.ro + * + */ +public class A_Depreciation_Exp_Modify extends SvrProcess +{ + private int p_A_Depreciation_Exp_ID = -1; + private int p_DR_Account_ID = -1; + private int p_CR_Account_ID = -1; + private boolean p_IsTest = true; + + + + protected void prepare() + { + ; + for (ProcessInfoParameter para : getParameter()) + { + String name = para.getParameterName(); + if (para.getParameter() == null) + ; + else if (name.equals("IsTest")) + { + p_IsTest = para.getParameterAsBoolean(); + } + + else if(name.equals(MDepreciationExp.COLUMNNAME_A_Depreciation_Exp_ID)) + { + p_A_Depreciation_Exp_ID = para.getParameterAsInt(); + } + else if (name.equals(MDepreciationExp.COLUMNNAME_DR_Account_ID)) + { + p_DR_Account_ID = para.getParameterAsInt(); + } + else if (name.equals(MDepreciationExp.COLUMNNAME_CR_Account_ID)) + { + p_CR_Account_ID = para.getParameterAsInt(); + } + } + + + } + + + protected String doIt() throws Exception + { +// ARHIPAC.assertDebugging(); + // + if (p_A_Depreciation_Exp_ID <= 0) + { + throw new FillMandatoryException("A_Depreciation_Exp_ID"); + } + // + MDepreciationExp exp = new MDepreciationExp(getCtx(), p_A_Depreciation_Exp_ID, get_TrxName()); + if (exp.get_ID() != p_A_Depreciation_Exp_ID) + { + throw new AdempiereException("@NotFound@ @A_Depreciation_Exp_ID@ = "+p_A_Depreciation_Exp_ID); + } + // + MDepreciationEntry.deleteFacts(exp); + exp.setDR_Account_ID(p_DR_Account_ID); + exp.setCR_Account_ID(p_CR_Account_ID); + exp.saveEx(); + // + if (p_IsTest) + { + rollback(); + } + // + return "Ok"; + } +} diff --git a/org.adempiere.base/src/org/idempiere/fa/process/A_Depreciation_Exp_Process.java b/org.adempiere.base/src/org/idempiere/fa/process/A_Depreciation_Exp_Process.java new file mode 100644 index 0000000000..bebeae73b1 --- /dev/null +++ b/org.adempiere.base/src/org/idempiere/fa/process/A_Depreciation_Exp_Process.java @@ -0,0 +1,25 @@ +/****************************************************************************** + * Copyright (C) 2008 SC ARHIPAC SERVICE SRL. All Rights Reserved. * + *****************************************************************************/ +package org.idempiere.fa.process; + +import org.compiere.model.MDepreciationExp; +import org.compiere.process.SvrProcess; + + +/** + * @author Teo_Sarca, SC ARHIPAC SERVICE SRL + */ +public class A_Depreciation_Exp_Process extends SvrProcess { + + protected void prepare() + { + } + + protected String doIt() throws Exception + { + MDepreciationExp depexp = new MDepreciationExp(getCtx(), getRecord_ID(), get_TrxName()); + depexp.process(); + return "@Processed@"; + } +} diff --git a/org.adempiere.base/src/org/idempiere/fa/process/A_Depreciation_Workfile_Build.java b/org.adempiere.base/src/org/idempiere/fa/process/A_Depreciation_Workfile_Build.java new file mode 100644 index 0000000000..da80b30e68 --- /dev/null +++ b/org.adempiere.base/src/org/idempiere/fa/process/A_Depreciation_Workfile_Build.java @@ -0,0 +1,66 @@ +/** + * + */ +package org.idempiere.fa.process; + +import org.compiere.model.MDepreciationWorkfile; +import org.compiere.model.POResultSet; +import org.compiere.model.Query; +import org.compiere.process.ProcessInfoParameter; +import org.compiere.process.SvrProcess; +import org.compiere.util.DB; + + +/** + * Create Depreciation + * @author Teo Sarca, SC ARHIPAC SERVICE SRL + */ +public class A_Depreciation_Workfile_Build extends SvrProcess +{ + private int A_Depreciation_Workfile_ID = 0; + + protected void prepare() { + A_Depreciation_Workfile_ID = getRecord_ID(); + ProcessInfoParameter[] para = getParameter(); + for (int i = 0; i < para.length; i++) + { + String name = para[i].getParameterName(); + if (para[i].getParameter() == null) + ; + else if (name.equals("AllAssets")) { + if ("Y".equals(para[i].getParameter())) + A_Depreciation_Workfile_ID = 0; + } + else { + } + } + } + + protected String doIt() throws Exception { + int cnt_all = 0; + if (A_Depreciation_Workfile_ID > 0) { + MDepreciationWorkfile wk = new MDepreciationWorkfile(getCtx(), A_Depreciation_Workfile_ID, get_TrxName()); + wk.buildDepreciation(); + wk.saveEx(); + cnt_all = 1; + } + else { + String whereClause = MDepreciationWorkfile.COLUMNNAME_IsDepreciated + "='Y'"; + POResultSet + rs = new Query(getCtx(), MDepreciationWorkfile.Table_Name, whereClause, get_TrxName()) + .scroll(); + try { + while(rs.hasNext()) { + MDepreciationWorkfile wk = rs.next(); + wk.buildDepreciation(); + wk.saveEx(); + } + } + finally { + DB.close(rs); rs = null; + } + } + // + return "@Processed@ #" + cnt_all; + } +} diff --git a/org.adempiere.base/src/org/idempiere/fa/process/ImportFixedAsset.java b/org.adempiere.base/src/org/idempiere/fa/process/ImportFixedAsset.java new file mode 100644 index 0000000000..80359b3eda --- /dev/null +++ b/org.adempiere.base/src/org/idempiere/fa/process/ImportFixedAsset.java @@ -0,0 +1,411 @@ +package org.idempiere.fa.process; + +import java.math.BigDecimal; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Timestamp; +import java.util.logging.Level; + +import org.compiere.model.I_C_BPartner; +import org.compiere.model.MAssetAddition; +import org.compiere.model.MBPartner; +import org.compiere.model.MBPartnerLocation; +import org.compiere.model.MIFixedAsset; +import org.compiere.model.MLocation; +import org.compiere.model.MProduct; +import org.compiere.model.POResultSet; +import org.compiere.model.Query; +import org.compiere.model.X_I_FixedAsset; +import org.compiere.process.DocAction; +import org.compiere.process.ProcessInfoParameter; +import org.compiere.process.SvrProcess; +import org.compiere.util.DB; +import org.compiere.util.Env; + + +/** + * Import Fixed Asset + * + * @author Zuhri Utama, Ambidexter [based on ImportAssetClass Teo Sarca] + * + * @version $Id$ + */ +public class ImportFixedAsset extends SvrProcess +{ + /** Client to be imported to */ + private int p_AD_Client_ID = 0; + /** Organization to be imported to */ + private int p_AD_Org_ID = 0; + + /** Account Date */ + private Timestamp p_DateAcct = null; + + /** Validate Only - only validate import data */ + private boolean p_IsValidateOnly = false; + + /** Delete old Imported */ + private boolean p_DeleteOldImported = true; + + /** + * Prepare - e.g., get Parameters. + */ + protected void prepare() + { + ProcessInfoParameter[] para = getParameter(); + for (int i = 0; i < para.length; i++) + { + String name = para[i].getParameterName(); + if (para[i].getParameter() == null) + ; + else if (name.equals("AD_Client_ID")) + p_AD_Client_ID = ((BigDecimal)para[i].getParameter()).intValue(); + else if (name.equals("AD_Org_ID")) + p_AD_Org_ID = ((BigDecimal)para[i].getParameter()).intValue(); + + else if (name.equals("DateAcct")) + p_DateAcct = ((Timestamp)para[i].getParameter()); + else if (name.equals("DeleteOldImported")) + p_DeleteOldImported = "Y".equals(para[i].getParameter()); + else if (name.equals("IsValidateOnly")) + p_IsValidateOnly = "Y".equals(para[i].getParameter()); + else + log.log(Level.SEVERE, "Unknown Parameter: " + name); + } + } // prepare + + + /** + * Perrform process. + * @return Message + * @throws Exception + */ + protected String doIt() throws java.lang.Exception + { + StringBuffer sql = null; + int no = 0; + if(p_AD_Client_ID==0) + p_AD_Client_ID = Env.getAD_Client_ID(getCtx()); + String sqlCheck = " AND AD_Client_ID=" + p_AD_Client_ID; + + // **** Prepare **** + + // Delete Old Imported + if (p_DeleteOldImported) + { + sql = new StringBuffer ("DELETE "+X_I_FixedAsset.Table_Name + + " WHERE I_IsImported='Y'").append (sqlCheck); + no = DB.executeUpdateEx(sql.toString(), get_TrxName()); + log.fine("Delete Old Imported =" + no); + } + + // Set Client, Org, IsActive, Created/Updated + sql = new StringBuffer ("UPDATE "+MIFixedAsset.Table_Name+ " " + + "SET AD_Client_ID = COALESCE (AD_Client_ID,").append (p_AD_Client_ID).append (")," + + " AD_Org_ID = COALESCE (AD_Org_ID,").append (p_AD_Org_ID).append (")," + + " IsActive = COALESCE (IsActive, 'Y')," + + " Created = COALESCE (Created, SysDate)," + + " CreatedBy = COALESCE (CreatedBy, 0)," + + " Updated = COALESCE (Updated, SysDate)," + + " UpdatedBy = COALESCE (UpdatedBy, 0)," + + " I_ErrorMsg = ' '," + + " I_IsImported = 'N' " + + "WHERE I_IsImported<>'Y' OR I_IsImported IS NULL"); + no = DB.executeUpdate(sql.toString(), get_TrxName()); + log.info ("Reset=" + no); + + // Check if Org is Null or 0 + sql = new StringBuffer ("UPDATE "+MIFixedAsset.Table_Name+" ifa " + + "SET I_IsImported='N', I_ErrorMsg=I_ErrorMsg||'ERR=Invalid Org, '" + + "WHERE (AD_Org_ID IS NULL OR AD_Org_ID=0" + + " OR EXISTS (SELECT * FROM AD_Org oo WHERE ifa.AD_Org_ID=oo.AD_Org_ID AND (oo.IsSummary='Y' OR oo.IsActive='N')))" + + " AND I_IsImported<>'Y'").append (sqlCheck); + no = DB.executeUpdate(sql.toString(), get_TrxName()); + if (no != 0) + log.warning ("Invalid Org=" + no); + + // Check if Name is Null + sql = new StringBuffer ("UPDATE "+MIFixedAsset.Table_Name+" ifa " + + "SET I_IsImported='N', I_ErrorMsg=I_ErrorMsg||'ERR=Name Is Mandatory, '" + + "WHERE Name IS NULL AND I_IsImported<>'Y'").append (sqlCheck); + no = DB.executeUpdate(sql.toString(), get_TrxName()); + if (no != 0) + log.warning ("Invalid Name=" + no); + + // Asset Group From Value + sql = new StringBuffer ("UPDATE "+MIFixedAsset.Table_Name+" ifa " + + "SET A_Asset_Group_ID=(SELECT MAX(A_Asset_Group_ID) FROM A_Asset_Group t" + + " WHERE ifa.A_Asset_Group_Value=t.Name AND ifa.AD_Client_ID=t.AD_Client_ID) " + + "WHERE A_Asset_Group_ID IS NULL AND A_Asset_Group_Value IS NOT NULL" + + " AND I_IsImported<>'Y'").append (sqlCheck); + no = DB.executeUpdate(sql.toString(), get_TrxName()); + log.fine("Set Asset Group from Value=" + no); + + // Check if Asset Group Have Asset Group Acct Record + sql = new StringBuffer ("UPDATE "+MIFixedAsset.Table_Name+" ifa " + + "SET I_IsImported='N', I_ErrorMsg=I_ErrorMsg||'ERR=Asset Group Doesnt Have Asset Group Acct Record, ' " + + "WHERE A_Asset_Group_ID IS NOT NULL AND A_Asset_Group_ID>0 " //@win change to AND from OR + + "AND NOT EXISTS (SELECT 1 FROM A_Asset_Group_Acct aga WHERE ifa.A_Asset_Group_ID=aga.A_Asset_Group_ID) " //@win change to AND from OR + + "AND I_IsImported<>'Y'").append (sqlCheck); + no = DB.executeUpdate(sql.toString(), get_TrxName()); + if (no != 0) + log.warning ("Invalid Asset Group=" + no); + + // Asset Type From Value + /* commented by @win + sql = new StringBuffer ("UPDATE "+MIFixedAsset.Table_Name+" ifa " + + "SET A_Asset_Type_ID=(SELECT MAX(A_Asset_Type_ID) FROM A_Asset_Type t" + + " WHERE ifa.A_Asset_Type_Value=t.Value AND ifa.AD_Client_ID=t.AD_Client_ID) " + + "WHERE A_Asset_Type_ID IS NULL AND A_Asset_Type_Value IS NOT NULL" + + " AND I_IsImported<>'Y'").append (sqlCheck); + no = DB.executeUpdate(sql.toString(), get_TrxName()); + log.fine("Set Asset Type from Value=" + no); + */ + + // BP From Value + sql = new StringBuffer ("UPDATE "+MIFixedAsset.Table_Name+" ifa " + + "SET C_BPartnerSR_ID=(SELECT MAX(C_BPartner_ID) FROM C_BPartner t" + + " WHERE ifa.BPartner_Value=t.Value AND ifa.AD_Client_ID=t.AD_Client_ID) " + + "WHERE C_BPartnerSR_ID IS NULL AND BPartner_Value IS NOT NULL" + + " AND I_IsImported<>'Y'").append (sqlCheck); + no = DB.executeUpdate(sql.toString(), get_TrxName()); + log.fine("Set BP from Value=" + no); + + // City From Value + sql = new StringBuffer ("UPDATE "+MIFixedAsset.Table_Name+" ifa " + + "SET C_City_ID=(SELECT MAX(C_City_ID) FROM C_City t" + + " WHERE ifa.C_City_Value=t.Name AND ifa.AD_Client_ID=t.AD_Client_ID) " + + "WHERE C_City_ID IS NULL AND C_City_Value IS NOT NULL" + + " AND I_IsImported<>'Y'").append (sqlCheck); + no = DB.executeUpdate(sql.toString(), get_TrxName()); + log.fine("Set City from Value=" + no); + + // Product + sql = new StringBuffer ("UPDATE "+MIFixedAsset.Table_Name+" ifa " + + "SET M_Product_ID=(SELECT MAX(M_Product_ID) FROM M_Product t" + + " WHERE ifa.ProductValue=t.Value AND ifa.AD_Client_ID=t.AD_Client_ID) " + + "WHERE M_Product_ID IS NULL AND ProductValue IS NOT NULL" + + " AND I_IsImported<>'Y'").append (sqlCheck); + no = DB.executeUpdate(sql.toString(), get_TrxName()); + log.fine("Set Product from Value=" + no); + + sql = new StringBuffer ("UPDATE "+MIFixedAsset.Table_Name+" ifa " + + "SET I_IsImported='N', I_ErrorMsg=I_ErrorMsg||'ERR=Invalid Product, ' " + + "WHERE M_Product_ID IS NULL AND ProductValue IS NOT NULL" + + " AND I_IsImported<>'Y'").append (sqlCheck); + no = DB.executeUpdate(sql.toString(), get_TrxName()); + if (no != 0) + log.warning ("Invalid Product=" + no); + + // Check if Product using Product Category has A Asset Category Set + sql = new StringBuffer ("UPDATE "+MIFixedAsset.Table_Name+" ifa " + + "SET I_IsImported='N', I_ErrorMsg=I_ErrorMsg||'ERR=Product Using Product Category Without Asset Group Defined, ' " + + "WHERE EXISTS (SELECT 1 FROM M_Product p " + + "JOIN M_Product_Category pc ON p.M_Product_Category_ID=pc.M_Product_Category_ID " + + "WHERE ifa.M_Product_ID=p.M_Product_ID " + + "AND (pc.A_Asset_Group_ID=0 OR pc.A_Asset_Group_ID IS NULL)) " + + "AND I_IsImported<>'Y'").append (sqlCheck); + no = DB.executeUpdate(sql.toString(), get_TrxName()); + if (no != 0) + log.warning ("Invalid Product Category=" + no); + + // Locator From Value + sql = new StringBuffer ("UPDATE "+MIFixedAsset.Table_Name+" ifa " + + "SET M_Locator_ID=(SELECT MAX(M_Locator_ID) FROM M_Product t" + + " WHERE ifa.LocatorValue=t.Value AND ifa.AD_Client_ID=t.AD_Client_ID) " + + "WHERE M_Locator_ID IS NULL AND LocatorValue IS NOT NULL" + + " AND I_IsImported<>'Y'").append (sqlCheck); + no = DB.executeUpdate(sql.toString(), get_TrxName()); + log.fine("Set Locator from Value=" + no); + + //-- New BPartner --------------------------------------------------- + + // Go through Fixed Assets Records w/o C_BPartner_ID + /* no need this @win + sql = new StringBuffer ("SELECT * FROM "+MIFixedAsset.Table_Name+ " + + "WHERE I_IsImported='N' AND C_BPartnerSR_ID IS NULL").append (sqlCheck); + try + { + PreparedStatement pstmt = DB.prepareStatement (sql.toString(), get_TrxName()); + ResultSet rs = pstmt.executeQuery (); + while (rs.next ()) + { + MIFixedAsset ifa = new MIFixedAsset (getCtx(), rs, get_TrxName()); + if (ifa.getBPartner_Value () == null) + continue; + + // BPartner + MBPartner bp = MBPartner.get (getCtx(), ifa.getBPartner_Value()); + if (bp == null) + { + bp = new MBPartner (getCtx (), -1, get_TrxName()); + bp.setClientOrg (ifa.getAD_Client_ID (), ifa.getAD_Org_ID ()); + bp.setValue (ifa.getBPartner_Value ()); + bp.setName (ifa.getBPartner_Value ()); + if (!bp.save ()) + continue; + } + ifa.setC_BPartnerSR_ID (bp.getC_BPartner_ID ()); + + MBPartnerLocation bpl = null; + + if (bpl == null) + { + // New Location + MLocation loc = new MLocation (getCtx (), 0, get_TrxName()); + loc.setCity (ifa.getC_City_Value ()); + if (!loc.save ()) + continue; + // + bpl = new MBPartnerLocation (bp); + bpl.setC_Location_ID (loc.getC_Location_ID()); + if (!bpl.save ()) + continue; + } + ifa.save (); + } // for all new BPartners + rs.close (); + pstmt.close (); + // + } + catch (SQLException e) + { + log.log(Level.SEVERE, "CreateBP", e); + } + sql = new StringBuffer ("UPDATE "+MIFixedAsset.Table_Name+ " " + + "SET I_IsImported='N', I_ErrorMsg=I_ErrorMsg||'ERR=No BPartner, ' " + + "WHERE C_BPartnerSR_ID IS NULL" + + " AND I_IsImported<>'Y'").append (sqlCheck); + no = DB.executeUpdate(sql.toString(), get_TrxName()); + if (no != 0) + log.warning ("No BPartner=" + no); + + commitEx(); + + //-- New Product --------------------------------------------------- + // TODO : zuhri Utama - need to fixed create new product + + // Go through Fixed Assets Records w/o M_Product_ID + sql = new StringBuffer ("SELECT * FROM "+MIFixedAsset.Table_Name+ " " + + "WHERE I_IsImported='N' AND M_Product_ID IS NULL").append (sqlCheck); + try + { + PreparedStatement pstmt = DB.prepareStatement (sql.toString(), get_TrxName()); + ResultSet rs = pstmt.executeQuery (); + while (rs.next ()) + { + MIFixedAsset ifa = new MIFixedAsset (getCtx(), rs, get_TrxName()); + if (ifa.getProductValue () == null) + continue; + + // Product + String Value = ifa.getProductValue (); + if (Value == null || Value.length() == 0) + return null; + final String whereClause = "Value=? AND AD_Client_ID=?"; + MProduct product = new Query(getCtx(), MProduct.Table_Name, whereClause, null) + .setParameters(Value,Env.getAD_Client_ID(getCtx())) + .firstOnly(); + if (product == null) + { + product = new MProduct (getCtx (), -1, get_TrxName()); + product.setAD_Org_ID(ifa.getAD_Org_ID ()); + product.setValue (ifa.getProductValue ()); + product.setName (ifa.getProductValue ()); + product.setC_UOM_ID(ifa.getC_UOM_ID()); + if(p_M_Product_Category_ID>0) + product.setM_Product_Category_ID(p_M_Product_Category_ID); + if (!product.save ()) + continue; + } + ifa.setM_Product_ID (product.getM_Product_ID()); + + ifa.save (); + } // for all new Products + rs.close (); + pstmt.close (); + // + } + catch (SQLException e) + { + log.log(Level.SEVERE, "CreateProduct", e); + } + sql = new StringBuffer ("UPDATE "+MIFixedAsset.Table_Name+ " " + + "SET I_IsImported='N', I_ErrorMsg=I_ErrorMsg||'ERR=No BPartner, ' " + + "WHERE M_Product_ID IS NULL" + + " AND I_IsImported<>'Y'").append (sqlCheck); + no = DB.executeUpdate(sql.toString(), get_TrxName()); + if (no != 0) + log.warning ("No Product=" + no); + + commitEx(); + */ //commented by @win + + if(p_IsValidateOnly) + return "Data Was Validated"; + + int cnt_ok = 0; + int cnt_err = 0; + + String whereClause = "NVL(I_IsImported,'N')='N'"+sqlCheck; + POResultSet + rs = new Query(getCtx(), X_I_FixedAsset.Table_Name, whereClause, get_TrxName()) + .scroll(); + try + { + while (rs.hasNext()) { + X_I_FixedAsset xfa = rs.next(); + MIFixedAsset ifa = new MIFixedAsset(getCtx(), xfa.getI_FixedAsset_ID(), get_TrxName()); + try + { + MAssetAddition assetAdd = MAssetAddition.createAsset(ifa); + if(assetAdd==null){ + ifa.setI_ErrorMsg("Failed Create Assets"); + cnt_err++; + assetAdd=null; + continue; + } + //if(p_A_Asset_Group_ID>0) + // assetAdd.getA_Asset().setA_Asset_Group_ID(p_A_Asset_Group_ID); + //if(p_DateAcct!=null) + // assetAdd.setDateAcct(p_DateAcct); + assetAdd.saveEx(); + + //Process Asset Addition Based on Document Action + if(!assetAdd.processIt(ifa.getDocAction())){ + ifa.setI_ErrorMsg("Failed Process Asset Addition"); + cnt_err++; + assetAdd=null; + continue; + } + assetAdd.saveEx(); + + ifa.setI_IsImported(true); + ifa.setI_ErrorMsg(null); + ifa.setA_Asset_ID(assetAdd.getA_Asset_ID()); + ifa.setProcessed(true); + ifa.saveEx(); + + + + cnt_ok++; + } + catch (Exception e) { + ifa.setI_ErrorMsg(e.getLocalizedMessage()); + cnt_err++; + ifa.saveEx(); + } + } + } + finally + { + DB.close(rs); rs = null; + // + addLog (0, null, new BigDecimal (cnt_ok), "Imported @Ok@: "); + addLog (0, null, new BigDecimal (cnt_err), "Imported @Error@: "); + } + + return ""; + } // doIt + +} // ImportAssetClass \ No newline at end of file diff --git a/org.adempiere.base/src/org/idempiere/fa/process/ProjectCreateAsset.java b/org.adempiere.base/src/org/idempiere/fa/process/ProjectCreateAsset.java new file mode 100644 index 0000000000..31993f6894 --- /dev/null +++ b/org.adempiere.base/src/org/idempiere/fa/process/ProjectCreateAsset.java @@ -0,0 +1,124 @@ +/****************************************************************************** + * Product: Adempiere ERP & CRM Smart Business Solution * + * Copyright (C) 1999-2006 ComPiere, Inc. All Rights Reserved. * + * This program is free software; you can redistribute it and/or modify it * + * under the terms version 2 of the GNU General Public License as published * + * by the Free Software Foundation. This program is distributed in the hope * + * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied * + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + * See the GNU General Public License for more details. * + * You should have received a copy of the GNU General Public License along * + * with this program; if not, write to the Free Software Foundation, Inc., * + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * + * For the text or an alternative of this public license, you may reach us * + * ComPiere, Inc., 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA * + * or via info@compiere.org or http://www.compiere.org/license.html * + *****************************************************************************/ +package org.idempiere.fa.process; + + +import java.sql.Timestamp; +import java.util.logging.Level; + +import org.compiere.model.MProductCategory; +import org.compiere.model.MProject; +import org.compiere.model.MProduct; +import org.compiere.model.MAssetAddition; +import org.compiere.process.DocAction; +import org.compiere.process.ProcessInfoParameter; +import org.compiere.process.SvrProcess; + + +/** + * Open Project. + * Opening project will automatically create asset and asset addition + * + * @author zuhri utama + */ +public class ProjectCreateAsset extends SvrProcess +{ + /** Project */ + private int m_C_Project_ID = 0; + + /** Product */ + private int m_Product_ID = 0; + + /** Use Life Years */ + private int m_UseLifeYears = 0; + + + /** DateTrx for create asset */ + private Timestamp m_DateTrx = null; + + private String message = ""; + + /** + * Prepare - e.g., get Parameters. + */ + protected void prepare() + { + ProcessInfoParameter[] para = getParameter(); + for (int i = 0; i < para.length; i++) + { + String name = para[i].getParameterName(); + if (para[i].getParameter() == null) + ; + else if (para[i].getParameterName().equalsIgnoreCase("C_Project_ID")) { + m_C_Project_ID = para[i].getParameterAsInt(); + } + else if (para[i].getParameterName().equalsIgnoreCase("M_Product_ID")) { + m_Product_ID = para[i].getParameterAsInt(); + } + else if (para[i].getParameterName().equalsIgnoreCase("UseLifeYears")) { + m_UseLifeYears = para[i].getParameterAsInt(); + } + else if (para[i].getParameterName().equalsIgnoreCase("DateTrx")) { + m_DateTrx = (Timestamp)para[i].getParameter(); + } + else { + log.log(Level.SEVERE, "prepare - Unknown Parameter: " + name); + } + } + + } // prepare + + /** + * Perform process. + * @return Message (translated text) + * @throws Exception if not successful + */ + protected String doIt() throws Exception + { + if (m_C_Project_ID == 0 || m_Product_ID == 0) { + return "Missing Mandatory Field Value (Project / Product)"; + } + + MProject project = new MProject (getCtx(), m_C_Project_ID, get_TrxName()); + log.info("doIt - " + project); + + MProduct product = new MProduct(getCtx(), m_Product_ID, get_TrxName()); + MProductCategory pc = MProductCategory.get(getCtx(), product.getM_Product_Category_ID()); + if (pc.getA_Asset_Group_ID() == 0) { + return "Product is not asset type"; + } + + MAssetAddition assetAdd = MAssetAddition.createAsset(project, product); + assetAdd.setDateAcct(m_DateTrx); + assetAdd.setDateDoc(m_DateTrx); + assetAdd.setM_Product_ID(m_Product_ID); + if(m_UseLifeYears > 0) { + assetAdd.setDeltaUseLifeYears(m_UseLifeYears); + assetAdd.setDeltaUseLifeYears_F(m_UseLifeYears); + } + assetAdd.saveEx(); + if (!assetAdd.processIt(DocAction.ACTION_Complete)) { + return "Error Process Asset Addition"; + } + assetAdd.saveEx(); + + message += ". @A_Asset_Addition_ID@ - " + assetAdd; + + return "Asset Created " + message; + } // doIt + +} // ProjectClose diff --git a/org.adempiere.base/src/org/idempiere/fa/process/SvrProcess2.java b/org.adempiere.base/src/org/idempiere/fa/process/SvrProcess2.java new file mode 100644 index 0000000000..87d0488f81 --- /dev/null +++ b/org.adempiere.base/src/org/idempiere/fa/process/SvrProcess2.java @@ -0,0 +1,97 @@ +/** + * + */ +package org.idempiere.fa.process; + +import java.lang.reflect.Field; + +import org.adempiere.exceptions.AdempiereException; +import org.compiere.process.ProcessInfoParameter; +import org.compiere.process.SvrProcess; +import org.compiere.util.CLogger; + +/** + * Server Process Template (v2). + * In this version, parameters fields will be automatically filled if they start with p_ and are accessible. + * + * @author Teo Sarca, www.arhipac.ro + * + */ +public abstract class SvrProcess2 extends SvrProcess +{ + /** Logger */ + private static final CLogger s_log = CLogger.getCLogger(SvrProcess2.class); + + + protected final void prepare() + { + readParameters(this, getParameter()); + } + + private static void readParameters(SvrProcess process, ProcessInfoParameter[] params) + { + try + { + for (Field field : process.getClass().getFields()) + { + if (!field.getName().startsWith("p_")) + { + continue; + } + final String parameterName; + final boolean isTo; + if (field.getName().endsWith("_To")) + { + parameterName = field.getName().substring(2, field.getName().length() - 3); + isTo = true; + } + else + { + parameterName = field.getName().substring(2); + isTo = false; + } + // + boolean isSet = false; + for (ProcessInfoParameter para : params) + { + if (!parameterName.equals(para.getParameterName())) + { + continue; + } + if (field.getType() == int.class) + { + if (isTo) + field.setInt(process, para.getParameter_ToAsInt()); + else + field.setInt(process, para.getParameterAsInt()); + } + else if (field.getType() == boolean.class) + { + if (isTo) + field.setBoolean(process, para.getParameter_ToAsBoolean()); + else + field.setBoolean(process, para.getParameterAsBoolean()); + } + else + { + if (isTo) + field.set(process, para.getParameter_To()); + else + field.set(process, para.getParameter()); + } + isSet = true; + break; + } // for ProcessInfoParameter + // + if (!isSet) + { + s_log.info("Parameter not set - "+parameterName); + } + } // for Field + } + catch (Exception e) + { + throw new AdempiereException(e); + } + } +} diff --git a/org.adempiere.base/src/org/idempiere/fa/util/POCacheLocal.java b/org.adempiere.base/src/org/idempiere/fa/util/POCacheLocal.java new file mode 100644 index 0000000000..580bf146b4 --- /dev/null +++ b/org.adempiere.base/src/org/idempiere/fa/util/POCacheLocal.java @@ -0,0 +1,101 @@ +/** + * + */ +package org.idempiere.fa.util; + +import java.util.Properties; + +import org.adempiere.exceptions.AdempiereException; +import org.compiere.model.MTable; +import org.compiere.model.PO; + +/** + * @author Teo Sarca, SC ARHIPAC SERVICE SRL + */ +public final class POCacheLocal +{ + private final PO parent; + private final String idColumnName; + private final String po_tableName; + private T po = null; + + public static POCacheLocal newInstance(PO parent, Class cl) + { + return new POCacheLocal(parent, cl); + } + + public static POCacheLocal newInstance(PO parent, Class cl, String idColumnName) + { + return new POCacheLocal(parent, cl, idColumnName); + } + + private POCacheLocal(PO parent, Class cl) + { + this(parent, cl, null); + } + + private POCacheLocal(PO parent, Class cl, String idColumnName) + { + this.parent = parent; + try + { + this.po_tableName = (String)cl.getField("Table_Name").get(null); + } + catch (Exception e) + { + throw new AdempiereException(e); + } + if (idColumnName == null) + { + this.idColumnName = this.po_tableName + "_ID"; + } + else + { + this.idColumnName = idColumnName; + } + } + + public T get(boolean requery) + { + int id = get_id(); + if (id <= 0) + { + this.po = null; + return null; + } + if (requery || !isValidPO(this.po)) + { + this.po = load(this.parent.getCtx(), id, this.parent.get_TrxName()); + } + return this.po; + } + + public void set(T po) + { + if (isValidPO(po)) + { + this.po = po; + } + } + + private boolean isValidPO(T po) + { + int id = get_id(); + return id > 0 + && po != null + && po.get_ID() == id + && Util.equals(this.parent.get_TrxName(), po.get_TrxName()) + ; + } + + @SuppressWarnings("unchecked") + protected T load(Properties ctx, int id, String trxName) + { + return (T)MTable.get(ctx, this.po_tableName).getPO(id, trxName); + } + + private int get_id() + { + return parent.get_ValueAsInt(idColumnName); + } +} diff --git a/org.adempiere.base/src/org/idempiere/fa/util/Util.java b/org.adempiere.base/src/org/idempiere/fa/util/Util.java new file mode 100644 index 0000000000..10d011d790 --- /dev/null +++ b/org.adempiere.base/src/org/idempiere/fa/util/Util.java @@ -0,0 +1,47 @@ +/** + * + */ +package org.idempiere.fa.util; + +import java.text.SimpleDateFormat; +import java.util.Properties; + +import org.compiere.model.MClient; +import org.compiere.util.DisplayType; +import org.compiere.util.Language; + +/** + * Misc utils + * @author Teo Sarca, www.arhipac.ro + * + */ +public final class Util +{ + private Util() + { + // nothing + } + + /** + * @param ctx + * @return DateFormat for current AD_Client's language + */ + public static SimpleDateFormat getClientDateFormat(Properties ctx) + { + String lang = MClient.get(ctx).getAD_Language(); + return DisplayType.getDateFormat(Language.getLanguage(lang)); + } + + /** + * Check if strings are equal. + * We consider 2 strings equal if they both are null or they both are equal. + * @param s1 + * @param s2 + * @return true if string are equal + */ + public static boolean equals(String s1, String s2) + { + return (s1 == null && s2 == null) + || (s1 != null && s2 != null && s1.equals(s2)); + } +}