/******************************************************************************
* 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