/****************************************************************************** * Product: Adempiere ERP & CRM Smart Business Solution * * Copyright (C) 1999-2006 Adempiere, 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. * * Copyright (C) 2003-2007 e-Evolution,SC. All Rights Reserved. * * Contributor(s): Victor Perez www.e-evolution.com * *****************************************************************************/ package org.eevolution.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.List; import java.util.Properties; import java.util.logging.Level; import org.adempiere.exceptions.AdempiereException; import org.adempiere.exceptions.NegativeInventoryDisallowedException; import org.compiere.model.MBPartner; import org.compiere.model.MBPartnerLocation; import org.compiere.model.MDocType; import org.compiere.model.MLocator; import org.compiere.model.MMovement; import org.compiere.model.MPeriod; import org.compiere.model.MProduct; import org.compiere.model.MProject; import org.compiere.model.MRefList; import org.compiere.model.MStorageOnHand; import org.compiere.model.MUser; import org.compiere.model.ModelValidationEngine; import org.compiere.model.ModelValidator; import org.compiere.model.PO; import org.compiere.model.Query; import org.compiere.print.ReportEngine; import org.compiere.process.DocAction; import org.compiere.process.DocumentEngine; import org.compiere.util.DB; import org.compiere.util.Env; import org.compiere.util.Msg; import org.compiere.util.Util; /** * Order Distribution Model. * Please do not set DocStatus and C_DocType_ID directly. * They are set in the process() method. * Use DocAction and C_DocTypeTarget_ID instead. * * @author victor.perez@e-evolution.com, e-Evolution http://www.e-evolution.com *
  • Original contributor of Distribution Functionality *
  • FR [ 2520591 ] Support multiples calendar for Org * @see https://sourceforge.net/p/adempiere/feature-requests/631/ */ public class MDDOrder extends X_DD_Order implements DocAction { /** * */ private static final long serialVersionUID = -5997157712614274458L; /** * Create new Order by copying * @param from order * @param dateDoc date of the document date * @param C_DocTypeTarget_ID target document type * @param isSOTrx sales order * @param counter create counter links * @param copyASI copy line attributes Attribute Set Instance, Resaouce Assignment * @param trxName trx * @return Distribution Order */ public static MDDOrder copyFrom (MDDOrder from, Timestamp dateDoc, int C_DocTypeTarget_ID, boolean isSOTrx, boolean counter, boolean copyASI, String trxName) { MDDOrder to = new MDDOrder (from.getCtx(), 0, trxName); to.set_TrxName(trxName); PO.copyValues(from, to, from.getAD_Client_ID(), from.getAD_Org_ID()); to.set_ValueNoCheck ("DD_Order_ID", I_ZERO); to.set_ValueNoCheck ("DocumentNo", null); // to.setDocStatus (DOCSTATUS_Drafted); // Draft to.setDocAction(DOCACTION_Complete); // to.setC_DocType_ID(0); to.setIsSOTrx(isSOTrx); // to.setIsSelected (false); to.setDateOrdered (dateDoc); to.setDatePromised (dateDoc); // assumption to.setDatePrinted(null); to.setIsPrinted (false); // to.setIsApproved (false); // to.setIsDelivered(false); to.setPosted (false); to.setProcessed (false); if (counter) to.setRef_Order_ID(from.getDD_Order_ID()); else to.setRef_Order_ID(0); // if (!to.save(trxName)) throw new IllegalStateException("Could not create Order"); if (counter) from.setRef_Order_ID(to.getDD_Order_ID()); if (to.copyLinesFrom(from, counter, copyASI) == 0) throw new IllegalStateException("Could not create Order Lines"); return to; } // copyFrom /** * UUID based Constructor * @param ctx Context * @param DD_Order_UU UUID key * @param trxName Transaction */ public MDDOrder(Properties ctx, String DD_Order_UU, String trxName) { super(ctx, DD_Order_UU, trxName); if (Util.isEmpty(DD_Order_UU)) setInitialDefaults(); } /************************************************************************** * Default Constructor * @param ctx context * @param DD_Order_ID order to load, (0 create new order) * @param trxName trx name */ public MDDOrder(Properties ctx, int DD_Order_ID, String trxName) { super (ctx, DD_Order_ID, trxName); // New if (DD_Order_ID == 0) setInitialDefaults(); } // MDDOrder /** * Set the initial defaults for a new record */ private void setInitialDefaults() { setDocStatus(DOCSTATUS_Drafted); setDocAction (DOCACTION_Prepare); // setDeliveryRule (DELIVERYRULE_Availability); setFreightCostRule (FREIGHTCOSTRULE_FreightIncluded); setPriorityRule (PRIORITYRULE_Medium); setDeliveryViaRule (DELIVERYVIARULE_Pickup); // setIsSelected (false); setIsSOTrx (true); setIsDropShip(false); setSendEMail (false); // setIsApproved(false); setIsPrinted(false); setIsDelivered(false); // super.setProcessed(false); setProcessing(false); setPosted(false); setDatePromised (new Timestamp(System.currentTimeMillis())); setDateOrdered (new Timestamp(System.currentTimeMillis())); setFreightAmt (Env.ZERO); setChargeAmt (Env.ZERO); } /************************************************************************** * Project Constructor * @param project Project to create Order from * @param IsSOTrx sales order * @param DocSubTypeSO if SO DocType Target (default DocSubTypeSO_OnCredit) */ public MDDOrder (MProject project, boolean IsSOTrx, String DocSubTypeSO) { this (project.getCtx(), 0, project.get_TrxName()); setAD_Client_ID(project.getAD_Client_ID()); setAD_Org_ID(project.getAD_Org_ID()); setC_Campaign_ID(project.getC_Campaign_ID()); setSalesRep_ID(project.getSalesRep_ID()); // setC_Project_ID(project.getC_Project_ID()); setDescription(project.getName()); Timestamp ts = project.getDateContract(); if (ts != null) setDateOrdered (ts); ts = project.getDateFinish(); if (ts != null) setDatePromised (ts); // setC_BPartner_ID(project.getC_BPartner_ID()); setC_BPartner_Location_ID(project.getC_BPartner_Location_ID()); setAD_User_ID(project.getAD_User_ID()); // setM_Warehouse_ID(project.getM_Warehouse_ID()); // setIsSOTrx(IsSOTrx); } // MDDOrder /** * Load Constructor * @param ctx context * @param rs result set record * @param trxName transaction */ public MDDOrder (Properties ctx, ResultSet rs, String trxName) { super(ctx, rs, trxName); } // MDDOrder public MDDOrder(Properties ctx, int DD_Order_ID, String trxName, String... virtualColumns) { super(ctx, DD_Order_ID, trxName, virtualColumns); } /** Order Lines */ private MDDOrderLine[] m_lines = null; /** Force Creation of order */ @SuppressWarnings("unused") private boolean m_forceCreation = false; /** * Add to Description * @param description text */ public void addDescription (String description) { String desc = getDescription(); if (desc == null) setDescription(description); else setDescription(desc + " | " + description); } // addDescription /** * Set Ship Business Partner * @param C_BPartner_ID bpartner */ public void setShip_BPartner_ID (int C_BPartner_ID) { super.setC_BPartner_ID (C_BPartner_ID); } // setShip_BPartner_ID /** * Set Ship Business Partner Location * @param C_BPartner_Location_ID bp location */ public void setShip_Location_ID (int C_BPartner_Location_ID) { super.setC_BPartner_Location_ID (C_BPartner_Location_ID); } // setShip_Location_ID /** * Set Ship Business Partner Contact * @param AD_User_ID user */ public void setShip_User_ID (int AD_User_ID) { super.setAD_User_ID (AD_User_ID); } // setShip_User_ID /** * Set Business Partner Defaults and Details. * SOTrx should be set. * @param bp business partner */ public void setBPartner (MBPartner bp) { if (bp == null) return; setC_BPartner_ID(bp.getC_BPartner_ID()); // Defaults Payment Term int ii = 0; if (isSOTrx()) ii = bp.getC_PaymentTerm_ID(); else ii = bp.getPO_PaymentTerm_ID(); // Default Price List if (isSOTrx()) ii = bp.getM_PriceList_ID(); else ii = bp.getPO_PriceList_ID(); // Default Delivery/Via Rule String ss = bp.getDeliveryRule(); if (ss != null) setDeliveryRule(ss); ss = bp.getDeliveryViaRule(); if (ss != null) setDeliveryViaRule(ss); // Default Invoice/Payment Rule ss = bp.getInvoiceRule(); if (getSalesRep_ID() == 0) { ii = Env.getAD_User_ID(getCtx()); if (ii != 0) setSalesRep_ID (ii); } // Set Locations MBPartnerLocation[] locs = bp.getLocations(false); if (locs != null) { for (int i = 0; i < locs.length; i++) { if (locs[i].isShipTo()) { super.setC_BPartner_Location_ID(locs[i].getC_BPartner_Location_ID()); } } // set to first if (getC_BPartner_Location_ID() == 0 && locs.length > 0) { super.setC_BPartner_Location_ID(locs[0].getC_BPartner_Location_ID()); } } if (getC_BPartner_Location_ID() == 0) { log.log(Level.SEVERE, "MDDOrder.setBPartner - Has no Ship To Address: " + bp); } // Set Contact MUser[] contacts = bp.getContacts(false); if (contacts != null && contacts.length == 1) { setAD_User_ID(contacts[0].getAD_User_ID()); } } // setBPartner /** * Copy Lines From other Order * @param otherOrder order * @param counter set counter info * @param copyASI copy line attributes Attribute Set Instance, Resource Assignment * @return number of lines copied */ public int copyLinesFrom (MDDOrder otherOrder, boolean counter, boolean copyASI) { if (isProcessed() || isPosted() || otherOrder == null) return 0; MDDOrderLine[] fromLines = otherOrder.getLines(false, null); int count = 0; for (int i = 0; i < fromLines.length; i++) { MDDOrderLine line = new MDDOrderLine (this); PO.copyValues(fromLines[i], line, getAD_Client_ID(), getAD_Org_ID()); line.setDD_Order_ID(getDD_Order_ID()); line.setOrder(this); // References if (!copyASI) { line.setM_AttributeSetInstance_ID(0); //line.setS_ResourceAssignment_ID(0); } line.setQtyDelivered(Env.ZERO); line.setQtyReserved(Env.ZERO); line.setDateDelivered(null); line.setProcessed(false); if (line.save(get_TrxName())) count++; } if (fromLines.length != count) log.log(Level.SEVERE, "Line difference - From=" + fromLines.length + " <> Saved=" + count); return count; } // copyLinesFrom /************************************************************************** * String Representation * @return info */ public String toString () { StringBuilder sb = new StringBuilder ("MDDOrder[") .append(get_ID()).append("-").append(getDocumentNo()) .append(",IsSOTrx=").append(isSOTrx()) .append(",C_DocType_ID=").append(getC_DocType_ID()) .append ("]"); return sb.toString (); } // toString /** * Get Document Info * @return document info (untranslated) */ public String getDocumentInfo() { MDocType dt = MDocType.get(getCtx(), getC_DocType_ID()); return dt.getNameTrl() + " " + getDocumentNo(); } // getDocumentInfo /** * Create PDF * @return File or null */ public File createPDF () { try { File temp = File.createTempFile(get_TableName()+get_ID()+"_", ".pdf"); return createPDF (temp); } catch (Exception e) { log.severe("Could not create PDF - " + e.getMessage()); } return null; } // getPDF /** * Create PDF file * @param file output file * @return file if success */ public File createPDF (File file) { ReportEngine re = ReportEngine.get (getCtx(), ReportEngine.DISTRIBUTION_ORDER, getDD_Order_ID()); if (re == null) return null; return re.getPDF(file); } // createPDF /************************************************************************** * Get Lines of Order * @param whereClause where clause or null (starting with AND) * @param orderClause order clause * @return lines */ public MDDOrderLine[] getLines (String whereClause, String orderClause) { StringBuilder whereClauseFinal = new StringBuilder(MDDOrderLine.COLUMNNAME_DD_Order_ID).append("=?"); if (!Util.isEmpty(whereClause, true)) whereClauseFinal.append(" AND (").append(whereClause).append(")"); // List list = new Query(getCtx(), I_DD_OrderLine.Table_Name, whereClauseFinal.toString(), get_TrxName()) .setParameters(getDD_Order_ID()) .setOrderBy(orderClause) .list(); return list.toArray(new MDDOrderLine[list.size()]); } // getLines /** * Get Lines of Order * @param requery requery * @param orderBy optional order by column * @return lines */ public MDDOrderLine[] getLines (boolean requery, String orderBy) { if (m_lines != null && !requery) { set_TrxName(m_lines, get_TrxName()); return m_lines; } // String orderClause = ""; if (orderBy != null && orderBy.length() > 0) orderClause += orderBy; else orderClause += "Line"; m_lines = getLines(null, orderClause); return m_lines; } // getLines /** * Get Lines of Order. * (useb by web store) * @return lines */ public MDDOrderLine[] getLines() { return getLines(false, null); } // getLines /** * Renumber Lines * @param step start and step */ public void renumberLines (int step) { int number = step; MDDOrderLine[] lines = getLines(true, null); // Line is default for (int i = 0; i < lines.length; i++) { MDDOrderLine line = lines[i]; line.setLine(number); line.saveEx(get_TrxName()); number += step; } m_lines = null; } // renumberLines /** * Get Shipments of Order * @return shipments */ public MMovement[] getMovement() { ArrayList list = new ArrayList(); String sql = "SELECT DISTINCT io.* FROM M_MovementLine ml " + "INNER JOIN M_Movement m ON (m.M_Movement_ID = ml.M_Movement_ID) " + "INNER JOIN DD_ORDERLINE ol ON (ol.DD_ORDERLINE_ID=ml.DD_ORDERLINE_ID) " + "INNER JOIN DD_ORDER o ON (o.DD_ORDER_ID=ol.DD_ORDER_ID) " + "WHERE o.DD_ORDER_ID=? " + "ORDER BY m.Created DESC"; PreparedStatement pstmt = null; ResultSet rs = null; try { pstmt = DB.prepareStatement(sql, get_TrxName()); pstmt.setInt(1, getDD_Order_ID()); rs = pstmt.executeQuery(); while (rs.next()) list.add(new MMovement(getCtx(), rs, get_TrxName())); } catch (Exception e) { log.log(Level.SEVERE, sql, e); } finally { DB.close(rs, pstmt); rs = null; pstmt = null; } // MMovement[] retValue = new MMovement[list.size()]; list.toArray(retValue); return retValue; } // getShipments /** * Get Document Status * @return Document Status Clear Text */ public String getDocStatusName() { return MRefList.getListName(getCtx(), 131, getDocStatus()); } // getDocStatusName /** * Set DocAction * @param DocAction doc action */ public void setDocAction (String DocAction) { setDocAction (DocAction, false); } // setDocAction /** * Set Processed. * Propergate to Lines/Taxes * @param processed processed */ public void setProcessed (boolean processed) { super.setProcessed (processed); if (get_ID() == 0) return; String set = "SET Processed='" + (processed ? "Y" : "N") + "' WHERE DD_Order_ID=" + getDD_Order_ID(); int noLine = DB.executeUpdate("UPDATE DD_OrderLine " + set, get_TrxName()); m_lines = null; if (log.isLoggable(Level.FINE)) log.fine("setProcessed - " + processed + " - Lines=" + noLine); } // setProcessed @Override protected boolean beforeSave (boolean newRecord) { // Client/Org Check if (getAD_Org_ID() == 0) { int context_AD_Org_ID = Env.getAD_Org_ID(getCtx()); if (context_AD_Org_ID != 0) { setAD_Org_ID(context_AD_Org_ID); log.warning("Changed Org to Context=" + context_AD_Org_ID); } } if (getAD_Client_ID() == 0) { m_processMsg = "AD_Client_ID = 0"; return false; } // New Record Doc Type - make sure DocType set to 0 if (newRecord && getC_DocType_ID() == 0) setC_DocType_ID (0); // Default Warehouse if (getM_Warehouse_ID() == 0) { int ii = Env.getContextAsInt(getCtx(), Env.M_WAREHOUSE_ID); if (ii != 0) setM_Warehouse_ID(ii); else { log.saveError("FillMandatory", Msg.getElement(getCtx(), "M_Warehouse_ID")); return false; } } // Validate whether it is ok to change warehouse if (!newRecord && is_ValueChanged("M_Warehouse_ID")) { MDDOrderLine[] lines = getLines(false,null); for (int i = 0; i < lines.length; i++) { if (!lines[i].canChangeWarehouse()) return false; } } // No Partner Info - set Template if (getC_BPartner_ID() == 0) setBPartner(MBPartner.getTemplate(getCtx(), getAD_Client_ID())); // Set default values from business partner if (getC_BPartner_Location_ID() == 0) setBPartner(new MBPartner(getCtx(), getC_BPartner_ID(), null)); // Default Sales Rep if (getSalesRep_ID() == 0) { int ii = Env.getContextAsInt(getCtx(), Env.AD_USER_ID); if (ii != 0) setSalesRep_ID (ii); } return true; } // beforeSave @Override protected boolean afterSave (boolean newRecord, boolean success) { if (!success || newRecord) return success; // Propagate Description and POReference change to M_Movement records if (is_ValueChanged("Description") || is_ValueChanged("POReference")) { String sql = "UPDATE M_Movement i" + " SET (Description,POReference)=" + "(SELECT Description,POReference " + "FROM DD_Order o WHERE i.DD_Order_ID=o.DD_Order_ID) " + "WHERE DocStatus NOT IN ('RE','CL') AND DD_Order_ID=" + getDD_Order_ID(); int no = DB.executeUpdate(sql, get_TrxName()); if (log.isLoggable(Level.FINE)) log.fine("Description -> #" + no); } // Sync Lines afterSaveSync("AD_Org_ID"); afterSaveSync("C_BPartner_ID"); afterSaveSync("C_BPartner_Location_ID"); afterSaveSync("DateOrdered"); afterSaveSync("DatePromised"); afterSaveSync("M_Shipper_ID"); // return true; } // afterSave /** * Copy columnName value to line (MDDOrderLine) records * @param columnName */ private void afterSaveSync (String columnName) { if (is_ValueChanged(columnName)) { final String whereClause = I_DD_Order.COLUMNNAME_DD_Order_ID + "=?"; List lines = new Query (getCtx(), I_DD_OrderLine.Table_Name, whereClause, get_TrxName()) .setParameters(getDD_Order_ID()) .list(); for (MDDOrderLine line : lines) { line.set_ValueOfColumn(columnName, get_Value(columnName)); line.saveEx(); if (log.isLoggable(Level.FINE)) log.fine(columnName + " Lines -> #" + get_Value(columnName)); } } } // afterSaveSync /** * Set DocAction * @param DocAction doc oction * @param forceCreation force creation */ public void setDocAction (String DocAction, boolean forceCreation) { super.setDocAction (DocAction); m_forceCreation = forceCreation; } // setDocAction @Override protected boolean beforeDelete () { if (isProcessed()) return false; // Delete lines getLines(); for (int i = 0; i < m_lines.length; i++) { m_lines[i].delete(true); } return true; } // beforeDelete /** * Process document * @param processAction document action * @return true if performed */ 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; /** * Unlock Document. * @return true if success */ public boolean unlockIt() { if (log.isLoggable(Level.INFO)) log.info("unlockIt - " + toString()); setProcessing(false); return true; } // unlockIt /** * Invalidate Document * @return true if success */ public boolean invalidateIt() { if (log.isLoggable(Level.INFO)) log.info(toString()); setDocAction(DOCACTION_Prepare); return true; } // invalidateIt /************************************************************************** * Prepare Document * @return new status (In Progress or Invalid) */ public String prepareIt() { if (log.isLoggable(Level.INFO)) log.info(toString()); m_processMsg = ModelValidationEngine.get().fireDocValidate(this, ModelValidator.TIMING_BEFORE_PREPARE); if (m_processMsg != null) return DocAction.STATUS_Invalid; MDocType dt = MDocType.get(getCtx(), getC_DocType_ID()); // Std Period open? if (!MPeriod.isOpen(getCtx(), getDateOrdered(), dt.getDocBaseType(), getAD_Org_ID())) { m_processMsg = "@PeriodClosed@"; return DocAction.STATUS_Invalid; } // Lines MDDOrderLine[] lines = getLines(true, "M_Product_ID"); if (lines.length == 0) { m_processMsg = "@NoLines@"; return DocAction.STATUS_Invalid; } // Bug 1564431 if (getDeliveryRule() != null && getDeliveryRule().equals(MDDOrder.DELIVERYRULE_CompleteOrder)) { for (int i = 0; i < lines.length; i++) { MDDOrderLine line = lines[i]; MProduct product = line.getProduct(); if (product != null && product.isExcludeAutoDelivery()) { m_processMsg = "@M_Product_ID@ "+product.getValue()+" @IsExcludeAutoDelivery@"; return DocAction.STATUS_Invalid; } } } // Mandatory Product Attribute Set Instance String mandatoryType = "='Y'"; // IN ('Y','S') String sql = "SELECT COUNT(*) " + "FROM DD_OrderLine ol" + " INNER JOIN M_Product p ON (ol.M_Product_ID=p.M_Product_ID)" + " INNER JOIN M_AttributeSet pas ON (p.M_AttributeSet_ID=pas.M_AttributeSet_ID) " + "WHERE pas.MandatoryType" + mandatoryType + " AND ol.M_AttributeSetInstance_ID IS NULL" + " AND ol.DD_Order_ID=?"; int no = DB.getSQLValue(get_TrxName(), sql, getDD_Order_ID()); if (no != 0) { m_processMsg = "@LinesWithoutProductAttribute@ (" + no + ")"; return DocAction.STATUS_Invalid; } reserveStock(lines); m_processMsg = ModelValidationEngine.get().fireDocValidate(this, ModelValidator.TIMING_AFTER_PREPARE); if (m_processMsg != null) return DocAction.STATUS_Invalid; m_justPrepared = true; return DocAction.STATUS_InProgress; } // prepareIt /** * Reserve Inventory. * Counterpart: MMovement.completeIt() * @param lines distribution order lines (ordered by M_Product_ID for deadlock prevention) */ public void reserveStock (MDDOrderLine[] lines) { BigDecimal Volume = Env.ZERO; BigDecimal Weight = Env.ZERO; StringBuilder errors = new StringBuilder(); // Always check and (un) Reserve Inventory for (MDDOrderLine line : lines) { MLocator locator_from = MLocator.get(getCtx(),line.getM_Locator_ID()); MLocator locator_to = MLocator.get(getCtx(),line.getM_LocatorTo_ID()); BigDecimal reserved_ordered = line.getQtyOrdered() .subtract(line.getQtyReserved()) .subtract(line.getQtyDelivered()); if (reserved_ordered.signum() == 0) { MProduct product = line.getProduct(); if (product != null) { Volume = Volume.add(product.getVolume().multiply(line.getQtyOrdered())); Weight = Weight.add(product.getWeight().multiply(line.getQtyOrdered())); } continue; } if (log.isLoggable(Level.FINE)) log.fine("Line=" + line.getLine() + " - Ordered=" + line.getQtyOrdered() + ",Reserved=" + line.getQtyReserved() + ",Delivered=" + line.getQtyDelivered()); // Check Product - Stocked and Item MProduct product = line.getProduct(); if (product != null) { try { if (product.isStocked()) { // Update Storage if (!MStorageOnHand.add(getCtx(), locator_to.getM_Locator_ID(), line.getM_Product_ID(), line.getM_AttributeSetInstance_ID(), Env.ZERO,null, get_TrxName())) { throw new AdempiereException(); } if (!MStorageOnHand.add(getCtx(), locator_from.getM_Locator_ID(), line.getM_Product_ID(), line.getM_AttributeSetInstanceTo_ID(), Env.ZERO,null, get_TrxName())) { throw new AdempiereException(); } } // stockec // update line line.setQtyReserved(line.getQtyReserved().add(reserved_ordered)); line.saveEx(); // Volume = Volume.add(product.getVolume().multiply(line.getQtyOrdered())); Weight = Weight.add(product.getWeight().multiply(line.getQtyOrdered())); } catch (NegativeInventoryDisallowedException e) { log.severe(e.getMessage()); errors.append(Msg.getElement(getCtx(), "Line")).append(" ").append(line.getLine()).append(": "); errors.append(e.getMessage()).append("\n"); } } // product } // reverse inventory if (errors.toString().length() > 0) throw new AdempiereException(errors.toString()); setVolume(Volume); setWeight(Weight); } // reserveStock /** * Approve Document * @return true if success */ public boolean approveIt() { if (log.isLoggable(Level.INFO)) log.info("approveIt - " + toString()); setIsApproved(true); return true; } // approveIt /** * Reject Approval * @return true if success */ public boolean rejectIt() { if (log.isLoggable(Level.INFO)) log.info("rejectIt - " + toString()); setIsApproved(false); return true; } // rejectIt /************************************************************************** * Complete Document * @return new status (Complete, In Progress, Invalid, Waiting ..) */ public String completeIt() { @SuppressWarnings("unused") MDocType dt = MDocType.get(getCtx(), getC_DocType_ID()); // Just prepare if (DOCACTION_Prepare.equals(getDocAction())) { setProcessed(false); return DocAction.STATUS_InProgress; } // Re-Check if (!m_justPrepared) { String status = prepareIt(); m_justPrepared = false; 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; // Implicit Approval if (!isApproved()) approveIt(); getLines(true,null); if (log.isLoggable(Level.INFO)) log.info(toString()); StringBuilder info = new StringBuilder(); String valid = ModelValidationEngine.get().fireDocValidate(this, ModelValidator.TIMING_AFTER_COMPLETE); if (valid != null) { if (info.length() > 0) info.append(" - "); info.append(valid); m_processMsg = info.toString(); return DocAction.STATUS_Invalid; } setProcessed(true); m_processMsg = info.toString(); // setDocAction(DOCACTION_Close); return DocAction.STATUS_Completed; } // completeIt /** * Void Document. * Set Qtys to 0 - Sales: reverse all documents * @return true if success */ public boolean voidIt() { if (log.isLoggable(Level.INFO)) log.info(toString()); // Before Void m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_BEFORE_VOID); if (m_processMsg != null) return false; MDDOrderLine[] lines = getLines(true, "M_Product_ID"); for (int i = 0; i < lines.length; i++) { MDDOrderLine line = lines[i]; BigDecimal old = line.getQtyOrdered(); if (old.signum() != 0) { line.addDescription(Msg.getMsg(getCtx(), "Voided") + " (" + old + ")"); line.saveEx(get_TrxName()); } } addDescription(Msg.getMsg(getCtx(), "Voided")); // Clear Reservations reserveStock(lines); // After Void m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_AFTER_VOID); if (m_processMsg != null) return false; setProcessed(true); setDocAction(DOCACTION_None); return true; } // voidIt /** * Create Shipment/Invoice Reversals * @return true if success */ /* private boolean createReversals() { // Cancel only Sales if (!isSOTrx()) return true; if (log.isLoggable(Level.INFO)) log.info("createReversals"); StringBuilder info = new StringBuilder(); // Reverse All *Shipments* info.append("@M_InOut_ID@:"); MInOut[] shipments = getShipments(); for (int i = 0; i < shipments.length; i++) { MInOut ship = shipments[i]; // if closed - ignore if (MInOut.DOCSTATUS_Closed.equals(ship.getDocStatus()) || MInOut.DOCSTATUS_Reversed.equals(ship.getDocStatus()) || MInOut.DOCSTATUS_Voided.equals(ship.getDocStatus()) ) continue; ship.set_TrxName(get_TrxName()); // If not completed - void - otherwise reverse it if (!MInOut.DOCSTATUS_Completed.equals(ship.getDocStatus())) { if (ship.voidIt()) ship.setDocStatus(MInOut.DOCSTATUS_Voided); } else if (ship.reverseCorrectIt()) // completed shipment { ship.setDocStatus(MInOut.DOCSTATUS_Reversed); info.append(" ").append(ship.getDocumentNo()); } else { m_processMsg = "Could not reverse Shipment " + ship; return false; } ship.setDocAction(MInOut.DOCACTION_None); ship.save(get_TrxName()); } // for all shipments // Reverse All *Invoices* info.append(" - @C_Invoice_ID@:"); MInvoice[] invoices = getInvoices(); for (int i = 0; i < invoices.length; i++) { MInvoice invoice = invoices[i]; // if closed - ignore if (MInvoice.DOCSTATUS_Closed.equals(invoice.getDocStatus()) || MInvoice.DOCSTATUS_Reversed.equals(invoice.getDocStatus()) || MInvoice.DOCSTATUS_Voided.equals(invoice.getDocStatus()) ) continue; invoice.set_TrxName(get_TrxName()); // If not completed - void - otherwise reverse it if (!MInvoice.DOCSTATUS_Completed.equals(invoice.getDocStatus())) { if (invoice.voidIt()) invoice.setDocStatus(MInvoice.DOCSTATUS_Voided); } else if (invoice.reverseCorrectIt()) // completed invoice { invoice.setDocStatus(MInvoice.DOCSTATUS_Reversed); info.append(" ").append(invoice.getDocumentNo()); } else { m_processMsg = "Could not reverse Invoice " + invoice; return false; } invoice.setDocAction(MInvoice.DOCACTION_None); invoice.save(get_TrxName()); } // for all shipments m_processMsg = info.toString(); return true; } // createReversals */ /** * Close Document. * Cancel not delivered Qunatities * @return true if success */ public boolean closeIt() { if (log.isLoggable(Level.INFO)) log.info(toString()); // Before Close m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_BEFORE_CLOSE); if (m_processMsg != null) return false; // Close Not delivered Qty - SO/PO MDDOrderLine[] lines = getLines(true, "M_Product_ID"); for (int i = 0; i < lines.length; i++) { MDDOrderLine line = lines[i]; BigDecimal old = line.getQtyOrdered(); if (old.compareTo(line.getQtyDelivered()) != 0) { line.setQtyOrdered(line.getQtyDelivered()); // QtyEntered unchanged line.addDescription("Close (" + old + ")"); line.saveEx(get_TrxName()); } } // Clear Reservations reserveStock(lines); setProcessed(true); setDocAction(DOCACTION_None); // After Close m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_AFTER_CLOSE); if (m_processMsg != null) return false; return true; } // closeIt /** * Reverse Correction - same void * @return true if success */ public boolean reverseCorrectIt() { if (log.isLoggable(Level.INFO)) log.info(toString()); // Before reverseCorrect m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_BEFORE_REVERSECORRECT); if (m_processMsg != null) return false; // After reverseCorrect m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_AFTER_REVERSECORRECT); if (m_processMsg != null) return false; return voidIt(); } // reverseCorrectionIt /** * Reverse Accrual - none * @return false */ public boolean reverseAccrualIt() { if (log.isLoggable(Level.INFO)) log.info(toString()); // Before reverseAccrual m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_BEFORE_REVERSEACCRUAL); if (m_processMsg != null) return false; // After reverseAccrual m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_AFTER_REVERSEACCRUAL); if (m_processMsg != null) return false; return false; } // reverseAccrualIt /** * Re-activate. * @return true if success */ public boolean reActivateIt() { if (log.isLoggable(Level.INFO)) log.info(toString()); // Before reActivate m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_BEFORE_REACTIVATE); if (m_processMsg != null) return false; // After reActivate m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_AFTER_REACTIVATE); if (m_processMsg != null) return false; setDocAction(DOCACTION_Complete); setProcessed(false); return true; } // reActivateIt /************************************************************************* * Get Summary * @return Summary of Document */ public String getSummary() { StringBuilder sb = new StringBuilder(); sb.append(getDocumentNo()); if (m_lines != null) sb.append(" (#").append(m_lines.length).append(")"); // - Description if (getDescription() != null && getDescription().length() > 0) sb.append(" - ").append(getDescription()); return sb.toString(); } // getSummary /** * Get Process Message * @return clear text error message */ public String getProcessMsg() { return m_processMsg; } // getProcessMsg /** * Get Document Owner (Responsible) * @return AD_User_ID */ public int getDoc_User_ID() { return getSalesRep_ID(); } // getDoc_User_ID public BigDecimal getApprovalAmt() { // TODO Auto-generated method stub return null; } public int getC_Currency_ID() { // TODO Auto-generated method stub return 0; } /** * Document Status is Complete or Closed * @return true if CO, CL or RE */ public boolean isComplete() { String ds = getDocStatus(); return DOCSTATUS_Completed.equals(ds) || DOCSTATUS_Closed.equals(ds) || DOCSTATUS_Reversed.equals(ds); } // isComplete } // MDDOrder