/****************************************************************************** * 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.compiere.acct; import java.math.BigDecimal; import java.math.RoundingMode; import java.sql.ResultSet; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.logging.Level; import org.compiere.model.I_C_OrderLine; import org.compiere.model.I_M_InOutLine; import org.compiere.model.I_M_RMALine; import org.compiere.model.MAccount; import org.compiere.model.MAcctSchema; import org.compiere.model.MConversionRate; import org.compiere.model.MCostDetail; import org.compiere.model.MCurrency; import org.compiere.model.MInOut; import org.compiere.model.MInOutLine; import org.compiere.model.MInOutLineMA; import org.compiere.model.MOrderLandedCostAllocation; import org.compiere.model.MOrderLine; import org.compiere.model.MProduct; import org.compiere.model.MTax; import org.compiere.model.ProductCost; import org.compiere.util.DB; import org.compiere.util.Env; import org.compiere.util.Msg; import org.compiere.util.Util; /** * Post Shipment/Receipt Documents. *
 *  Table:              M_InOut (319)
 *  Document Types:     MMS, MMR
 *  
* @author Jorg Janke * @author Armen Rizal, Goodwill Consulting *
  • BF [ 1745154 ] Cost in Reversing Material Related Docs *
  • BF [ 2858043 ] Correct Included Tax in Average Costing * @version $Id: Doc_InOut.java,v 1.3 2006/07/30 00:53:33 jjanke Exp $ */ public class Doc_InOut extends Doc { /** * Constructor * @param as accounting schema * @param rs record * @param trxName trx */ public Doc_InOut (MAcctSchema as, ResultSet rs, String trxName) { super (as, MInOut.class, rs, null, trxName); } // DocInOut private int m_Reversal_ID = 0; @SuppressWarnings("unused") private String m_DocStatus = ""; private boolean m_deferPosting = false; /** * Load Document Details * @return error message or null */ @Override protected String loadDocumentDetails() { setC_Currency_ID(NO_CURRENCY); MInOut inout = (MInOut)getPO(); setDateDoc (inout.getMovementDate()); m_Reversal_ID = inout.getReversal_ID();//store original (voided/reversed) document m_DocStatus = inout.getDocStatus(); // Contained Objects p_lines = loadLines(inout); if (log.isLoggable(Level.FINE)) log.fine("Lines=" + p_lines.length); if (inout.isSOTrx()) { MInOutLine[] lines = inout.getLines(); for (MInOutLine line : lines) { I_C_OrderLine orderLine = line.getC_OrderLine(); if (orderLine != null) { if (orderLine.getLink_OrderLine_ID() > 0) { // Defer posting if found the linked MR is not posted String sql = "SELECT COUNT(*) FROM M_InOutLine iol WHERE iol.C_OrderLine_ID=? AND EXISTS (SELECT * FROM M_InOut io WHERE io.M_InOut_ID=iol.M_InOut_ID AND io.IsSOTrx='N' AND io.Posted<>'Y')"; int count = DB.getSQLValueEx(getTrxName(), sql, orderLine.getLink_OrderLine_ID()); if (count > 0) { m_deferPosting = true; break; } } } } } return null; } // loadDocumentDetails /** * Load InOut Line * @param inout shipment/receipt * @return DocLine Array */ private DocLine[] loadLines(MInOut inout) { ArrayList list = new ArrayList(); MInOutLine[] lines = inout.getLines(false); for (int i = 0; i < lines.length; i++) { MInOutLine line = lines[i]; if (line.isDescription() || line.getM_Product_ID() == 0 || line.getMovementQty().signum() == 0) { if (log.isLoggable(Level.FINER)) log.finer("Ignored: " + line); continue; } DocLine_InOut docLine = new DocLine_InOut (line, this); BigDecimal Qty = line.getMovementQty(); docLine.setReversalLine_ID(line.getReversalLine_ID()); docLine.setQty (Qty, getDocumentType().equals(DOCTYPE_MatShipment)); // sets Trx and Storage Qty //Define if Outside Processing String sql = "SELECT PP_Cost_Collector_ID FROM C_OrderLine WHERE C_OrderLine_ID=? AND PP_Cost_Collector_ID IS NOT NULL"; int PP_Cost_Collector_ID = DB.getSQLValueEx(getTrxName(), sql, new Object[]{line.getC_OrderLine_ID()}); docLine.setPP_Cost_Collector_ID(PP_Cost_Collector_ID); // if (log.isLoggable(Level.FINE)) log.fine(docLine.toString()); list.add (docLine); } // Return Array DocLine[] dls = new DocLine[list.size()]; list.toArray(dls); return dls; } // loadLines /** * Get Balance * @return Zero (always balanced) */ @Override public BigDecimal getBalance() { BigDecimal retValue = Env.ZERO; return retValue; } // getBalance /** * Create Facts (the accounting logic) for * MMS, MMR. *
    	 *  Shipment
    	 *      CoGS (RevOrg)   DR
    	 *      Inventory               CR
    	 *  Shipment of Project Issue
    	 *      CoGS            DR
    	 *      Project                 CR
    	 *  Receipt
    	 *      Inventory       DR
    	 *      NotInvoicedReceipt      CR
    	 *  
    * @param as accounting schema * @return Fact */ @Override public ArrayList createFacts (MAcctSchema as) { // ArrayList facts = new ArrayList(); // create Fact Header Fact fact = new Fact(this, as, Fact.POST_Actual); setC_Currency_ID (as.getC_Currency_ID()); // Line pointers FactLine dr = null; FactLine cr = null; // *** Sales - Shipment if (getDocumentType().equals(DOCTYPE_MatShipment) && isSOTrx()) { for (int i = 0; i < p_lines.length; i++) { Map batchLotCostMap = null; DocLine_InOut line = (DocLine_InOut) p_lines[i]; MProduct product = line.getProduct(); BigDecimal costs = null; if (!isReversal(line)) { if (MAcctSchema.COSTINGLEVEL_BatchLot.equals(product.getCostingLevel(as)) ) { if (line.getM_AttributeSetInstance_ID() == 0 ) { MInOutLine ioLine = (MInOutLine) line.getPO(); MInOutLineMA mas[] = MInOutLineMA.get(getCtx(), ioLine.get_ID(), getTrxName()); if (mas != null && mas.length > 0 ) { batchLotCostMap = new HashMap<>(); costs = BigDecimal.ZERO; for (int j = 0; j < mas.length; j++) { MInOutLineMA ma = mas[j]; BigDecimal QtyMA = ma.getMovementQty(); ProductCost pc = line.getProductCost(); pc.setQty(QtyMA); pc.setM_M_AttributeSetInstance_ID(ma.getM_AttributeSetInstance_ID()); BigDecimal maCosts = line.getProductCosts(as, line.getAD_Org_ID(), true, "M_InOutLine_ID=?"); batchLotCostMap.put(ma.getM_InOutLineMA_UU(), maCosts); costs = costs.add(maCosts); } } } else { costs = line.getProductCosts(as, line.getAD_Org_ID(), true, "M_InOutLine_ID=?"); } } else { // MZ Goodwill // if Shipment CostDetail exist then get Cost from Cost Detail costs = line.getProductCosts(as, line.getAD_Org_ID(), true, "M_InOutLine_ID=?"); } // end MZ if (costs == null || costs.signum() == 0) // zero costs OK { if (product.isStocked()) { //ok if we have purchased zero cost item from vendor before int count = DB.getSQLValue(null, "SELECT Count(*) FROM M_CostDetail WHERE M_Product_ID=? AND Processed='Y' AND Amt=0.00 AND Qty > 0 AND (C_OrderLine_ID > 0 OR C_InvoiceLine_ID > 0)", product.getM_Product_ID()); if (count > 0) { costs = BigDecimal.ZERO; } else { p_Error = Msg.getMsg(getCtx(), "No Costs for") + " " + line.getProduct().getName(); log.log(Level.WARNING, p_Error); return null; } } else // ignore service continue; } } else { //temp to avoid NPE costs = BigDecimal.ZERO; } // CoGS DR dr = fact.createLine(line, line.getAccount(ProductCost.ACCTTYPE_P_Cogs, as), as.getC_Currency_ID(), costs, null); if (dr == null) { p_Error = Msg.getMsg(getCtx(),"FactLine DR not created:" + " ") + line; log.log(Level.WARNING, p_Error); return null; } dr.setM_Locator_ID(line.getM_Locator_ID()); dr.setLocationFromLocator(line.getM_Locator_ID(), true); // from Loc dr.setLocationFromBPartner(getC_BPartner_Location_ID(), false); // to Loc dr.setAD_Org_ID(line.getOrder_Org_ID()); // Revenue X-Org dr.setQty(line.getQty().negate()); if (isReversal(line)) { // Set AmtAcctDr from Original Shipment/Receipt if (!dr.updateReverseLine (MInOut.Table_ID, m_Reversal_ID, line.getReversalLine_ID(),Env.ONE)) { if (! product.isStocked()) { // ignore service fact.remove(dr); continue; } p_Error = Msg.getMsg(getCtx(),"Original Shipment/Receipt not posted yet"); return null; } } // Inventory CR cr = fact.createLine(line, line.getAccount(ProductCost.ACCTTYPE_P_Asset, as), as.getC_Currency_ID(), null, costs); if (cr == null) { p_Error = Msg.getMsg(getCtx(),"FactLine CR not created:") + " " + line; log.log(Level.WARNING, p_Error); return null; } cr.setM_Locator_ID(line.getM_Locator_ID()); cr.setLocationFromLocator(line.getM_Locator_ID(), true); // from Loc cr.setLocationFromBPartner(getC_BPartner_Location_ID(), false); // to Loc if (isReversal(line)) { // Set AmtAcctCr from Original Shipment/Receipt if (!cr.updateReverseLine (MInOut.Table_ID, m_Reversal_ID, line.getReversalLine_ID(),Env.ONE, dr)) { p_Error = Msg.getMsg(getCtx(),"Original Shipment/Receipt not posted yet"); return null; } costs = cr.getAcctBalance(); //get original cost } if (MAcctSchema.COSTINGLEVEL_BatchLot.equals(product.getCostingLevel(as)) ) { if (line.getM_AttributeSetInstance_ID() == 0 ) { MInOutLine ioLine = (MInOutLine) line.getPO(); MInOutLineMA mas[] = MInOutLineMA.get(getCtx(), ioLine.get_ID(), getTrxName()); if (mas != null && mas.length > 0 ) { for (int j = 0; j < mas.length; j++) { MInOutLineMA ma = mas[j]; BigDecimal qty = ma.getMovementQty(); if (qty.signum() != line.getQty().signum()) qty = qty.negate(); BigDecimal amt = batchLotCostMap != null ? batchLotCostMap.get(ma.getM_InOutLineMA_UU()) : null; if (amt == null && isReversal(line)) { amt = findReversalCostDetailAmt(as, line.getM_Product_ID(), ma, line.getReversalLine_ID()); if (amt != null) amt = amt.negate(); } if (amt == null) { amt = costs.divide(line.getProductCost().getQty(), RoundingMode.HALF_UP); amt = amt.multiply(qty); } else if (!isReversal(line) && line.getProductCost().getQty().signum() != line.getQty().signum()) { if (amt.signum() != (costs.signum() * -1)) { amt = amt.negate(); } } if (!MCostDetail.createShipment(as, line.getAD_Org_ID(), line.getM_Product_ID(), ma.getM_AttributeSetInstance_ID(), line.get_ID(), 0, amt, qty, line.getDescription(), true, getTrxName())) { p_Error = Msg.getMsg(getCtx(),"Failed to create cost detail record"); return null; } } } } else { // if (line.getM_Product_ID() != 0) { BigDecimal amt = costs; if (line.getProductCost().getQty().signum() != line.getQty().signum() && !isReversal(line)) amt = amt.negate(); if (!MCostDetail.createShipment(as, line.getAD_Org_ID(), line.getM_Product_ID(), line.getM_AttributeSetInstance_ID(), line.get_ID(), 0, amt, line.getQty(), line.getDescription(), true, getTrxName())) { p_Error = Msg.getMsg(getCtx(),"Failed to create cost detail record"); return null; } } } } else { // if (line.getM_Product_ID() != 0) { BigDecimal amt = costs; if (line.getProductCost().getQty().signum() != line.getQty().signum() && !isReversal(line)) amt = amt.negate(); if (!MCostDetail.createShipment(as, line.getAD_Org_ID(), line.getM_Product_ID(), line.getM_AttributeSetInstance_ID(), line.get_ID(), 0, amt, line.getQty(), line.getDescription(), true, getTrxName())) { p_Error = Msg.getMsg(getCtx(),"Failed to create cost detail record"); return null; } } } } // for all lines /** Commitment release ****/ if (as.isAccrual() && as.isCreateSOCommitment()) { for (int i = 0; i < p_lines.length; i++) { DocLine_InOut line = (DocLine_InOut) p_lines[i]; Fact factcomm = Doc_Order.getCommitmentSalesRelease(as, this, line.getQty(), line.get_ID(), Env.ONE); if (factcomm != null) facts.add(factcomm); } } // Commitment } // Shipment // *** Sales - Return else if ( getDocumentType().equals(DOCTYPE_MatReceipt) && isSOTrx() ) { for (int i = 0; i < p_lines.length; i++) { DocLine_InOut line = (DocLine_InOut) p_lines[i]; MProduct product = line.getProduct(); BigDecimal costs = null; Map batchLotCostMap = null; if (!isReversal(line)) { if (MAcctSchema.COSTINGLEVEL_BatchLot.equals(product.getCostingLevel(as)) ) { if (line.getM_AttributeSetInstance_ID() == 0 ) { MInOutLine ioLine = (MInOutLine) line.getPO(); MInOutLineMA mas[] = MInOutLineMA.get(getCtx(), ioLine.get_ID(), getTrxName()); costs = BigDecimal.ZERO; if (mas != null && mas.length > 0 ) { batchLotCostMap = new HashMap<>(); for (int j = 0; j < mas.length; j++) { MInOutLineMA ma = mas[j]; BigDecimal QtyMA = ma.getMovementQty(); ProductCost pc = line.getProductCost(); pc.setQty(QtyMA); pc.setM_M_AttributeSetInstance_ID(ma.getM_AttributeSetInstance_ID()); BigDecimal maCosts = line.getProductCosts(as, line.getAD_Org_ID(), true, "M_InOutLine_ID=?"); batchLotCostMap.put(ma.getM_InOutLineMA_UU(), maCosts); costs = costs.add(maCosts); } } } else { costs = line.getProductCosts(as, line.getAD_Org_ID(), true, "M_InOutLine_ID=?"); } } else { // MZ Goodwill // if Shipment CostDetail exist then get Cost from Cost Detail costs = line.getProductCosts(as, line.getAD_Org_ID(), true, "M_InOutLine_ID=?"); // end MZ } if (costs == null || costs.signum() == 0) // zero costs OK { if (product.isStocked()) { p_Error = Msg.getMsg(getCtx(),"No Costs for") + " " + line.getProduct().getName(); log.log(Level.WARNING, p_Error); return null; } else // ignore service continue; } } else { costs = BigDecimal.ZERO; } // Inventory DR dr = fact.createLine(line, line.getAccount(ProductCost.ACCTTYPE_P_Asset, as), as.getC_Currency_ID(), costs, null); if (dr == null) { p_Error = Msg.getMsg(getCtx(),"FactLine DR not created:" + " ") + line; log.log(Level.WARNING, p_Error); return null; } dr.setM_Locator_ID(line.getM_Locator_ID()); dr.setLocationFromLocator(line.getM_Locator_ID(), true); // from Loc dr.setLocationFromBPartner(getC_BPartner_Location_ID(), false); // to Loc if (isReversal(line)) { // Set AmtAcctDr from Original Shipment/Receipt if (!dr.updateReverseLine (MInOut.Table_ID, m_Reversal_ID, line.getReversalLine_ID(),Env.ONE)) { if (! product.isStocked()) { // ignore service fact.remove(dr); continue; } p_Error = Msg.getMsg(getCtx(),"Original Shipment/Receipt not posted yet"); return null; } costs = dr.getAcctBalance(); //get original cost } // if (MAcctSchema.COSTINGLEVEL_BatchLot.equals(product.getCostingLevel(as)) ) { if (line.getM_AttributeSetInstance_ID() == 0 ) { MInOutLine ioLine = (MInOutLine) line.getPO(); MInOutLineMA mas[] = MInOutLineMA.get(getCtx(), ioLine.get_ID(), getTrxName()); if (mas != null && mas.length > 0 ) { for (int j = 0; j < mas.length; j++) { MInOutLineMA ma = mas[j]; BigDecimal qty = ma.getMovementQty(); if (qty.signum() != line.getQty().signum()) qty = qty.negate(); BigDecimal amt = batchLotCostMap != null ? batchLotCostMap.get(ma.getM_InOutLineMA_UU()) : null; if (amt == null && isReversal(line)) { amt = findReversalCostDetailAmt(as, line.getM_Product_ID(), ma, line.getReversalLine_ID()); if (amt != null) amt = amt.negate(); } if (amt == null) { amt = costs.divide(line.getProductCost().getQty(), RoundingMode.HALF_UP); amt = amt.multiply(qty); } else if (!isReversal(line) && line.getProductCost().getQty().signum() != line.getQty().signum()) { if (amt.signum() != (costs.signum() * -1)) { amt = amt.negate(); } } if (!MCostDetail.createShipment(as, line.getAD_Org_ID(), line.getM_Product_ID(), ma.getM_AttributeSetInstance_ID(), line.get_ID(), 0, amt, qty, line.getDescription(), true, getTrxName())) { p_Error = Msg.getMsg(getCtx(),"Failed to create cost detail record"); return null; } } } } else { if (line.getM_Product_ID() != 0) { BigDecimal amt = costs; if (line.getProductCost().getQty().signum() != line.getQty().signum() && !isReversal(line)) amt = amt.negate(); if (!MCostDetail.createShipment(as, line.getAD_Org_ID(), line.getM_Product_ID(), line.getM_AttributeSetInstance_ID(), line.get_ID(), 0, amt, line.getQty(), line.getDescription(), true, getTrxName())) { p_Error = Msg.getMsg(getCtx(),"Failed to create cost detail record"); return null; } } } } else { // if (line.getM_Product_ID() != 0) { BigDecimal amt = costs; if (line.getProductCost().getQty().signum() != line.getQty().signum() && !isReversal(line)) amt = amt.negate(); if (!MCostDetail.createShipment(as, line.getAD_Org_ID(), line.getM_Product_ID(), line.getM_AttributeSetInstance_ID(), line.get_ID(), 0, amt, line.getQty(), line.getDescription(), true, getTrxName())) { p_Error = Msg.getMsg(getCtx(),"Failed to create cost detail record"); return null; } } } // CoGS CR cr = fact.createLine(line, line.getAccount(ProductCost.ACCTTYPE_P_Cogs, as), as.getC_Currency_ID(), null, costs); if (cr == null) { p_Error = Msg.getMsg(getCtx(),"FactLine CR not created:") + " " + line; log.log(Level.WARNING, p_Error); return null; } cr.setM_Locator_ID(line.getM_Locator_ID()); cr.setLocationFromLocator(line.getM_Locator_ID(), true); // from Loc cr.setLocationFromBPartner(getC_BPartner_Location_ID(), false); // to Loc cr.setAD_Org_ID(line.getOrder_Org_ID()); // Revenue X-Org cr.setQty(line.getQty().negate()); if (isReversal(line)) { // Set AmtAcctCr from Original Shipment/Receipt if (!cr.updateReverseLine (MInOut.Table_ID, m_Reversal_ID, line.getReversalLine_ID(),Env.ONE, dr)) { p_Error = Msg.getMsg(getCtx(),"Original Shipment/Receipt not posted yet"); return null; } } } // for all lines } // Sales Return // *** Purchasing - Receipt else if (getDocumentType().equals(DOCTYPE_MatReceipt) && !isSOTrx()) { for (int i = 0; i < p_lines.length; i++) { // Elaine 2008/06/26 int C_Currency_ID = as.getC_Currency_ID(); // DocLine_InOut line = (DocLine_InOut) p_lines[i]; BigDecimal costs = null; MProduct product = line.getProduct(); MOrderLine orderLine = null; BigDecimal landedCost = BigDecimal.ZERO; String costingMethod = product.getCostingMethod(as); if (!isReversal(line)) { int C_OrderLine_ID = line.getC_OrderLine_ID(); if (C_OrderLine_ID > 0) { orderLine = new MOrderLine (getCtx(), C_OrderLine_ID, getTrxName()); MOrderLandedCostAllocation[] allocations = MOrderLandedCostAllocation.getOfOrderLine(C_OrderLine_ID, getTrxName()); for(MOrderLandedCostAllocation allocation : allocations) { BigDecimal totalAmt = allocation.getAmt(); BigDecimal totalQty = allocation.getQty(); BigDecimal amt = totalAmt.multiply(line.getQty()).divide(totalQty, RoundingMode.HALF_UP); landedCost = landedCost.add(amt); } } //get costing method for product if (MAcctSchema.COSTINGMETHOD_AveragePO.equals(costingMethod) || MAcctSchema.COSTINGMETHOD_AverageInvoice.equals(costingMethod) || MAcctSchema.COSTINGMETHOD_LastPOPrice.equals(costingMethod) || ( MAcctSchema.COSTINGMETHOD_StandardCosting.equals(costingMethod) && MAcctSchema.COSTINGLEVEL_BatchLot.equals(product.getCostingLevel(as)))) { // Low - check if c_orderline_id is valid if (orderLine != null) { C_Currency_ID = orderLine.getC_Currency_ID(); // costs = orderLine.getPriceCost(); if (costs == null || costs.signum() == 0) { costs = orderLine.getPriceActual(); // Goodwill: Correct included Tax int C_Tax_ID = orderLine.getC_Tax_ID(); if (orderLine.isTaxIncluded() && C_Tax_ID != 0) { MTax tax = MTax.get(getCtx(), C_Tax_ID); if (!tax.isZeroTax()) { int stdPrecision = MCurrency.getStdPrecision(getCtx(), C_Currency_ID); BigDecimal costTax = tax.calculateTax(costs, true, stdPrecision); if (log.isLoggable(Level.FINE)) log.fine("Costs=" + costs + " - Tax=" + costTax); if(tax.isSummary()) { MTax[] cTaxes = tax.getChildTaxes(false); List toSubtract = new ArrayList<>(); for(MTax cTax : cTaxes) { if (!cTax.isDistributeTaxWithLineItem()) toSubtract.add(cTax); } if (toSubtract.size() > 0) { BigDecimal base = costs.subtract(costTax); for(MTax cTax : toSubtract) { BigDecimal ts = cTax.calculateTax(base, false, stdPrecision); costs = costs.subtract(ts); } } } else if (!tax.isDistributeTaxWithLineItem()) { costs = costs.subtract(costTax); } } } // correct included Tax else if (C_Tax_ID != 0) { MTax tax = MTax.get(getCtx(), C_Tax_ID); if(tax.isSummary()) { MTax[] cTaxes = tax.getChildTaxes(false); BigDecimal base = costs; for(MTax cTax : cTaxes) { if (cTax.isDistributeTaxWithLineItem()) { //do not round to stdprecision before multiply qty BigDecimal costTax = cTax.calculateTax(base, false, 12); if (log.isLoggable(Level.FINE)) log.fine("Costs=" + base + " - Tax=" + costTax); costs = costs.add(costTax); } } } else if (tax.isDistributeTaxWithLineItem()) { //do not round to stdprecision before multiply qty BigDecimal costTax = tax.calculateTax(costs, false, 12); if (log.isLoggable(Level.FINE)) log.fine("Costs=" + costs + " - Tax=" + costTax); costs = costs.add(costTax); } } } costs = costs.multiply(line.getQty()); } else { p_Error = Msg.getMsg(getCtx(),"Resubmit - No Costs for") + " " + product.getName() + Msg.getMsg(getCtx()," (required order line)"); log.log(Level.WARNING, p_Error); return null; } // } else { costs = line.getProductCosts(as, line.getAD_Org_ID(), false); // current costs } if (costs == null || costs.signum() == 0) { //ok if purchase price is actually zero if (orderLine != null && orderLine.getPriceActual().signum() == 0) { costs = BigDecimal.ZERO; } else { p_Error = Msg.getMsg(getCtx(),"Resubmit - No Costs for") + " " + product.getName(); log.log(Level.WARNING, p_Error); return null; } } } else { costs = BigDecimal.ZERO; } // Inventory/Asset DR MAccount assets = line.getAccount(ProductCost.ACCTTYPE_P_Asset, as); if (product.isService()) { //if the line is a Outside Processing then DR WIP if(line.getPP_Cost_Collector_ID() > 0) assets = line.getAccount(ProductCost.ACCTTYPE_P_WorkInProcess, as); else assets = line.getAccount(ProductCost.ACCTTYPE_P_Expense, as); } BigDecimal drAsset = costs; if (landedCost.signum() != 0 && (MAcctSchema.COSTINGMETHOD_AverageInvoice.equals(costingMethod) || MAcctSchema.COSTINGMETHOD_AveragePO.equals(costingMethod))) { drAsset = drAsset.add(landedCost); } dr = fact.createLine(line, assets, C_Currency_ID, drAsset, null); // if (dr == null) { p_Error = Msg.getMsg(getCtx(),"DR not created:") + " " + line; log.log(Level.WARNING, p_Error); return null; } dr.setM_Locator_ID(line.getM_Locator_ID()); dr.setLocationFromBPartner(getC_BPartner_Location_ID(), true); // from Loc dr.setLocationFromLocator(line.getM_Locator_ID(), false); // to Loc if (isReversal(line)) { // Set AmtAcctDr from Original Shipment/Receipt if (!dr.updateReverseLine (MInOut.Table_ID, m_Reversal_ID, line.getReversalLine_ID(),Env.ONE)) { if (! product.isStocked()) { // ignore service fact.remove(dr); continue; } p_Error = Msg.getMsg(getCtx(),"Original Receipt not posted yet"); return null; } } // NotInvoicedReceipt CR cr = fact.createLine(line, getAccount(Doc.ACCTTYPE_NotInvoicedReceipts, as), C_Currency_ID, null, costs); // if (cr == null) { p_Error = Msg.getMsg(getCtx(),"CR not created:") + " " + line; log.log(Level.WARNING, p_Error); return null; } cr.setM_Locator_ID(line.getM_Locator_ID()); cr.setLocationFromBPartner(getC_BPartner_Location_ID(), true); // from Loc cr.setLocationFromLocator(line.getM_Locator_ID(), false); // to Loc cr.setQty(line.getQty().negate()); if (isReversal(line)) { // Set AmtAcctCr from Original Shipment/Receipt if (!cr.updateReverseLine (MInOut.Table_ID, m_Reversal_ID, line.getReversalLine_ID(),Env.ONE, dr)) { p_Error = Msg.getMsg(getCtx(),"Original Receipt not posted yet"); return null; } } if (!fact.isAcctBalanced()) { if (isReversal(line)) { dr = fact.createLine(line, line.getAccount(ProductCost.ACCTTYPE_P_LandedCostClearing, as), C_Currency_ID, Env.ONE, (BigDecimal)null); if (!dr.updateReverseLine (MInOut.Table_ID, m_Reversal_ID, line.getReversalLine_ID(),Env.ONE)) { p_Error = Msg.getMsg(getCtx(),"Original Receipt not posted yet"); return null; } } else if (landedCost.signum() != 0) { cr = fact.createLine(line, line.getAccount(ProductCost.ACCTTYPE_P_LandedCostClearing, as), C_Currency_ID, null, landedCost); // if (cr == null) { p_Error = Msg.getMsg(getCtx(),"CR not created:") + " " + line; log.log(Level.WARNING, p_Error); return null; } cr.setM_Locator_ID(line.getM_Locator_ID()); cr.setLocationFromBPartner(getC_BPartner_Location_ID(), true); // from Loc cr.setLocationFromLocator(line.getM_Locator_ID(), false); // to Loc cr.setQty(line.getQty().negate()); } } } } // Receipt // *** Purchasing - return else if (getDocumentType().equals(DOCTYPE_MatShipment) && !isSOTrx()) { for (int i = 0; i < p_lines.length; i++) { int C_Currency_ID = as.getC_Currency_ID(); // DocLine_InOut line = (DocLine_InOut) p_lines[i]; BigDecimal costs = null; MProduct product = line.getProduct(); if (!isReversal(line)) { MInOutLine ioLine = (MInOutLine) line.getPO(); I_M_RMALine rmaLine = ioLine.getM_RMALine(); costs = rmaLine != null ? rmaLine.getAmt() : BigDecimal.ZERO; I_M_InOutLine originalInOutLine = rmaLine != null ? rmaLine.getM_InOutLine() : null; if (originalInOutLine != null && originalInOutLine.getC_OrderLine_ID() > 0) { MOrderLine originalOrderLine = (MOrderLine) originalInOutLine.getC_OrderLine(); // Goodwill: Correct included Tax int C_Tax_ID = originalOrderLine.getC_Tax_ID(); MTax tax = MTax.get(getCtx(), C_Tax_ID); int stdPrecision = MCurrency.getStdPrecision(getCtx(), originalOrderLine.getC_Currency_ID()); if (originalOrderLine.isTaxIncluded() && C_Tax_ID != 0) { BigDecimal costTax = tax.calculateTax(costs, true, stdPrecision); if (log.isLoggable(Level.FINE)) log.fine("Costs=" + costs + " - Tax=" + costTax); if (tax.isSummary()) { costs = costs.subtract(costTax); BigDecimal base = costs; for(MTax cTax : tax.getChildTaxes(false)) { if (!cTax.isZeroTax() && cTax.isDistributeTaxWithLineItem()) { costTax = cTax.calculateTax(base, false, stdPrecision); costs = costs.add(costTax); } } } else if (!tax.isZeroTax() && !tax.isDistributeTaxWithLineItem()) { costs = costs.subtract(costTax); } } // correct included Tax else { if (tax.isSummary()) { BigDecimal base = costs; for(MTax cTax : tax.getChildTaxes(false)) { if (!cTax.isZeroTax() && cTax.isDistributeTaxWithLineItem()) { BigDecimal costTax = cTax.calculateTax(base, false, stdPrecision); costs = costs.add(costTax); } } } else if (tax.isDistributeTaxWithLineItem()) { BigDecimal costTax = tax.calculateTax(costs, false, stdPrecision); costs = costs.add(costTax); } } // different currency if (C_Currency_ID != originalOrderLine.getC_Currency_ID()) { costs = MConversionRate.convert (getCtx(), costs, originalOrderLine.getC_Currency_ID(), C_Currency_ID, getDateAcct(), line.getC_ConversionType_ID(), getAD_Client_ID(), getAD_Org_ID(), true); } costs = costs.multiply(line.getQty()); costs = costs.negate(); } else { if (MAcctSchema.COSTINGLEVEL_BatchLot.equals(product.getCostingLevel(as)) ) { if (line.getM_AttributeSetInstance_ID() == 0 ) { MInOutLineMA mas[] = MInOutLineMA.get(getCtx(), ioLine.get_ID(), getTrxName()); costs = BigDecimal.ZERO; if (mas != null && mas.length > 0 ) { for (int j = 0; j < mas.length; j++) { MInOutLineMA ma = mas[j]; BigDecimal QtyMA = ma.getMovementQty(); ProductCost pc = line.getProductCost(); pc.setQty(QtyMA); pc.setM_M_AttributeSetInstance_ID(ma.getM_AttributeSetInstance_ID()); BigDecimal maCosts = line.getProductCosts(as, line.getAD_Org_ID(), true, "M_InOutLine_ID=?"); costs = costs.add(maCosts); } } } else { costs = line.getProductCosts(as, line.getAD_Org_ID(), false); // current costs } } else { costs = line.getProductCosts(as, line.getAD_Org_ID(), false); // current costs } if (costs == null || costs.signum() == 0) { p_Error = Msg.getMsg(getCtx(),"Resubmit - No Costs for") + " " + product.getName(); log.log(Level.WARNING, p_Error); return null; } } } else { //update below costs = Env.ONE; } dr = fact.createLine(line, getAccount(Doc.ACCTTYPE_NotInvoicedReceipts, as), C_Currency_ID, costs , null); // if (dr == null) { p_Error = Msg.getMsg(getCtx(),"CR not created:")+ " " + line; log.log(Level.WARNING, p_Error); return null; } dr.setM_Locator_ID(line.getM_Locator_ID()); dr.setLocationFromBPartner(getC_BPartner_Location_ID(), true); // from Loc dr.setLocationFromLocator(line.getM_Locator_ID(), false); // to Loc dr.setQty(line.getQty().negate()); if (isReversal(line)) { // Set AmtAcctDr from Original Shipment/Receipt if (!dr.updateReverseLine (MInOut.Table_ID, m_Reversal_ID, line.getReversalLine_ID(),Env.ONE)) { if (! product.isStocked()) { // ignore service fact.remove(dr); continue; } p_Error = Msg.getMsg(getCtx(),"Original Receipt not posted yet"); return null; } } // Inventory/Asset CR MAccount assets = line.getAccount(ProductCost.ACCTTYPE_P_Asset, as); if (product.isService()) assets = line.getAccount(ProductCost.ACCTTYPE_P_Expense, as); cr = fact.createLine(line, assets, C_Currency_ID, null, costs); // if (cr == null) { p_Error = Msg.getMsg(getCtx(),"DR not created:") + " " + line; log.log(Level.WARNING, p_Error); return null; } cr.setM_Locator_ID(line.getM_Locator_ID()); cr.setLocationFromBPartner(getC_BPartner_Location_ID(), true); // from Loc cr.setLocationFromLocator(line.getM_Locator_ID(), false); // to Loc if (isReversal(line)) { // Set AmtAcctCr from Original Shipment/Receipt if (!cr.updateReverseLine (MInOut.Table_ID, m_Reversal_ID, line.getReversalLine_ID(),Env.ONE, dr)) { p_Error = Msg.getMsg(getCtx(),"Original Receipt not posted yet"); return null; } } String costingError = createVendorRMACostDetail(as, line, costs); if (!Util.isEmpty(costingError)) { p_Error = costingError; return null; } } } // Purchasing Return else { p_Error = Msg.getMsg(getCtx(),"DocumentType unknown:") + " " + getDocumentType(); log.log(Level.SEVERE, p_Error); return null; } // facts.add(fact); return facts; } // createFact /** * @param as * @param M_Product_ID * @param ma * @param reversalLine_ID * @return MCostDetail.Amt */ private BigDecimal findReversalCostDetailAmt(MAcctSchema as, int M_Product_ID, MInOutLineMA ma, int reversalLine_ID) { StringBuilder select = new StringBuilder("SELECT ").append(MCostDetail.COLUMNNAME_Amt) .append(" FROM ").append(MCostDetail.Table_Name).append(" WHERE ") .append(MCostDetail.COLUMNNAME_C_AcctSchema_ID).append("=? ") .append("AND ").append(MCostDetail.COLUMNNAME_M_AttributeSetInstance_ID).append("=? ") .append("AND ").append(MCostDetail.COLUMNNAME_M_InOutLine_ID).append("=? ") .append("AND ").append(MCostDetail.COLUMNNAME_M_Product_ID).append("=? "); BigDecimal amt = DB.getSQLValueBDEx(getTrxName(), select.toString(), as.getC_AcctSchema_ID(), ma.getM_AttributeSetInstance_ID(), reversalLine_ID, M_Product_ID); return amt; } /** * @param line * @return true if line is for reversal */ private boolean isReversal(DocLine line) { return m_Reversal_ID !=0 && line.getReversalLine_ID() != 0; } /** * Create cost detail record from purchase return * @param as * @param line * @param costs * @return error message or empty string */ private String createVendorRMACostDetail(MAcctSchema as, DocLine line, BigDecimal costs) { BigDecimal tQty = line.getQty(); BigDecimal tAmt = costs; if (tAmt.signum() != tQty.signum()) { tAmt = tAmt.negate(); } MProduct product = line.getProduct(); if (MAcctSchema.COSTINGLEVEL_BatchLot.equals(product.getCostingLevel(as)) ) { if (line.getM_AttributeSetInstance_ID() == 0 ) { MInOutLineMA mas[] = MInOutLineMA.get(getCtx(), line.get_ID(), getTrxName()); if (mas != null && mas.length > 0 ) { for (int j = 0; j < mas.length; j++) { MInOutLineMA ma = mas[j]; if (!MCostDetail.createShipment(as, line.getAD_Org_ID(), line.getM_Product_ID(), ma.getM_AttributeSetInstance_ID(), line.get_ID(), 0, tAmt, ma.getMovementQty().negate(), line.getDescription(), false, getTrxName())) return "SaveError"; } } } else { if (!MCostDetail.createShipment(as, line.getAD_Org_ID(), line.getM_Product_ID(), line.getM_AttributeSetInstance_ID(), line.get_ID(), 0, tAmt, tQty, line.getDescription(), false, getTrxName())) return "SaveError"; } } else { if (!MCostDetail.createShipment(as, line.getAD_Org_ID(), line.getM_Product_ID(), line.getM_AttributeSetInstance_ID(), line.get_ID(), 0, tAmt, tQty, line.getDescription(), false, getTrxName())) return "SaveError"; } return ""; } @Override public boolean isDeferPosting() { return m_deferPosting; } @Override public int getC_Currency_ID() { MInOut io = (MInOut) getPO(); if (io.getC_Order_ID() > 0) return io.getC_Order().getC_Currency_ID(); else if (io.getM_RMA_ID() > 0) { if (io.getM_RMA().getInOut_ID() > 0) { if (io.getM_RMA().getInOut().getC_Order_ID() > 0) return io.getM_RMA().getInOut().getC_Order().getC_Currency_ID(); } } return super.getC_Currency_ID(); } @Override public int getC_ConversionType_ID() { MInOut io = (MInOut) getPO(); if (io.getC_Order_ID() > 0) return io.getC_Order().getC_ConversionType_ID(); else if (io.getM_RMA_ID() > 0) { if (io.getM_RMA().getInOut_ID() > 0) { if (io.getM_RMA().getInOut().getC_Order_ID() > 0) return io.getM_RMA().getInOut().getC_Order().getC_ConversionType_ID(); } } return super.getC_ConversionType_ID(); } } // Doc_InOut