/****************************************************************************** * 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.model; import java.math.BigDecimal; import java.math.RoundingMode; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.Properties; import java.util.logging.Level; import java.util.regex.Pattern; import org.adempiere.base.Core; import org.adempiere.base.IProductPricing; import org.adempiere.exceptions.AdempiereException; import org.adempiere.exceptions.ProductNotOnPriceListException; import org.adempiere.model.ITaxProvider; import org.compiere.process.DocAction; import org.compiere.util.CLogger; import org.compiere.util.DB; import org.compiere.util.Env; import org.compiere.util.Msg; import org.compiere.util.Util; /** * Order Line Model. *
 * 		MOrderLine ol = new MOrderLine(m_order);
		ol.setM_Product_ID(wbl.getM_Product_ID());
		ol.setQtyOrdered(wbl.getQuantity());
		ol.setPrice();
		ol.setPriceActual(wbl.getPrice());
		ol.setTax();
		ol.saveEx();
 *	
* @author Jorg Janke * @version $Id: MOrderLine.java,v 1.6 2006/10/02 05:18:39 jjanke Exp $ * * @author Teo Sarca, SC ARHIPAC SERVICE SRL *
  • BF [ 2588043 ] Insufficient message ProductNotOnPriceList */ public class MOrderLine extends X_C_OrderLine { /** * generated serial id */ private static final long serialVersionUID = 7994694334621222461L; /** * Get Order Qty that have not been reserved * @param ctx context * @param M_Warehouse_ID wh * @param M_Product_ID product * @param M_AttributeSetInstance_ID asi * @param excludeC_OrderLine_ID exclude C_OrderLine_ID * @return Order Qty that have not been reserved */ public static BigDecimal getNotReserved (Properties ctx, int M_Warehouse_ID, int M_Product_ID, int M_AttributeSetInstance_ID, int excludeC_OrderLine_ID) { BigDecimal retValue = Env.ZERO; String sql = "SELECT SUM(QtyOrdered-QtyDelivered-QtyReserved) " + "FROM C_OrderLine ol" + " INNER JOIN C_Order o ON (ol.C_Order_ID=o.C_Order_ID) " + "WHERE ol.M_Warehouse_ID=?" // #1 + " AND M_Product_ID=?" // #2 + " AND o.IsSOTrx='Y' AND o.DocStatus='DR'" + " AND QtyOrdered-QtyDelivered-QtyReserved<>0" + " AND ol.C_OrderLine_ID<>?"; if (M_AttributeSetInstance_ID != 0) sql += " AND M_AttributeSetInstance_ID=?"; PreparedStatement pstmt = null; ResultSet rs = null; try { pstmt = DB.prepareStatement (sql, null); pstmt.setInt (1, M_Warehouse_ID); pstmt.setInt (2, M_Product_ID); pstmt.setInt (3, excludeC_OrderLine_ID); if (M_AttributeSetInstance_ID != 0) pstmt.setInt (4, M_AttributeSetInstance_ID); rs = pstmt.executeQuery (); if (rs.next ()) retValue = rs.getBigDecimal(1); } catch (Exception e) { s_log.log (Level.SEVERE, sql, e); } finally { DB.close(rs, pstmt); rs = null; pstmt = null; } if (retValue == null) s_log.fine("-"); else if (s_log.isLoggable(Level.FINE)) s_log.fine(retValue.toString()); return retValue; } // getNotReserved /** Logger */ protected static CLogger s_log = CLogger.getCLogger (MOrderLine.class); /** * UUID based Constructor * @param ctx Context * @param C_OrderLine_UU UUID key * @param trxName Transaction */ public MOrderLine(Properties ctx, String C_OrderLine_UU, String trxName) { super(ctx, C_OrderLine_UU, trxName); if (Util.isEmpty(C_OrderLine_UU)) setInitialDefaults(); } /** * Default Constructor * @param ctx context * @param C_OrderLine_ID order line to load * @param trxName trx name */ public MOrderLine (Properties ctx, int C_OrderLine_ID, String trxName) { this (ctx, C_OrderLine_ID, trxName, (String[]) null); } // MOrderLine /** * @param ctx * @param C_OrderLine_ID * @param trxName * @param virtualColumns */ public MOrderLine(Properties ctx, int C_OrderLine_ID, String trxName, String... virtualColumns) { super(ctx, C_OrderLine_ID, trxName, virtualColumns); if (C_OrderLine_ID == 0) setInitialDefaults(); } /** * Set the initial defaults for a new record */ private void setInitialDefaults() { setFreightAmt (Env.ZERO); setLineNetAmt (Env.ZERO); // setPriceEntered(Env.ZERO); setPriceActual (Env.ZERO); setPriceLimit (Env.ZERO); setPriceList (Env.ZERO); // setM_AttributeSetInstance_ID(0); // setQtyEntered (Env.ZERO); setQtyOrdered (Env.ZERO); // 1 setQtyDelivered (Env.ZERO); setQtyInvoiced (Env.ZERO); setQtyReserved (Env.ZERO); // setIsDescription (false); // N setProcessed (false); setLine (0); } /** * Parent Constructor. * @param order parent order */ public MOrderLine (MOrder order) { this (order.getCtx(), 0, order.get_TrxName()); if (order.get_ID() == 0) throw new IllegalArgumentException("Header not saved"); setC_Order_ID (order.getC_Order_ID()); // parent setOrder(order); } // MOrderLine /** * Load Constructor * @param ctx context * @param rs result set record * @param trxName transaction */ public MOrderLine (Properties ctx, ResultSet rs, String trxName) { super(ctx, rs, trxName); } // MOrderLine protected int m_M_PriceList_ID = 0; // protected boolean m_IsSOTrx = true; // Product Pricing protected IProductPricing m_productPrice = null; /** Tax */ protected MTax m_tax = null; /** Cached Currency Precision */ protected Integer m_precision = null; /** Product */ protected MProduct m_product = null; /** Charge */ protected MCharge m_charge = null; /** Parent */ protected MOrder m_parent = null; /** * Set Defaults from Order. * @param order order */ public void setOrder (MOrder order) { setClientOrg(order); setC_BPartner_ID(order.getC_BPartner_ID()); setC_BPartner_Location_ID(order.getC_BPartner_Location_ID()); setM_Warehouse_ID(order.getM_Warehouse_ID()); setDateOrdered(order.getDateOrdered()); setDatePromised(order.getDatePromised()); setC_Currency_ID(order.getC_Currency_ID()); // setHeaderInfo(order); // sets m_order // Don't set Activity, etc as they are overwrites } // setOrder /** * Set Header Info * @param order order */ public void setHeaderInfo (MOrder order) { m_parent = order; m_precision = Integer.valueOf(order.getPrecision()); m_M_PriceList_ID = order.getM_PriceList_ID(); m_IsSOTrx = order.isSOTrx(); } // setHeaderInfo /** * Get Parent * @return parent */ public MOrder getParent() { if (m_parent == null) m_parent = new MOrder(getCtx(), getC_Order_ID(), get_TrxName()); return m_parent; } // getParent /** * Set Price Entered/Actual. * Use this Method if the Line UOM is the Product UOM. * @param PriceActual price */ public void setPrice (BigDecimal PriceActual) { setPriceEntered(PriceActual); setPriceActual (PriceActual); } // setPrice /** * Set Price Actual. * (actual price is not updateable) * @param PriceActual actual price */ public void setPriceActual (BigDecimal PriceActual) { if (PriceActual == null) throw new IllegalArgumentException ("PriceActual is mandatory"); set_ValueNoCheck("PriceActual", PriceActual); } // setPriceActual /** * Set Price for Product and PriceList. */ public void setPrice() { if (getM_Product_ID() == 0) return; if (m_M_PriceList_ID == 0) throw new IllegalStateException("PriceList unknown!"); setPrice (m_M_PriceList_ID); } // setPrice /** * Set Price for Product and PriceList * @param M_PriceList_ID price list */ public void setPrice (int M_PriceList_ID) { if (getM_Product_ID() == 0) return; // if (log.isLoggable(Level.FINE)) log.fine(toString() + " - M_PriceList_ID=" + M_PriceList_ID); getProductPricing (M_PriceList_ID); setPriceActual (m_productPrice.getPriceStd()); setPriceList (m_productPrice.getPriceList()); setPriceLimit (m_productPrice.getPriceLimit()); // if (getQtyEntered().compareTo(getQtyOrdered()) == 0) setPriceEntered(getPriceActual()); else setPriceEntered(getPriceActual().multiply(getQtyOrdered() .divide(getQtyEntered(), 12, RoundingMode.HALF_UP))); // precision // Calculate Discount setDiscount(m_productPrice.getDiscount()); // Set UOM if (getC_UOM_ID()==0) setC_UOM_ID(m_productPrice.getC_UOM_ID()); } // setPrice /** * Get and calculate Product Pricing * @param M_PriceList_ID id * @return product pricing */ protected IProductPricing getProductPricing (int M_PriceList_ID) { m_productPrice = Core.getProductPricing(); m_productPrice.setOrderLine(this, get_TrxName()); m_productPrice.setM_PriceList_ID(M_PriceList_ID); // m_productPrice.calculatePrice(); return m_productPrice; } // getProductPricing /** * Set Tax * @return true if tax is set */ public boolean setTax() { int ii = Core.getTaxLookup().get(getCtx(), getM_Product_ID(), getC_Charge_ID(), getDateOrdered(), getDateOrdered(), getAD_Org_ID(), getM_Warehouse_ID(), getC_BPartner_Location_ID(), // should be bill to getC_BPartner_Location_ID(), getParent().getDropShip_Location_ID(), m_IsSOTrx, getParent().getDeliveryViaRule(), get_TrxName()); if (ii == 0) { log.log(Level.SEVERE, "No Tax found"); return false; } setC_Tax_ID (ii); return true; } // setTax /** * Calculate Extended Amt. * May or may not include tax. */ public void setLineNetAmt () { BigDecimal bd = getPriceEntered().multiply(getQtyEntered()); int precision = getPrecision(); if (bd.scale() > precision) bd = bd.setScale(precision, RoundingMode.HALF_UP); super.setLineNetAmt (bd); } // setLineNetAmt /** * Get Charge * @return charge or null */ public MCharge getCharge() { if (m_charge == null && getC_Charge_ID() != 0) m_charge = MCharge.getCopy(getCtx(), getC_Charge_ID(), get_TrxName()); return m_charge; } /** * Get Tax (immutable) * @return tax */ protected MTax getTax() { if (m_tax == null) m_tax = MTax.get(getCtx(), getC_Tax_ID()); return m_tax; } // getTax /** * Get Currency Precision from Currency * @return precision */ public int getPrecision() { if (m_precision != null) return m_precision.intValue(); // if (getC_Currency_ID() == 0) { setOrder (getParent()); if (m_precision != null) return m_precision.intValue(); } if (getC_Currency_ID() != 0) { MCurrency cur = MCurrency.get(getCtx(), getC_Currency_ID()); if (cur.get_ID() != 0) { m_precision = Integer.valueOf(cur.getStdPrecision()); return m_precision.intValue(); } } // Fallback String sql = "SELECT c.StdPrecision " + "FROM C_Currency c INNER JOIN C_Order x ON (x.C_Currency_ID=c.C_Currency_ID) " + "WHERE x.C_Order_ID=?"; int i = DB.getSQLValue(get_TrxName(), sql, getC_Order_ID()); m_precision = Integer.valueOf(i); return m_precision.intValue(); } // getPrecision /** * Set Product * @param product product */ public void setProduct (MProduct product) { m_product = product; if (m_product != null) { setM_Product_ID(m_product.getM_Product_ID()); setC_UOM_ID (m_product.getC_UOM_ID()); } else { setM_Product_ID(0); set_ValueNoCheck ("C_UOM_ID", null); } setM_AttributeSetInstance_ID(0); } // setProduct /** * Set M_Product_ID * @param M_Product_ID product * @param setUOM true to set also UOM */ public void setM_Product_ID (int M_Product_ID, boolean setUOM) { if (setUOM) setProduct(MProduct.get(getCtx(), M_Product_ID)); else super.setM_Product_ID (M_Product_ID); setM_AttributeSetInstance_ID(0); } // setM_Product_ID /** * Set Product and UOM * @param M_Product_ID product * @param C_UOM_ID uom */ public void setM_Product_ID (int M_Product_ID, int C_UOM_ID) { super.setM_Product_ID (M_Product_ID); if (C_UOM_ID != 0) super.setC_UOM_ID(C_UOM_ID); setM_AttributeSetInstance_ID(0); } // setM_Product_ID /** * Get Product * @return product or null */ public MProduct getProduct() { if (m_product == null && getM_Product_ID() != 0) m_product = MProduct.getCopy(getCtx(), getM_Product_ID(), get_TrxName()); return m_product; } // getProduct /** * Set M_AttributeSetInstance_ID * @param M_AttributeSetInstance_ID id */ public void setM_AttributeSetInstance_ID (int M_AttributeSetInstance_ID) { if (M_AttributeSetInstance_ID == 0) // 0 is valid ID set_Value("M_AttributeSetInstance_ID", Integer.valueOf(0)); else super.setM_AttributeSetInstance_ID (M_AttributeSetInstance_ID); } // setM_AttributeSetInstance_ID /** * Set Warehouse * @param M_Warehouse_ID warehouse */ public void setM_Warehouse_ID (int M_Warehouse_ID) { if (getM_Warehouse_ID() > 0 && getM_Warehouse_ID() != M_Warehouse_ID && !canChangeWarehouse()) log.severe("Ignored - Already Delivered/Invoiced/Reserved"); else super.setM_Warehouse_ID (M_Warehouse_ID); } // setM_Warehouse_ID /** * Can Change Warehouse * @return true if warehouse can be changed */ public boolean canChangeWarehouse() { if (getQtyDelivered().signum() != 0) { log.saveError("Error", Msg.translate(getCtx(), "QtyDelivered") + "=" + getQtyDelivered()); return false; } if (getQtyInvoiced().signum() != 0) { log.saveError("Error", Msg.translate(getCtx(), "QtyInvoiced") + "=" + getQtyInvoiced()); return false; } if (getQtyReserved().signum() != 0) { log.saveError("Error", Msg.translate(getCtx(), "QtyReserved") + "=" + getQtyReserved()); return false; } // We can change return true; } // canChangeWarehouse /** * Get C_Project_ID * @return C_Project_ID */ public int getC_Project_ID() { int ii = super.getC_Project_ID (); if (ii == 0) ii = getParent().getC_Project_ID(); return ii; } // getC_Project_ID /** * Get C_Activity_ID * @return C_Activity_ID */ public int getC_Activity_ID() { int ii = super.getC_Activity_ID (); if (ii == 0) ii = getParent().getC_Activity_ID(); return ii; } // getC_Activity_ID /** * Get C_Campaign_ID * @return C_Campaign_ID */ public int getC_Campaign_ID() { int ii = super.getC_Campaign_ID (); if (ii == 0) ii = getParent().getC_Campaign_ID(); return ii; } // getC_Campaign_ID /** * Get User1_ID * @return User1_ID */ public int getUser1_ID () { int ii = super.getUser1_ID (); if (ii == 0) ii = getParent().getUser1_ID(); return ii; } // getUser1_ID /** * Get User2_ID * @return User2_ID */ public int getUser2_ID () { int ii = super.getUser2_ID (); if (ii == 0) ii = getParent().getUser2_ID(); return ii; } // getUser2_ID /** * Get AD_OrgTrx_ID * @return AD_OrgTrx_ID */ public int getAD_OrgTrx_ID() { int ii = super.getAD_OrgTrx_ID(); if (ii == 0) ii = getParent().getAD_OrgTrx_ID(); return ii; } // getAD_OrgTrx_ID /** * String Representation * @return info */ @Override public String toString () { StringBuilder sb = new StringBuilder ("MOrderLine[") .append(get_ID()) .append(", Line=").append(getLine()) .append(", Ordered=").append(getQtyOrdered()) .append(", Delivered=").append(getQtyDelivered()) .append(", Invoiced=").append(getQtyInvoiced()) .append(", Reserved=").append(getQtyReserved()) .append(", LineNet=").append(getLineNetAmt()) .append ("]"); return sb.toString (); } // toString /** * Add to Description * @param description text */ public void addDescription (String description) { String desc = getDescription(); if (desc == null) setDescription(description); else setDescription(desc + " | " + description); } // addDescription /** * Get Description Text. * @return description */ public String getDescriptionText() { return super.getDescription(); } // getDescriptionText /** * Get Name * @return get the name of the line (from Product or Charge) */ public String getName() { getProduct(); if (m_product != null) return m_product.getName(); if (getC_Charge_ID() != 0) { MCharge charge = MCharge.get(getCtx(), getC_Charge_ID()); return charge.getName(); } return ""; } // getName /** * Set C_Charge_ID * @param C_Charge_ID charge */ public void setC_Charge_ID (int C_Charge_ID) { super.setC_Charge_ID (C_Charge_ID); if (C_Charge_ID > 0) set_ValueNoCheck ("C_UOM_ID", null); } // setC_Charge_ID /** * Calculate discount percentage (actual vs list) */ public void setDiscount() { BigDecimal list = getPriceList(); // No List Price if (Env.ZERO.compareTo(list) == 0) return; BigDecimal discount = list.subtract(getPriceActual()) .multiply(Env.ONEHUNDRED) .divide(list, getPrecision(), RoundingMode.HALF_UP); setDiscount(discount); } // setDiscount /** * Is Tax Included in Amount * @return true if tax calculated */ public boolean isTaxIncluded() { if (m_M_PriceList_ID == 0) { m_M_PriceList_ID = DB.getSQLValue(get_TrxName(), "SELECT M_PriceList_ID FROM C_Order WHERE C_Order_ID=?", getC_Order_ID()); } MPriceList pl = MPriceList.get(getCtx(), m_M_PriceList_ID, get_TrxName()); return pl.isTaxIncluded(); } // isTaxIncluded /** * Set Qty Entered/Ordered. * Use this Method if the Line UOM is the Product UOM. * @param Qty QtyOrdered/Entered */ public void setQty (BigDecimal Qty) { super.setQtyEntered (Qty); super.setQtyOrdered (getQtyEntered()); } // setQty /** * Set Qty Entered - enforce entered UOM precision. * @param QtyEntered */ public void setQtyEntered (BigDecimal QtyEntered) { if (QtyEntered != null && getC_UOM_ID() != 0) { int precision = MUOM.getPrecision(getCtx(), getC_UOM_ID()); QtyEntered = QtyEntered.setScale(precision, RoundingMode.HALF_UP); } super.setQtyEntered (QtyEntered); } // setQtyEntered /** * Set Qty Ordered - enforce Product UOM precision. * @param QtyOrdered */ public void setQtyOrdered (BigDecimal QtyOrdered) { MProduct product = getProduct(); if (QtyOrdered != null && product != null) { int precision = product.getUOMPrecision(); QtyOrdered = QtyOrdered.setScale(precision, RoundingMode.HALF_UP); } super.setQtyOrdered(QtyOrdered); } // setQtyOrdered /** * Get Base value for Cost Distribution * @param CostDistribution cost Distribution (MLandedCost.LANDEDCOSTDISTRIBUTION_*) * @return base number */ public BigDecimal getBase (String CostDistribution) { if (MLandedCost.LANDEDCOSTDISTRIBUTION_Costs.equals(CostDistribution)) { return this.getQtyOrdered().multiply(getPriceActual()); // Actual delivery } else if (MLandedCost.LANDEDCOSTDISTRIBUTION_Line.equals(CostDistribution)) return Env.ONE; else if (MLandedCost.LANDEDCOSTDISTRIBUTION_Quantity.equals(CostDistribution)) return getQtyOrdered(); else if (MLandedCost.LANDEDCOSTDISTRIBUTION_Volume.equals(CostDistribution)) { MProduct product = getProduct(); if (product == null) { log.severe("No Product"); return Env.ZERO; } return getQtyOrdered().multiply(product.getVolume()); } else if (MLandedCost.LANDEDCOSTDISTRIBUTION_Weight.equals(CostDistribution)) { MProduct product = getProduct(); if (product == null) { log.severe("No Product"); return Env.ZERO; } return getQtyOrdered().multiply(product.getWeight()); } // log.severe("Invalid Criteria: " + CostDistribution); return Env.ZERO; } // getBase @Override protected boolean beforeSave (boolean newRecord) { if (newRecord && getParent().isProcessed()) { log.saveError("ParentComplete", Msg.translate(getCtx(), "C_Order_ID")); return false; } // Get Defaults from Parent if (getC_BPartner_ID() == 0 || getC_BPartner_Location_ID() == 0 || getM_Warehouse_ID() == 0 || getC_Currency_ID() == 0) setOrder (getParent()); if (m_M_PriceList_ID == 0) setHeaderInfo(getParent()); // Validate change of warehouse, product or ASI if ( !newRecord && ( is_ValueChanged("M_Product_ID") || is_ValueChanged("M_Warehouse_ID") || ( !getParent().isProcessed() && getM_AttributeSetInstance_ID() != get_ValueOldAsInt(COLUMNNAME_M_AttributeSetInstance_ID)))) { if (!canChangeWarehouse()) return false; } // Product Changed // Charge line, set M_Product_ID to 0 if (getC_Charge_ID() != 0 && getM_Product_ID() != 0) setM_Product_ID(0); // No Product, set M_AttributeSetInstance_ID to 0 if (getM_Product_ID() == 0) setM_AttributeSetInstance_ID(0); else if (!isProcessed()) { // Set Product Price if (m_productPrice == null && Env.ZERO.compareTo(getPriceActual()) == 0 && Env.ZERO.compareTo(getPriceList()) == 0) setPrice(); if (m_productPrice == null) getProductPricing(m_M_PriceList_ID); // IDEMPIERE-1574 Sales Order Line lets Price under the Price Limit when updating // Enforce PriceLimit boolean enforce = m_IsSOTrx && getParent().getM_PriceList().isEnforcePriceLimit(); if (enforce && MRole.getDefault().isOverwritePriceLimit()) enforce = false; if (enforce && getPriceLimit() != Env.ZERO && getPriceActual().compareTo(getPriceLimit()) < 0) { log.saveError("UnderLimitPrice", "PriceEntered=" + getPriceEntered() + ", PriceLimit=" + getPriceLimit()); return false; } // Check is product not on price list int C_DocType_ID = getParent().getDocTypeID(); MDocType docType = MDocType.get(getCtx(), C_DocType_ID); // if (!docType.isNoPriceListCheck() && !m_productPrice.isCalculated()) { throw new ProductNotOnPriceListException(m_productPrice, getLine()); } } // Set Default UOM if (getC_UOM_ID() == 0) setDefaultC_UOM_ID(); // Enforce Qty Precision if (newRecord || is_ValueChanged("QtyEntered")) setQtyEntered(getQtyEntered()); if (newRecord || is_ValueChanged("QtyOrdered")) setQtyOrdered(getQtyOrdered()); // FreightAmt Not used if (Env.ZERO.compareTo(getFreightAmt()) != 0) setFreightAmt(Env.ZERO); // Set C_Tax_ID if (getC_Tax_ID() == 0) setTax(); // Set Line No if (getLine() == 0) { String sql = "SELECT COALESCE(MAX(Line),0)+10 FROM C_OrderLine WHERE C_Order_ID=?"; int ii = DB.getSQLValue (get_TrxName(), sql, getC_Order_ID()); setLine (ii); } // Calculations & Rounding setLineNetAmt(); setDiscount(); /* Carlos Ruiz - globalqss * IDEMPIERE-178 Orders and Invoices must disallow amount lines without product/charge */ if (getParent().getC_DocTypeTarget().isChargeOrProductMandatory()) { if (getC_Charge_ID() == 0 && getM_Product_ID() == 0 && (getPriceEntered().signum() != 0 || getQtyEntered().signum() != 0)) { log.saveError("FillMandatory", Msg.translate(getCtx(), "ChargeOrProductMandatory")); return false; } } // Update QtyOrdered and QtyLostSales for closed order if (!newRecord && DocAction.STATUS_Closed.equals(getParent().getDocStatus()) && is_ValueChanged(COLUMNNAME_QtyDelivered) && !getParent().is_ValueChanged(MOrder.COLUMNNAME_DocStatus)) { if (getQtyOrdered().compareTo(getQtyDelivered()) > 0) { setQtyLostSales(getQtyLostSales().add(getQtyOrdered().subtract(getQtyDelivered()))); setQtyOrdered(getQtyDelivered()); } else { setQtyLostSales(Env.ZERO); } } MClientInfo ci = MClientInfo.get(getCtx(), getAD_Client_ID(), get_TrxName()); if (MOrder.DELIVERYVIARULE_Shipper.equals(getParent().getDeliveryViaRule()) && MOrder.FREIGHTCOSTRULE_FreightIncluded.equals(getParent().getFreightCostRule()) && ( (getM_Product_ID() > 0 && getM_Product_ID() == ci.getM_ProductFreight_ID()) || (getC_Charge_ID() > 0 && getC_Charge_ID() == ci.getC_ChargeFreight_ID()) ) ) { log.saveError("Error", Msg.getMsg(getCtx(), "FreightOrderLineNotAllowed")); return false; } return true; } // beforeSave /*** * Set default unit of measurement.
    * If there's a product, it sets the UOM of the product.
    * If not, it sets the default UOM of the client. */ private void setDefaultC_UOM_ID() { int C_UOM_ID = 0; if (MProduct.get(getCtx(), getM_Product_ID()) != null) { C_UOM_ID = MProduct.get(getCtx(), getM_Product_ID()).getC_UOM_ID(); } else { C_UOM_ID = MUOM.getDefault_UOM_ID(getCtx()); } if (C_UOM_ID > 0) setC_UOM_ID (C_UOM_ID); } @Override protected boolean beforeDelete () { // Can't delete if QtyDelivered is not 0 if (Env.ZERO.compareTo(getQtyDelivered()) != 0) { log.saveError("DeleteError", Msg.translate(getCtx(), "QtyDelivered") + "=" + getQtyDelivered()); return false; } // Can't delete if QtyInvoiced is not 0 if (Env.ZERO.compareTo(getQtyInvoiced()) != 0) { log.saveError("DeleteError", Msg.translate(getCtx(), "QtyInvoiced") + "=" + getQtyInvoiced()); return false; } // Can't delete if QtyReserved is not 0 if (Env.ZERO.compareTo(getQtyReserved()) != 0) { // For PO should be On Order log.saveError("DeleteError", Msg.translate(getCtx(), "QtyReserved") + "=" + getQtyReserved()); return false; } // Remove reference from requisition lines MRequisitionLine.unlinkC_OrderLine_ID(getCtx(), get_ID(), get_TrxName()); return true; } // beforeDelete @Override protected boolean afterSave (boolean newRecord, boolean success) { if (!success) return success; if (getParent().isProcessed()) return success; // Re-calculate order tax if (newRecord || is_ValueChanged(MOrderLine.COLUMNNAME_C_Tax_ID) || is_ValueChanged(MOrderLine.COLUMNNAME_LineNetAmt)) { MTax tax = new MTax(getCtx(), getC_Tax_ID(), get_TrxName()); MTaxProvider provider = new MTaxProvider(tax.getCtx(), tax.getC_TaxProvider_ID(), tax.get_TrxName()); ITaxProvider calculator = Core.getTaxProvider(provider); if (calculator == null) throw new AdempiereException(Msg.getMsg(getCtx(), "TaxNoProvider")); return calculator.recalculateTax(provider, this, newRecord); } return success; } // afterSave @Override protected boolean afterDelete (boolean success) { if (!success) return success; // Delete resource assignment record if (getS_ResourceAssignment_ID() != 0) { MResourceAssignment ra = new MResourceAssignment(getCtx(), getS_ResourceAssignment_ID(), get_TrxName()); ra.delete(true); } return updateHeaderTax(); } // afterDelete /** * Recalculate order tax * @param oldTax true if the old C_Tax_ID should be used * @return true if success, false otherwise * * author teo_sarca [ 1583825 ] */ public boolean updateOrderTax(boolean oldTax) { int C_Tax_ID = getC_Tax_ID(); boolean isOldTax = oldTax && is_ValueChanged(MOrderLine.COLUMNNAME_C_Tax_ID); if (isOldTax) { Object old = get_ValueOld(MOrderLine.COLUMNNAME_C_Tax_ID); if (old == null) { return true; } C_Tax_ID = ((Integer)old).intValue(); } if (C_Tax_ID == 0) { return true; } MTax t = MTax.get(C_Tax_ID); if (t.isSummary()) { MOrderTax[] taxes = MOrderTax.getChildTaxes(this, getPrecision(), isOldTax, get_TrxName()); if (taxes != null && taxes.length > 0) { for(MOrderTax tax : taxes) { if (!tax.calculateTaxFromLines()) return false; if (tax.getTaxAmt().signum() != 0) { if (!tax.save(get_TrxName())) return false; } else { if (!tax.is_new() && !tax.delete(false, get_TrxName())) return false; } } } } else { MOrderTax tax = MOrderTax.get (this, getPrecision(), oldTax, get_TrxName()); if (tax != null) { if (!tax.calculateTaxFromLines()) return false; if (tax.getTaxAmt().signum() != 0) { if (!tax.save(get_TrxName())) return false; } else { if (!tax.is_new() && !tax.delete(false, get_TrxName())) return false; } } } return true; } /** * Update Tax and Header * @return true if header updated */ public boolean updateHeaderTax() { // Update header only if the document is not processed if (isProcessed() && !is_ValueChanged(COLUMNNAME_Processed)) return true; MTax tax = new MTax(getCtx(), getC_Tax_ID(), get_TrxName()); MTaxProvider provider = new MTaxProvider(tax.getCtx(), tax.getC_TaxProvider_ID(), tax.get_TrxName()); ITaxProvider calculator = Core.getTaxProvider(provider); if (calculator == null) throw new AdempiereException(Msg.getMsg(getCtx(), "TaxNoProvider")); if (!calculator.updateOrderTax(provider, this)) return false; return calculator.updateHeaderTax(provider, this); } // updateHeaderTax /** * Reset {@link #m_parent} to null */ public void clearParent() { this.m_parent = null; } /** * Get the description stripping the Close tag that was created when closing the order * @return stripped description text */ public String getDescriptionStrippingCloseTag() { String description = getDescription(); if (description == null) return description; Pattern pattern = Pattern.compile("( \\| )?Close \\(.*\\)"); String[] parts = pattern.split(description); StringBuilder description_sb = new StringBuilder(); for (String s : parts) description_sb.append(s); return description_sb.toString(); } } // MOrderLine