From fd04f75d8acd195b9aa1c5f963abb66f5014a5ab Mon Sep 17 00:00:00 2001 From: armenrz Date: Tue, 19 Jun 2007 12:47:17 +0000 Subject: [PATCH] Average Costing & Landed Cost fixes --- base/src/org/compiere/model/MCostDetail.java | 121 +++++++++++++++--- base/src/org/compiere/model/MInvoice.java | 6 + base/src/org/compiere/model/MInvoiceLine.java | 87 +++++++++++++ base/src/org/compiere/model/MMatchInv.java | 79 ++++++++++++ base/src/org/compiere/model/MMatchPO.java | 73 +++++++++++ 5 files changed, 348 insertions(+), 18 deletions(-) diff --git a/base/src/org/compiere/model/MCostDetail.java b/base/src/org/compiere/model/MCostDetail.java index 18fb4ec7c9..5965e18ef5 100644 --- a/base/src/org/compiere/model/MCostDetail.java +++ b/base/src/org/compiere/model/MCostDetail.java @@ -73,10 +73,17 @@ public class MCostDetail extends X_M_CostDetail } else { - cd.setDeltaAmt(cd.getAmt().subtract(Amt)); - cd.setDeltaQty(cd.getQty().subtract(Qty)); + // MZ Goodwill + // set deltaAmt=Amt, deltaQty=qty, and set Cost Detail for Amt and Qty + cd.setDeltaAmt(Amt.subtract(cd.getAmt())); + cd.setDeltaQty(Qty.subtract(cd.getQty())); if (cd.isDelta()) + { cd.setProcessed(false); + cd.setAmt(Amt); + cd.setQty(Qty); + } + // end MZ else return true; // nothing to do } @@ -91,6 +98,7 @@ public class MCostDetail extends X_M_CostDetail return ok; } // createOrder + /** * Create New Invoice Cost Detail for AP Invoices. * Called from Doc_Invoice - for Invoice Adjustments @@ -133,10 +141,17 @@ public class MCostDetail extends X_M_CostDetail } else { - cd.setDeltaAmt(cd.getAmt().subtract(Amt)); - cd.setDeltaQty(cd.getQty().subtract(Qty)); + // MZ Goodwill + // set deltaAmt=Amt, deltaQty=qty, and set Cost Detail for Amt and Qty + cd.setDeltaAmt(Amt.subtract(cd.getAmt())); + cd.setDeltaQty(Qty.subtract(cd.getQty())); if (cd.isDelta()) + { cd.setProcessed(false); + cd.setAmt(Amt); + cd.setQty(Qty); + } + // end MZ else return true; // nothing to do } @@ -195,10 +210,17 @@ public class MCostDetail extends X_M_CostDetail } else { - cd.setDeltaAmt(cd.getAmt().subtract(Amt)); - cd.setDeltaQty(cd.getQty().subtract(Qty)); + // MZ Goodwill + // set deltaAmt=Amt, deltaQty=qty, and set Cost Detail for Amt and Qty + cd.setDeltaAmt(Amt.subtract(cd.getAmt())); + cd.setDeltaQty(Qty.subtract(cd.getQty())); if (cd.isDelta()) + { cd.setProcessed(false); + cd.setAmt(Amt); + cd.setQty(Qty); + } + // end MZ else return true; // nothing to do } @@ -255,10 +277,17 @@ public class MCostDetail extends X_M_CostDetail } else { - cd.setDeltaAmt(cd.getAmt().subtract(Amt)); - cd.setDeltaQty(cd.getQty().subtract(Qty)); + // MZ Goodwill + // set deltaAmt=Amt, deltaQty=qty, and set Cost Detail for Amt and Qty + cd.setDeltaAmt(Amt.subtract(cd.getAmt())); + cd.setDeltaQty(Qty.subtract(cd.getQty())); if (cd.isDelta()) + { cd.setProcessed(false); + cd.setAmt(Amt); + cd.setQty(Qty); + } + // end MZ else return true; // nothing to do } @@ -319,10 +348,17 @@ public class MCostDetail extends X_M_CostDetail } else { - cd.setDeltaAmt(cd.getAmt().subtract(Amt)); - cd.setDeltaQty(cd.getQty().subtract(Qty)); + // MZ Goodwill + // set deltaAmt=Amt, deltaQty=qty, and set Cost Detail for Amt and Qty + cd.setDeltaAmt(Amt.subtract(cd.getAmt())); + cd.setDeltaQty(Qty.subtract(cd.getQty())); if (cd.isDelta()) + { cd.setProcessed(false); + cd.setAmt(Amt); + cd.setQty(Qty); + } + // end MZ else return true; // nothing to do } @@ -379,10 +415,17 @@ public class MCostDetail extends X_M_CostDetail } else { - cd.setDeltaAmt(cd.getAmt().subtract(Amt)); - cd.setDeltaQty(cd.getQty().subtract(Qty)); + // MZ Goodwill + // set deltaAmt=Amt, deltaQty=qty, and set Cost Detail for Amt and Qty + cd.setDeltaAmt(Amt.subtract(cd.getAmt())); + cd.setDeltaQty(Qty.subtract(cd.getQty())); if (cd.isDelta()) + { cd.setProcessed(false); + cd.setAmt(Amt); + cd.setQty(Qty); + } + // end MZ else return true; // nothing to do } @@ -407,7 +450,7 @@ public class MCostDetail extends X_M_CostDetail * @param trxName trx * @return cost detail */ - private static MCostDetail get (Properties ctx, String whereClause, + public static MCostDetail get (Properties ctx, String whereClause, int ID, int M_AttributeSetInstance_ID, String trxName) { String sql = "SELECT * FROM M_CostDetail WHERE " + whereClause; @@ -766,9 +809,46 @@ public class MCostDetail extends X_M_CostDetail // if (cost == null) // cost = new MCost(product, M_ASI_ID, // as, Org_ID, ce.getM_CostElement_ID()); - - BigDecimal qty = getQty(); - BigDecimal amt = getAmt(); + + // MZ Goodwill + // reset non Material Cost Element when CurrentQty is ZERO and from Matched Invoice + if (ce.getCostingMethod() != null) + { + if (cost.getCurrentQty().signum() == 0 // CurrentQty is ZERO + && getC_InvoiceLine_ID() != 0 && !product.isService() // from Matched Invoice + && ce.getCostingMethod().equals(as.getCostingMethod())) // based on Accounting Schema Costing Method + { + MCostElement[] nce = MCostElement.getNonCostingMethods(this); + for (int i = 0 ; i < nce.length ; i++) + { + MCost ncost = MCost.get(getCtx(), cost.getAD_Client_ID(), cost.getAD_Org_ID(), cost.getM_Product_ID(), cost.getM_CostType_ID(), cost.getC_AcctSchema_ID(), nce[i].getM_CostElement_ID(), cost.getM_AttributeSetInstance_ID()); + if (ncost != null) + { + ncost.setCurrentCostPrice(Env.ZERO); + ncost.setCurrentQty(Env.ZERO); + ncost.save(); + } + } + } + } + // end MZ + + // MZ Goodwill + // used deltaQty and deltaAmt if exist + BigDecimal qty = Env.ZERO; + BigDecimal amt = Env.ZERO; + if (isDelta()) + { + qty = getDeltaQty(); + amt = getDeltaAmt(); + } + else + { + qty = getQty(); + amt = getAmt(); + } + // end MZ + int precision = as.getCostingPrecision(); BigDecimal price = amt; if (qty.signum() != 0) @@ -878,7 +958,13 @@ public class MCostDetail extends X_M_CostDetail } else if (!ce.isCostingMethod()) // Cost Adjustments { - BigDecimal cCosts = cost.getCurrentCostPrice().add(amt); + // MZ Goodwill + // Current Cost is using average + BigDecimal cCosts = cost.getCurrentCostPrice().multiply(cost.getCurrentQty()).add(amt); + BigDecimal cQty = cost.getCurrentQty().add(qty); + if (cQty.signum() != 0) + cCosts = cCosts.divide(cQty, precision, BigDecimal.ROUND_HALF_UP); + // end MZ cost.setCurrentCostPrice(cCosts); cost.add(amt, qty); log.finer("Inv - none - " + cost); @@ -982,7 +1068,6 @@ public class MCostDetail extends X_M_CostDetail log.warning("Unknown Type: " + toString()); return false; } - return cost.save(); } // process diff --git a/base/src/org/compiere/model/MInvoice.java b/base/src/org/compiere/model/MInvoice.java index 7cbcef6b48..30040b9655 100644 --- a/base/src/org/compiere/model/MInvoice.java +++ b/base/src/org/compiere/model/MInvoice.java @@ -708,6 +708,12 @@ public class MInvoice extends X_C_Invoice implements DocAction fromLine.setRef_InvoiceLine_ID(line.getC_InvoiceLine_ID()); fromLine.save(get_TrxName()); } + + // MZ Goodwill + // copy the landed cost + line.copyLandedCostFrom(fromLine); + line.allocateLandedCosts(); + // end MZ } if (fromLines.length != count) log.log(Level.SEVERE, "Line difference - From=" + fromLines.length + " <> Saved=" + count); diff --git a/base/src/org/compiere/model/MInvoiceLine.java b/base/src/org/compiere/model/MInvoiceLine.java index cbcab33dd2..4cc8d95b56 100644 --- a/base/src/org/compiere/model/MInvoiceLine.java +++ b/base/src/org/compiere/model/MInvoiceLine.java @@ -932,6 +932,10 @@ public class MInvoiceLine extends X_C_InvoiceLine lca.setM_AttributeSetInstance_ID(iol.getM_AttributeSetInstance_ID()); BigDecimal base = iol.getBase(lc.getLandedCostDistribution()); lca.setBase(base); + // MZ Goodwill + // add set Qty from InOutLine + lca.setQty(iol.getMovementQty()); + // end MZ if (base.signum() != 0) { double result = getLineNetAmt().multiply(base).doubleValue(); @@ -956,6 +960,10 @@ public class MInvoiceLine extends X_C_InvoiceLine lca.setM_Product_ID(iol.getM_Product_ID()); lca.setM_AttributeSetInstance_ID(iol.getM_AttributeSetInstance_ID()); lca.setAmt(getLineNetAmt()); + // MZ Goodwill + // add set Qty from InOutLine + lca.setQty(iol.getMovementQty()); + // end MZ if (lca.save()) return ""; return "Cannot save single line Allocation = " + lc; @@ -1033,6 +1041,10 @@ public class MInvoiceLine extends X_C_InvoiceLine lca.setM_AttributeSetInstance_ID(iol.getM_AttributeSetInstance_ID()); BigDecimal base = iol.getBase(LandedCostDistribution); lca.setBase(base); + // MZ Goodwill + // add set Qty from InOutLine + lca.setQty(iol.getMovementQty()); + // end MZ if (base.signum() != 0) { double result = getLineNetAmt().multiply(base).doubleValue(); @@ -1077,4 +1089,79 @@ public class MInvoiceLine extends X_C_InvoiceLine } } // allocateLandedCostRounding + // MZ Goodwill + /** + * Get LandedCost of InvoiceLine + * @param whereClause starting with AND + * @return landedCost + */ + public MLandedCost[] getLandedCost (String whereClause) + { + ArrayList list = new ArrayList(); + String sql = "SELECT * FROM C_LandedCost WHERE C_InvoiceLine_ID=? "; + if (whereClause != null) + sql += whereClause; + PreparedStatement pstmt = null; + try + { + pstmt = DB.prepareStatement(sql, get_TrxName()); + pstmt.setInt(1, getC_InvoiceLine_ID()); + ResultSet rs = pstmt.executeQuery(); + while (rs.next()) + { + MLandedCost lc = new MLandedCost(getCtx(), rs, get_TrxName()); + list.add(lc); + } + rs.close(); + pstmt.close(); + pstmt = null; + } + catch (Exception e) + { + log.log(Level.SEVERE, "getLandedCost", e); + } + finally + { + try + { + if (pstmt != null) + pstmt.close (); + } + catch (Exception e) + {} + pstmt = null; + } + + // + MLandedCost[] landedCost = new MLandedCost[list.size()]; + list.toArray(landedCost); + return landedCost; + } // getLandedCost + + /** + * Copy LandedCost From other InvoiceLine. + * @param otherInvoiceLine invoiceline + * @return number of lines copied + */ + public int copyLandedCostFrom (MInvoiceLine otherInvoiceLine) + { + if (otherInvoiceLine == null) + return 0; + MLandedCost[] fromLandedCosts = otherInvoiceLine.getLandedCost(null); + int count = 0; + for (int i = 0; i < fromLandedCosts.length; i++) + { + MLandedCost landedCost = new MLandedCost (getCtx(), 0, get_TrxName()); + MLandedCost fromLandedCost = fromLandedCosts[i]; + PO.copyValues (fromLandedCost, landedCost, fromLandedCost.getAD_Client_ID(), fromLandedCost.getAD_Org_ID()); + landedCost.setC_InvoiceLine_ID(getC_InvoiceLine_ID()); + landedCost.set_ValueNoCheck ("C_LandedCost_ID", I_ZERO); // new + if (landedCost.save(get_TrxName())) + count++; + } + if (fromLandedCosts.length != count) + log.log(Level.SEVERE, "LandedCost difference - From=" + fromLandedCosts.length + " <> Saved=" + count); + return count; + } // copyLinesFrom + // end MZ } // MInvoiceLine diff --git a/base/src/org/compiere/model/MMatchInv.java b/base/src/org/compiere/model/MMatchInv.java index 696af88bd8..7af6b152f8 100644 --- a/base/src/org/compiere/model/MMatchInv.java +++ b/base/src/org/compiere/model/MMatchInv.java @@ -81,6 +81,53 @@ public class MMatchInv extends X_M_MatchInv return retValue; } // get + // MZ Goodwill + /** + * Get Inv Matches for InvoiceLine + * @param ctx context + * @param C_InvoiceLine_ID invoice + * @param trxName transaction + * @return array of matches + */ + public static MMatchInv[] getInvoiceLine (Properties ctx, int C_InvoiceLine_ID, String trxName) + { + if (C_InvoiceLine_ID == 0) + return new MMatchInv[]{}; + // + String sql = "SELECT * FROM M_MatchInv WHERE C_InvoiceLine_ID=?"; + ArrayList list = new ArrayList(); + PreparedStatement pstmt = null; + try + { + pstmt = DB.prepareStatement (sql, trxName); + pstmt.setInt (1, C_InvoiceLine_ID); + ResultSet rs = pstmt.executeQuery (); + while (rs.next ()) + list.add (new MMatchInv (ctx, rs, trxName)); + rs.close (); + pstmt.close (); + pstmt = null; + } + catch (Exception e) + { + s_log.log(Level.SEVERE, sql, e); + } + try + { + if (pstmt != null) + pstmt.close (); + pstmt = null; + } + catch (Exception e) + { + pstmt = null; + } + MMatchInv[] retValue = new MMatchInv[list.size()]; + list.toArray (retValue); + return retValue; + } // getInvoiceLine + // end MZ + /** * Get Inv Matches for InOut * @param ctx context @@ -360,6 +407,38 @@ public class MMatchInv extends X_M_MatchInv { if (success) { + // MZ Goodwill + // update/delete Cost Detail and recalculate Current Cost + MCostDetail cd = MCostDetail.get (getCtx(), "C_InvoiceLine_ID=? AND M_AttributeSetInstance_ID=?", + getC_InvoiceLine_ID(), getM_AttributeSetInstance_ID(), get_TrxName()); + if (cd != null) + { + MInOut receipt = (new MInOutLine(getCtx(),getM_InOutLine_ID(),get_TrxName())).getParent(); + BigDecimal qty = getQty(); + if (receipt.getMovementType().equals(MInOut.MOVEMENTTYPE_VendorReturns)) + qty = getQty().negate(); + // + BigDecimal price = cd.getAmt().divide(cd.getQty(),12,BigDecimal.ROUND_HALF_UP); + cd.setDeltaAmt(price.multiply(qty.negate())); + cd.setDeltaQty(qty.negate()); + cd.setProcessed(false); + // + cd.setAmt(price.multiply(cd.getQty().subtract(qty))); + cd.setQty(cd.getQty().subtract(qty)); + if (!cd.isProcessed()) + { + MClient client = MClient.get(getCtx(), getAD_Client_ID()); + if (client.isCostImmediate()) + cd.process(); + } + if (cd.getQty().compareTo(Env.ZERO) == 0) + { + cd.setProcessed(false); + cd.delete(true); + } + } + // end MZ + // Get Order and decrease invoices MInvoiceLine iLine = new MInvoiceLine (getCtx(), getC_InvoiceLine_ID(), get_TrxName()); int C_OrderLine_ID = iLine.getC_OrderLine_ID(); diff --git a/base/src/org/compiere/model/MMatchPO.java b/base/src/org/compiere/model/MMatchPO.java index a08c84c251..eccbe6a845 100644 --- a/base/src/org/compiere/model/MMatchPO.java +++ b/base/src/org/compiere/model/MMatchPO.java @@ -177,6 +177,52 @@ public class MMatchPO extends X_M_MatchPO return retValue; } // getInvoice + // MZ Goodwill + /** + * Get PO Matches for OrderLine + * @param ctx context + * @param C_OrderLine_ID order + * @param trxName transaction + * @return array of matches + */ + public static MMatchPO[] getOrderLine (Properties ctx, int C_OrderLine_ID, String trxName) + { + if (C_OrderLine_ID == 0) + return new MMatchPO[]{}; + // + String sql = "SELECT * FROM M_MatchPO WHERE C_OrderLine_ID=?"; + ArrayList list = new ArrayList(); + PreparedStatement pstmt = null; + try + { + pstmt = DB.prepareStatement (sql, trxName); + pstmt.setInt (1, C_OrderLine_ID); + ResultSet rs = pstmt.executeQuery (); + while (rs.next ()) + list.add (new MMatchPO (ctx, rs, trxName)); + rs.close (); + pstmt.close (); + pstmt = null; + } + catch (Exception e) + { + s_log.log(Level.SEVERE, sql, e); + } + try + { + if (pstmt != null) + pstmt.close (); + pstmt = null; + } + catch (Exception e) + { + pstmt = null; + } + MMatchPO[] retValue = new MMatchPO[list.size()]; + list.toArray (retValue); + return retValue; + } // getOrderLine + // end MZ /** * Find/Create PO(Inv) Match @@ -704,6 +750,33 @@ public class MMatchPO extends X_M_MatchPO // (Reserved in VMatch and MInOut.completeIt) if (success && getC_OrderLine_ID() != 0) { + // MZ Goodwill + // update/delete Cost Detail and recalculate Current Cost + MCostDetail cd = MCostDetail.get (getCtx(), "C_OrderLine_ID=? AND M_AttributeSetInstance_ID=?", + getC_OrderLine_ID(), getM_AttributeSetInstance_ID(), get_TrxName()); + if (cd != null) + { + BigDecimal price = cd.getAmt().divide(cd.getQty(),12,BigDecimal.ROUND_HALF_UP); + cd.setDeltaAmt(price.multiply(getQty().negate())); + cd.setDeltaQty(getQty().negate()); + cd.setProcessed(false); + // + cd.setAmt(price.multiply(cd.getQty().subtract(getQty()))); + cd.setQty(cd.getQty().subtract(getQty())); + if (!cd.isProcessed()) + { + MClient client = MClient.get(getCtx(), getAD_Client_ID()); + if (client.isCostImmediate()) + cd.process(); + } + if (cd.getQty().compareTo(Env.ZERO) == 0) + { + cd.setProcessed(false); + cd.delete(true); + } + } + // end MZ + MOrderLine orderLine = new MOrderLine (getCtx(), getC_OrderLine_ID(), get_TrxName()); if (getM_InOutLine_ID() != 0) orderLine.setQtyDelivered(orderLine.getQtyDelivered().subtract(getQty()));