From 7be93edc86ad48fb3ce425542f6d5dfe19ce64ca Mon Sep 17 00:00:00 2001 From: armenrz Date: Tue, 19 Jun 2007 13:32:45 +0000 Subject: [PATCH] Average Costing & Landed Cost fixes --- base/src/org/compiere/acct/DocLine.java | 22 ++++++++ base/src/org/compiere/acct/Doc_InOut.java | 6 ++- base/src/org/compiere/acct/Doc_Inventory.java | 5 +- base/src/org/compiere/acct/Doc_Invoice.java | 38 +++++++------- base/src/org/compiere/acct/Doc_MatchInv.java | 50 +++++++++++++++++-- base/src/org/compiere/acct/Doc_MatchPO.java | 47 +++++++++++++++-- base/src/org/compiere/acct/Doc_Movement.java | 7 ++- .../src/org/compiere/acct/Doc_Production.java | 42 ++++++++++------ 8 files changed, 168 insertions(+), 49 deletions(-) diff --git a/base/src/org/compiere/acct/DocLine.java b/base/src/org/compiere/acct/DocLine.java index 81240c176a..7d6bf6686a 100644 --- a/base/src/org/compiere/acct/DocLine.java +++ b/base/src/org/compiere/acct/DocLine.java @@ -687,6 +687,28 @@ public class DocLine return m_productCost; } // getProductCost + // MZ Goodwill + /** + * Get Total Product Costs from Cost Detail or from Current Cost + * @param as accounting schema + * @param AD_Org_ID trx org + * @param zeroCostsOK zero/no costs are OK + * @param whereClause null are OK + * @return costs + */ + public BigDecimal getProductCosts (MAcctSchema as, int AD_Org_ID, boolean zeroCostsOK, String whereClause) + { + if (whereClause != null) + { + MCostDetail cd = MCostDetail.get (Env.getCtx(), whereClause, + get_ID(), getM_AttributeSetInstance_ID(), p_po.get_TrxName()); + if (cd != null) + return cd.getAmt(); + } + return getProductCosts(as, AD_Org_ID, zeroCostsOK); + } // getProductCosts + // end MZ + /** * Get Total Product Costs * @param as accounting schema diff --git a/base/src/org/compiere/acct/Doc_InOut.java b/base/src/org/compiere/acct/Doc_InOut.java index 099c7df10d..e9d7c3f5fe 100644 --- a/base/src/org/compiere/acct/Doc_InOut.java +++ b/base/src/org/compiere/acct/Doc_InOut.java @@ -139,7 +139,11 @@ public class Doc_InOut extends Doc for (int i = 0; i < p_lines.length; i++) { DocLine line = p_lines[i]; - BigDecimal costs = line.getProductCosts(as, line.getAD_Org_ID(), true); + // MZ Goodwill + // if Shipment CostDetail exist then get Cost from Cost Detail + BigDecimal costs = line.getProductCosts(as, line.getAD_Org_ID(), true, "M_InOutLine_ID=? AND M_AttributeSetInstance_ID=?"); + // end MZ + if (costs == null || costs.signum() == 0) // zero costs OK { MProduct product = line.getProduct(); diff --git a/base/src/org/compiere/acct/Doc_Inventory.java b/base/src/org/compiere/acct/Doc_Inventory.java index fc8e902f51..a987d72fdf 100644 --- a/base/src/org/compiere/acct/Doc_Inventory.java +++ b/base/src/org/compiere/acct/Doc_Inventory.java @@ -134,7 +134,10 @@ public class Doc_Inventory extends Doc for (int i = 0; i < p_lines.length; i++) { DocLine line = p_lines[i]; - BigDecimal costs = line.getProductCosts(as, line.getAD_Org_ID(), false); + // MZ Goodwill + // if Physical Inventory CostDetail is exist then get Cost from Cost Detail + BigDecimal costs = line.getProductCosts(as, line.getAD_Org_ID(), true, "M_InventoryLine_ID=? AND M_AttributeSetInstance_ID=?"); + // end MZ if (costs == null || costs.signum() == 0) { p_Error = "No Costs for " + line.getProduct().getName(); diff --git a/base/src/org/compiere/acct/Doc_Invoice.java b/base/src/org/compiere/acct/Doc_Invoice.java index cde49cbe7d..2f33faf076 100644 --- a/base/src/org/compiere/acct/Doc_Invoice.java +++ b/base/src/org/compiere/acct/Doc_Invoice.java @@ -784,12 +784,6 @@ public class Doc_Invoice extends Doc if (lcas.length == 0) return false; - // Delete Old - String sql = "DELETE M_CostDetail WHERE C_InvoiceLine_ID=" + C_InvoiceLine_ID; - int no = DB.executeUpdate(sql, getTrxName()); - if (no != 0) - log.config("CostDetail Deleted #" + no); - // Calculate Total Base double totalBase = 0; for (int i = 0; i < lcas.length; i++) @@ -802,7 +796,7 @@ public class Doc_Invoice extends Doc MLandedCostAllocation lca = lcas[i]; if (lca.getBase().signum() == 0) continue; - double percent = totalBase / lca.getBase().doubleValue(); + double percent = lca.getBase().doubleValue() / totalBase; String desc = il.getDescription(); if (desc == null) desc = percent + "%"; @@ -823,6 +817,7 @@ public class Doc_Invoice extends Doc FactLine fl = fact.createLine (line, pc.getAccount(ProductCost.ACCTTYPE_P_CostAdjustment, as), getC_Currency_ID(), drAmt, crAmt); fl.setDescription(desc); + fl.setM_Product_ID(lca.getM_Product_ID()); // Cost Detail - Convert to AcctCurrency BigDecimal allocationAmt = lca.getAmt(); @@ -835,19 +830,22 @@ public class Doc_Invoice extends Doc allocationAmt = allocationAmt.setScale(as.getCostingPrecision(), BigDecimal.ROUND_HALF_UP); if (!dr) allocationAmt = allocationAmt.negate(); - MCostDetail cd = new MCostDetail (as, lca.getAD_Org_ID(), - lca.getM_Product_ID(), lca.getM_AttributeSetInstance_ID(), - lca.getM_CostElement_ID(), - allocationAmt, Env.ZERO, // Qty - desc, getTrxName()); - cd.setC_InvoiceLine_ID(C_InvoiceLine_ID); - boolean ok = cd.save(); - if (ok && !cd.isProcessed()) - { - MClient client = MClient.get(as.getCtx(), as.getAD_Client_ID()); - if (client.isCostImmediate()) - cd.process(); - } + // MZ Goodwill + // set Qty to 1 or -1 instead of 0 and allocation Amt is counted for each product qty + if (lca.getQty().signum() != 0) + allocationAmt = allocationAmt.divide(lca.getQty(), as.getCostingPrecision(), BigDecimal.ROUND_HALF_UP); + + // Qty is 1 or -1 + BigDecimal qty = Env.ONE; + if (il.getQtyInvoiced().signum() != 0) + qty = il.getQtyInvoiced().divide(il.getQtyInvoiced().abs()); + // use createInvoice to create/update non Material Cost Detail + MCostDetail.createInvoice(as, lca.getAD_Org_ID(), + lca.getM_Product_ID(), lca.getM_AttributeSetInstance_ID(), + C_InvoiceLine_ID, lca.getM_CostElement_ID(), + allocationAmt, qty, // Qty + desc, getTrxName()); + // end MZ } log.config("Created #" + lcas.length); diff --git a/base/src/org/compiere/acct/Doc_MatchInv.java b/base/src/org/compiere/acct/Doc_MatchInv.java index f6e253ce71..7ecc34f413 100644 --- a/base/src/org/compiere/acct/Doc_MatchInv.java +++ b/base/src/org/compiere/acct/Doc_MatchInv.java @@ -239,12 +239,52 @@ public class Doc_MatchInv extends Doc log.fine("IPV=" + ipv + "; Balance=" + fact.getSourceBalance()); // Cost Detail Record - data from Expense/IncClearing (CR) record + // MZ Goodwill + // Create Cost Detail Matched Invoice using Total Amount and Total Qty based on InvoiceLine + MMatchInv[] mInv = MMatchInv.getInvoiceLine(getCtx(), m_invoiceLine.getC_InvoiceLine_ID(), getTrxName()); + BigDecimal tQty = Env.ZERO; + BigDecimal tAmt = Env.ZERO; + for (int i = 0 ; i < mInv.length ; i++) + { + if (mInv[i].isPosted() && mInv[i].getM_MatchInv_ID() != get_ID()) + { + tQty = tQty.add(mInv[i].getQty()); + multiplier = mInv[i].getQty() + .divide(m_invoiceLine.getQtyInvoiced(), 12, BigDecimal.ROUND_HALF_UP) + .abs(); + tAmt = tAmt.add(m_invoiceLine.getLineNetAmt().multiply(multiplier)); + } + } + tAmt = tAmt.add(cr.getAcctBalance().negate()); + // set Qty to negative value when MovementType is Vendor Returns + MInOut receipt = m_receiptLine.getParent(); + if (receipt.getMovementType().equals(MInOut.MOVEMENTTYPE_VendorReturns)) + tQty = tQty.add(getQty().negate()); // Qty is set to negative value + else + tQty = tQty.add(getQty()); + + // Different currency + MInvoice invoice = m_invoiceLine.getParent(); + if (as.getC_Currency_ID() == invoice.getC_Currency_ID()) + { + tAmt = MConversionRate.convert(getCtx(), tAmt, + invoice.getC_Currency_ID(), as.getC_Currency_ID(), + invoice.getDateAcct(), invoice.getC_ConversionType_ID(), + invoice.getAD_Client_ID(), invoice.getAD_Org_ID()); + if (tAmt == null) + { + p_Error = "AP Invoice not convertible - " + as.getName(); + return null; + } + } + + // Set Total Amount and Total Quantity from Matched Invoice MCostDetail.createInvoice(as, getAD_Org_ID(), - getM_Product_ID(), matchInv.getM_AttributeSetInstance_ID(), - m_invoiceLine.getC_InvoiceLine_ID(), 0, // No cost element - cr.getAcctBalance().negate(), getQty(), // correcting - getDescription(), getTrxName()); - + getM_Product_ID(), matchInv.getM_AttributeSetInstance_ID(), + m_invoiceLine.getC_InvoiceLine_ID(), 0, // No cost element + tAmt, tQty, getDescription(), getTrxName()); + // end MZ + // Update Costing updateProductInfo(as.getC_AcctSchema_ID(), MAcctSchema.COSTINGMETHOD_StandardCosting.equals(as.getCostingMethod())); diff --git a/base/src/org/compiere/acct/Doc_MatchPO.java b/base/src/org/compiere/acct/Doc_MatchPO.java index eef7c8cb26..15c843a162 100644 --- a/base/src/org/compiere/acct/Doc_MatchPO.java +++ b/base/src/org/compiere/acct/Doc_MatchPO.java @@ -140,12 +140,49 @@ public class Doc_MatchPO extends Doc poCost = poCost.setScale(as.getCostingPrecision(), BigDecimal.ROUND_HALF_UP); } - // Create PO Cost Detail Record firs + // Create PO Cost Detail Record first + // MZ Goodwill + // Create Cost Detail Matched PO using Total Amount and Total Qty based on OrderLine + MMatchPO[] mPO = MMatchPO.getOrderLine(getCtx(), m_oLine.getC_OrderLine_ID(), getTrxName()); + BigDecimal tQty = Env.ZERO; + BigDecimal tAmt = Env.ZERO; + BigDecimal priceCost = m_oLine.getPriceCost(); + if (priceCost == null || priceCost.signum() == 0) + priceCost = m_oLine.getPriceActual(); + for (int i = 0 ; i < mPO.length ; i++) + { + if (mPO[i].isPosted()) + { + tQty = tQty.add(mPO[i].getQty()); + tAmt = tAmt.add(priceCost.multiply(mPO[i].getQty())); + } + } + + // Different currency + if (m_oLine.getC_Currency_ID() != as.getC_Currency_ID()) + { + MOrder order = m_oLine.getParent(); + BigDecimal rate = MConversionRate.getRate( + order.getC_Currency_ID(), as.getC_Currency_ID(), + order.getDateAcct(), order.getC_ConversionType_ID(), + m_oLine.getAD_Client_ID(), m_oLine.getAD_Org_ID()); + if (rate == null) + { + p_Error = "Purchase Order not convertible - " + as.getName(); + return null; + } + tAmt = tAmt.multiply(rate); + if (tAmt.scale() > as.getCostingPrecision()) + tAmt = tAmt.setScale(as.getCostingPrecision(), BigDecimal.ROUND_HALF_UP); + } + + // Set Total Amount and Total Quantity from Matched PO MCostDetail.createOrder(as, m_oLine.getAD_Org_ID(), - getM_Product_ID(), m_M_AttributeSetInstance_ID, - m_C_OrderLine_ID, 0, // no cost element - poCost, getQty(), // Delivered - m_oLine.getDescription(), getTrxName()); + getM_Product_ID(), m_M_AttributeSetInstance_ID, + m_C_OrderLine_ID, 0, // no cost element + tAmt, tQty, // Delivered + m_oLine.getDescription(), getTrxName()); + // end MZ // Calculate PPV for standard costing String costingMethod = as.getCostingMethod(); diff --git a/base/src/org/compiere/acct/Doc_Movement.java b/base/src/org/compiere/acct/Doc_Movement.java index 5a2ab5b025..54048c700d 100644 --- a/base/src/org/compiere/acct/Doc_Movement.java +++ b/base/src/org/compiere/acct/Doc_Movement.java @@ -120,8 +120,11 @@ public class Doc_Movement extends Doc for (int i = 0; i < p_lines.length; i++) { DocLine line = p_lines[i]; - BigDecimal costs = line.getProductCosts(as, line.getAD_Org_ID(), false); - + // MZ Goodwill + // if Inventory Move CostDetail exist then get Cost from Cost Detail + BigDecimal costs = line.getProductCosts(as, line.getAD_Org_ID(), true, "M_MovementLine_ID=? AND M_AttributeSetInstance_ID=? AND IsSOTrx='N'"); + // end MZ + // ** Inventory DR CR dr = fact.createLine(line, line.getAccount(ProductCost.ACCTTYPE_P_Asset, as), diff --git a/base/src/org/compiere/acct/Doc_Production.java b/base/src/org/compiere/acct/Doc_Production.java index fb2615d4c0..1f36e254f3 100644 --- a/base/src/org/compiere/acct/Doc_Production.java +++ b/base/src/org/compiere/acct/Doc_Production.java @@ -21,6 +21,7 @@ import java.sql.*; import java.util.*; import org.compiere.model.*; + import java.util.logging.*; import org.compiere.util.*; @@ -166,22 +167,33 @@ public class Doc_Production extends Doc DocLine line = p_lines[i]; // Calculate Costs BigDecimal costs = null; - if (line.isProductionBOM()) - { - // Get BOM Cost - Sum of individual lines - BigDecimal bomCost = Env.ZERO; - for (int ii = 0; ii < p_lines.length; ii++) - { - DocLine line0 = p_lines[ii]; - if (line0.getM_ProductionPlan_ID() != line.getM_ProductionPlan_ID()) - continue; - if (!line0.isProductionBOM()) - bomCost = bomCost.add(line0.getProductCosts(as, line.getAD_Org_ID(), false)); - } - costs = bomCost.negate(); - } + + // MZ Goodwill + // if Production CostDetail exist then get Cost from Cost Detail + MCostDetail cd = MCostDetail.get (as.getCtx(), "M_ProductionLine_ID=? AND M_AttributeSetInstance_ID=?", + line.get_ID(), line.getM_AttributeSetInstance_ID(), getTrxName()); + if (cd != null) + costs = cd.getAmt(); else - costs = line.getProductCosts(as, line.getAD_Org_ID(), false); + { + if (line.isProductionBOM()) + { + // Get BOM Cost - Sum of individual lines + BigDecimal bomCost = Env.ZERO; + for (int ii = 0; ii < p_lines.length; ii++) + { + DocLine line0 = p_lines[ii]; + if (line0.getM_ProductionPlan_ID() != line.getM_ProductionPlan_ID()) + continue; + if (!line0.isProductionBOM()) + bomCost = bomCost.add(line0.getProductCosts(as, line.getAD_Org_ID(), false)); + } + costs = bomCost.negate(); + } + else + costs = line.getProductCosts(as, line.getAD_Org_ID(), false); + } + // end MZ // Inventory DR CR fl = fact.createLine(line,