diff --git a/base/src/org/compiere/model/MInOut.java b/base/src/org/compiere/model/MInOut.java
index 0a98c9e6d3..264f74fa57 100644
--- a/base/src/org/compiere/model/MInOut.java
+++ b/base/src/org/compiere/model/MInOut.java
@@ -1654,7 +1654,6 @@ public class MInOut extends X_M_InOut implements DocAction
boolean needSave = false;
- BigDecimal qtyASI = Env.ZERO ;
MProduct product = line.getProduct();
@@ -1694,65 +1693,12 @@ public class MInOut extends X_M_InOut implements DocAction
else if(getMovementType().compareTo(MInOut.MOVEMENTTYPE_VendorReturns) == 0 || getMovementType().compareTo(MInOut.MOVEMENTTYPE_CustomerShipment) == 0)
{
String MMPolicy = product.getMMPolicy();
- MStorage[] storages = MStorage.getAllWithASI(getCtx(),
- line.getM_Product_ID(), line.getM_Locator_ID(),
- MClient.MMPOLICY_FiFo.equals(MMPolicy), get_TrxName());
+ Timestamp minGuaranteeDate = getMovementDate();
+ MStorage[] storages = MStorage.getWarehouse(getCtx(), getM_Warehouse_ID(), line.getM_Product_ID(), line.getM_AttributeSetInstance_ID(),
+ minGuaranteeDate, MClient.MMPOLICY_FiFo.equals(MMPolicy), true, line.getM_Locator_ID(), get_TrxName());
BigDecimal qtyToDeliver = line.getMovementQty();
- /*for (int ii = 0; ii < storages.length; ii++)
- {
- MStorage storage = storages[ii];
- if (ii == 0)
- {
- if (storage.getQtyOnHand().compareTo(qtyToDeliver) >= 0)
- {
- line.setM_AttributeSetInstance_ID(storage.getM_AttributeSetInstance_ID());
- needSave = true;
- log.config("Direct - " + line);
- qtyToDeliver = Env.ZERO;
- }
- else
- {
- log.config("Split - " + line);
- MInOutLineMA ma = new MInOutLineMA (line,
- storage.getM_AttributeSetInstance_ID(),
- storage.getQtyOnHand());
- if (!ma.save())
- ;
- qtyToDeliver = qtyToDeliver.subtract(storage.getQtyOnHand());
- log.fine("#" + ii + ": " + ma + ", QtyToDeliver=" + qtyToDeliver);
- }
- }
- else // create addl material allocation
- {
- MInOutLineMA ma = new MInOutLineMA (line,
- storage.getM_AttributeSetInstance_ID(),
- qtyToDeliver);
- if (storage.getQtyOnHand().compareTo(qtyToDeliver) >= 0)
- qtyToDeliver = Env.ZERO;
- else
- {
- ma.setMovementQty(storage.getQtyOnHand());
- qtyToDeliver = qtyToDeliver.subtract(storage.getQtyOnHand());
- }
- if (!ma.save())
- ;
- log.fine("#" + ii + ": " + ma + ", QtyToDeliver=" + qtyToDeliver);
- }
- if (qtyToDeliver.signum() == 0)
- break;
- } // for all storages
- */
-
for (MStorage storage: storages)
{
- //consume ASI Zero
- if (storage.getM_AttributeSetInstance_ID() == 0)
- {
- qtyASI = qtyASI.add(storage.getQtyOnHand());
- qtyToDeliver = qtyToDeliver.subtract(storage.getQtyOnHand());
- continue;
- }
-
if (storage.getQtyOnHand().compareTo(qtyToDeliver) >= 0)
{
MInOutLineMA ma = new MInOutLineMA (line,
@@ -1779,11 +1725,11 @@ public class MInOut extends X_M_InOut implements DocAction
}
// No AttributeSetInstance found for remainder
- if (qtyToDeliver.signum() != 0 || qtyASI.signum() != 0)
+ if (qtyToDeliver.signum() != 0)
{
- MInOutLineMA ma = new MInOutLineMA (line, 0, qtyToDeliver.add(qtyASI));
+ MInOutLineMA ma = new MInOutLineMA (line, 0, qtyToDeliver);
if (!ma.save())
- ;
+ throw new IllegalStateException("Error try create ASI Reservation");
log.fine("##: " + ma);
}
} // outgoing Trx
diff --git a/base/src/org/compiere/model/MInventory.java b/base/src/org/compiere/model/MInventory.java
index 7bc335ba1f..b2ec362981 100644
--- a/base/src/org/compiere/model/MInventory.java
+++ b/base/src/org/compiere/model/MInventory.java
@@ -1,1012 +1,929 @@
-/******************************************************************************
- * 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;
+/******************************************************************************
+ * 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.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.Properties;
+import java.util.logging.Level;
+
+import org.compiere.process.DocAction;
+import org.compiere.process.DocumentEngine;
+import org.compiere.util.CCache;
+import org.compiere.util.DB;
+import org.compiere.util.Env;
+import org.compiere.util.Msg;
+
+/**
+ * Physical Inventory Model
+ *
+ * @author Jorg Janke
+ * @version $Id: MInventory.java,v 1.3 2006/07/30 00:51:05 jjanke Exp $
+ * @author victor.perez@e-evolution.com, e-Evolution
+ *
FR [ 1948157 ] Is necessary the reference for document reverse
+ * @author Armen Rizal, Goodwill Consulting
+ * BF [ 1745154 ] Cost in Reversing Material Related Docs
+ * @see http://sourceforge.net/tracker/?func=detail&atid=879335&aid=1948157&group_id=176962
+ */
+public class MInventory extends X_M_Inventory implements DocAction
+{
+ /**
+ * Get Inventory from Cache
+ * @param ctx context
+ * @param M_Inventory_ID id
+ * @return MInventory
+ */
+ public static MInventory get (Properties ctx, int M_Inventory_ID)
+ {
+ Integer key = new Integer (M_Inventory_ID);
+ MInventory retValue = (MInventory) s_cache.get (key);
+ if (retValue != null)
+ return retValue;
+ retValue = new MInventory (ctx, M_Inventory_ID, null);
+ if (retValue.get_ID () != 0)
+ s_cache.put (key, retValue);
+ return retValue;
+ } // get
+
+ /** Cache */
+ private static CCache s_cache = new CCache("M_Inventory", 5, 5);
+
+
+ /**
+ * Standard Constructor
+ * @param ctx context
+ * @param M_Inventory_ID id
+ * @param trxName transaction
+ */
+ public MInventory (Properties ctx, int M_Inventory_ID, String trxName)
+ {
+ super (ctx, M_Inventory_ID, trxName);
+ if (M_Inventory_ID == 0)
+ {
+ // setName (null);
+ // setM_Warehouse_ID (0); // FK
+ setMovementDate (new Timestamp(System.currentTimeMillis()));
+ setDocAction (DOCACTION_Complete); // CO
+ setDocStatus (DOCSTATUS_Drafted); // DR
+ setIsApproved (false);
+ setMovementDate (new Timestamp(System.currentTimeMillis())); // @#Date@
+ setPosted (false);
+ setProcessed (false);
+ }
+ } // MInventory
+
+ /**
+ * Load Constructor
+ * @param ctx context
+ * @param rs result set
+ * @param trxName transaction
+ */
+ public MInventory (Properties ctx, ResultSet rs, String trxName)
+ {
+ super(ctx, rs, trxName);
+ } // MInventory
+
+ /**
+ * Warehouse Constructor
+ * @param wh warehouse
+ */
+ public MInventory (MWarehouse wh)
+ {
+ this (wh.getCtx(), 0, wh.get_TrxName());
+ setClientOrg(wh);
+ setM_Warehouse_ID(wh.getM_Warehouse_ID());
+ } // MInventory
+
+
+ /** Lines */
+ private MInventoryLine[] m_lines = null;
+
+ /**
+ * Get Lines
+ * @param requery requery
+ * @return array of lines
+ */
+ public MInventoryLine[] getLines (boolean requery)
+ {
+ if (m_lines != null && !requery) {
+ set_TrxName(m_lines, get_TrxName());
+ return m_lines;
+ }
+ //
+ ArrayList list = new ArrayList();
+ String sql = "SELECT * FROM M_InventoryLine WHERE M_Inventory_ID=? ORDER BY Line";
+ PreparedStatement pstmt = null;
+ ResultSet rs = null;
+ try
+ {
+ pstmt = DB.prepareStatement (sql, get_TrxName());
+ pstmt.setInt (1, getM_Inventory_ID());
+ rs = pstmt.executeQuery ();
+ while (rs.next ())
+ list.add (new MInventoryLine (getCtx(), rs, get_TrxName()));
+ }
+ catch (Exception e)
+ {
+ log.log(Level.SEVERE, sql, e);
+ }
+ finally
+ {
+ DB.close(rs, pstmt);
+ rs = null; pstmt = null;
+ }
+
+ m_lines = new MInventoryLine[list.size ()];
+ list.toArray (m_lines);
+ return m_lines;
+ } // getLines
+
+ /**
+ * Add to Description
+ * @param description text
+ */
+ public void addDescription (String description)
+ {
+ String desc = getDescription();
+ if (desc == null)
+ setDescription(description);
+ else
+ setDescription(desc + " | " + description);
+ } // addDescription
+
+ /**
+ * Overwrite Client/Org - from Import.
+ * @param AD_Client_ID client
+ * @param AD_Org_ID org
+ */
+ public void setClientOrg (int AD_Client_ID, int AD_Org_ID)
+ {
+ super.setClientOrg(AD_Client_ID, AD_Org_ID);
+ } // setClientOrg
+
+ /**
+ * String Representation
+ * @return info
+ */
+ public String toString ()
+ {
+ StringBuffer sb = new StringBuffer ("MInventory[");
+ sb.append (get_ID())
+ .append ("-").append (getDocumentNo())
+ .append (",M_Warehouse_ID=").append(getM_Warehouse_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.getName() + " " + 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.INVOICE, getC_Invoice_ID());
+ // if (re == null)
+ return null;
+ // return re.getPDF(file);
+ } // createPDF
+
+
+ /**
+ * Before Save
+ * @param newRecord new
+ * @return true
+ */
+ protected boolean beforeSave (boolean newRecord)
+ {
+ if (getC_DocType_ID() == 0)
+ {
+ MDocType types[] = MDocType.getOfDocBaseType(getCtx(), MDocType.DOCBASETYPE_MaterialPhysicalInventory);
+ if (types.length > 0) // get first
+ setC_DocType_ID(types[0].getC_DocType_ID());
+ else
+ {
+ log.saveError("Error", Msg.parseTranslation(getCtx(), "@NotFound@ @C_DocType_ID@"));
+ return false;
+ }
+ }
+ return true;
+ } // beforeSave
+
+
+ /**
+ * Set Processed.
+ * Propergate to Lines/Taxes
+ * @param processed processed
+ */
+ public void setProcessed (boolean processed)
+ {
+ super.setProcessed (processed);
+ if (get_ID() == 0)
+ return;
+ String sql = "UPDATE M_InventoryLine SET Processed='"
+ + (processed ? "Y" : "N")
+ + "' WHERE M_Inventory_ID=" + getM_Inventory_ID();
+ int noLine = DB.executeUpdate(sql, get_TrxName());
+ m_lines = null;
+ log.fine("Processed=" + processed + " - Lines=" + noLine);
+ } // setProcessed
+
+
+ /**************************************************************************
+ * 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()
+ {
+ log.info(toString());
+ setProcessing(false);
+ return true;
+ } // unlockIt
+
+ /**
+ * Invalidate Document
+ * @return true if success
+ */
+ public boolean invalidateIt()
+ {
+ log.info(toString());
+ setDocAction(DOCACTION_Prepare);
+ return true;
+ } // invalidateIt
+
+ /**
+ * Prepare Document
+ * @return new status (In Progress or Invalid)
+ */
+ public String prepareIt()
+ {
+ log.info(toString());
+ m_processMsg = ModelValidationEngine.get().fireDocValidate(this, ModelValidator.TIMING_BEFORE_PREPARE);
+ if (m_processMsg != null)
+ return DocAction.STATUS_Invalid;
+
+ // Std Period open?
+ if (!MPeriod.isOpen(getCtx(), getMovementDate(), MDocType.DOCBASETYPE_MaterialPhysicalInventory))
+ {
+ m_processMsg = "@PeriodClosed@";
+ return DocAction.STATUS_Invalid;
+ }
+ MInventoryLine[] lines = getLines(false);
+ if (lines.length == 0)
+ {
+ m_processMsg = "@NoLines@";
+ return DocAction.STATUS_Invalid;
+ }
+
+ // TODO: Add up Amounts
+ // setApprovalAmt();
+
+ m_processMsg = ModelValidationEngine.get().fireDocValidate(this, ModelValidator.TIMING_AFTER_PREPARE);
+ if (m_processMsg != null)
+ return DocAction.STATUS_Invalid;
+
+ m_justPrepared = true;
+ if (!DOCACTION_Complete.equals(getDocAction()))
+ setDocAction(DOCACTION_Complete);
+ return DocAction.STATUS_InProgress;
+ } // prepareIt
+
+ /**
+ * Approve Document
+ * @return true if success
+ */
+ public boolean approveIt()
+ {
+ log.info(toString());
+ setIsApproved(true);
+ return true;
+ } // approveIt
+
+ /**
+ * Reject Approval
+ * @return true if success
+ */
+ public boolean rejectIt()
+ {
+ log.info(toString());
+ setIsApproved(false);
+ return true;
+ } // rejectIt
+
+ /**
+ * Complete Document
+ * @return new status (Complete, In Progress, Invalid, Waiting ..)
+ */
+ public String completeIt()
+ {
+ // Re-Check
+ if (!m_justPrepared)
+ {
+ String status = prepareIt();
+ 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();
+ log.info(toString());
+
+ MInventoryLine[] lines = getLines(false);
+ for (MInventoryLine line : lines)
+ {
+ if (!line.isActive())
+ continue;
+
+ MProduct product = line.getProduct();
+
+ //Get Quantity to Inventory Inernal Use
+ BigDecimal qtyDiff = line.getQtyInternalUse().negate();
+ //If Quantity to Inventory Internal Use = Zero Then is Physical Inventory Else is Inventory Internal Use
+ if (qtyDiff.signum() == 0)
+ qtyDiff = line.getQtyCount().subtract(line.getQtyBook());
+
+ //Ignore the Material Policy when is Reverse Correction
+ if(!isReversal())
+ checkMaterialPolicy(line, qtyDiff);
+
+ // Stock Movement - Counterpart MOrder.reserveStock
+ if (product != null
+ && product.isStocked() )
+ {
+ log.fine("Material Transaction");
+ MTransaction mtrx = null;
+
+ //If AttributeSetInstance = Zero then create new AttributeSetInstance use Inventory Line MA else use current AttributeSetInstance
+ if (line.getM_AttributeSetInstance_ID() == 0 || qtyDiff.compareTo(Env.ZERO) == 0)
+ {
+ MInventoryLineMA mas[] = MInventoryLineMA.get(getCtx(),
+ line.getM_InventoryLine_ID(), get_TrxName());
+
+ for (int j = 0; j < mas.length; j++)
+ {
+ MInventoryLineMA ma = mas[j];
+ BigDecimal QtyMA = ma.getMovementQty();
+ BigDecimal QtyNew = QtyMA.add(qtyDiff);
+ log.fine("Diff=" + qtyDiff
+ + " - Instance OnHand=" + QtyMA + "->" + QtyNew);
+
+ if (!MStorage.add(getCtx(), getM_Warehouse_ID(),
+ line.getM_Locator_ID(),
+ line.getM_Product_ID(),
+ ma.getM_AttributeSetInstance_ID(), 0,
+ QtyMA.negate(), Env.ZERO, Env.ZERO, get_TrxName()))
+ {
+ m_processMsg = "Cannot correct Inventory (MA)";
+ return DocAction.STATUS_Invalid;
+ }
+
+ // Only Update Date Last Inventory if is a Physical Inventory
+ if(line.getQtyInternalUse().compareTo(Env.ZERO) == 0)
+ {
+ MStorage storage = MStorage.get(getCtx(), line.getM_Locator_ID(),
+ line.getM_Product_ID(), ma.getM_AttributeSetInstance_ID(), get_TrxName());
+ storage.setDateLastInventory(getMovementDate());
+ if (!storage.save(get_TrxName()))
+ {
+ m_processMsg = "Storage not updated(2)";
+ return DocAction.STATUS_Invalid;
+ }
+ }
+
+ String m_MovementType =null;
+ if(QtyMA.negate().compareTo(Env.ZERO) > 0 )
+ m_MovementType = MTransaction.MOVEMENTTYPE_InventoryIn;
+ else
+ m_MovementType = MTransaction.MOVEMENTTYPE_InventoryOut;
+ // Transaction
+ mtrx = new MTransaction (getCtx(), line.getAD_Org_ID(), m_MovementType,
+ line.getM_Locator_ID(), line.getM_Product_ID(), ma.getM_AttributeSetInstance_ID(),
+ QtyMA.negate(), getMovementDate(), get_TrxName());
+ mtrx.setM_InventoryLine_ID(line.getM_InventoryLine_ID());
+ if (!mtrx.save())
+ {
+ m_processMsg = "Transaction not inserted(2)";
+ return DocAction.STATUS_Invalid;
+ }
+ qtyDiff = QtyNew;
+ }
+ }
+
+ //sLine.getM_AttributeSetInstance_ID() != 0
+ // Fallback
+ if (mtrx == null)
+ {
+ //Fallback: Update Storage - see also VMatch.createMatchRecord
+ if (!MStorage.add(getCtx(), getM_Warehouse_ID(),
+ line.getM_Locator_ID(),
+ line.getM_Product_ID(),
+ line.getM_AttributeSetInstance_ID(), 0,
+ qtyDiff, Env.ZERO, Env.ZERO, get_TrxName()))
+ {
+ m_processMsg = "Cannot correct Inventory (MA)";
+ return DocAction.STATUS_Invalid;
+ }
+
+ // Only Update Date Last Inventory if is a Physical Inventory
+ if(line.getQtyInternalUse().compareTo(Env.ZERO) == 0)
+ {
+ MStorage storage = MStorage.get(getCtx(), line.getM_Locator_ID(),
+ line.getM_Product_ID(), line.getM_AttributeSetInstance_ID(), get_TrxName());
+
+ storage.setDateLastInventory(getMovementDate());
+ if (!storage.save(get_TrxName()))
+ {
+ m_processMsg = "Storage not updated(2)";
+ return DocAction.STATUS_Invalid;
+ }
+ }
+
+ String m_MovementType =null;
+ if(qtyDiff.compareTo(Env.ZERO) > 0 )
+ m_MovementType = MTransaction.MOVEMENTTYPE_InventoryIn;
+ else
+ m_MovementType = MTransaction.MOVEMENTTYPE_InventoryOut;
+ // Transaction
+ mtrx = new MTransaction (getCtx(), line.getAD_Org_ID(), m_MovementType,
+ line.getM_Locator_ID(), line.getM_Product_ID(), line.getM_AttributeSetInstance_ID(),
+ qtyDiff, getMovementDate(), get_TrxName());
+ mtrx.setM_InventoryLine_ID(line.getM_InventoryLine_ID());
+ if (!mtrx.save())
+ {
+ m_processMsg = "Transaction not inserted(2)";
+ return DocAction.STATUS_Invalid;
+ }
+ } // Fallback
+ } // stock movement
+
+
+ } // for all lines
+
+ // User Validation
+ String valid = ModelValidationEngine.get().fireDocValidate(this, ModelValidator.TIMING_AFTER_COMPLETE);
+ if (valid != null)
+ {
+ m_processMsg = valid;
+ return DocAction.STATUS_Invalid;
+ }
+
+ // Set the definite document number after completed (if needed)
+ setDefiniteDocumentNo();
+
+ //
+ setProcessed(true);
+ setDocAction(DOCACTION_Close);
+ return DocAction.STATUS_Completed;
+ } // completeIt
+
+ /**
+ * Set the definite document number after completed
+ */
+ private void setDefiniteDocumentNo() {
+ MDocType dt = MDocType.get(getCtx(), getC_DocType_ID());
+ if (dt.isOverwriteDateOnComplete()) {
+ setMovementDate(new Timestamp (System.currentTimeMillis()));
+ }
+ if (dt.isOverwriteSeqOnComplete()) {
+ String value = DB.getDocumentNo(getC_DocType_ID(), get_TrxName(), true, this);
+ if (value != null)
+ setDocumentNo(value);
+ }
+ }
+
+ /**
+ * Check Material Policy.
+ * (NOT USED)
+ * Sets line ASI
+ */
+ private void checkMaterialPolicy(MInventoryLine line, BigDecimal qtyDiff)
+ {
+ int no = MInventoryLineMA.deleteInventoryMA(line.getM_InventoryLine_ID(), get_TrxName());
+ if (no > 0)
+ log.config("Delete old #" + no);
+
+
+ // Check Line
+ boolean needSave = false;
+ // Attribute Set Instance
+ if (line.getM_AttributeSetInstance_ID() == 0)
+ {
+ MProduct product = MProduct.get(getCtx(), line.getM_Product_ID());
+ if (qtyDiff.signum() > 0) // Incoming Trx
+ {
+ MAttributeSetInstance asi = new MAttributeSetInstance(getCtx(), 0, get_TrxName());
+ asi.setClientOrg(getAD_Client_ID(), 0);
+ asi.setM_AttributeSet_ID(product.getM_AttributeSet_ID());
+ if (!asi.save())
+ {
+ throw new IllegalStateException("Error try create ASI Reservation");
+ }
+ if (asi.save())
+ {
+ line.setM_AttributeSetInstance_ID(asi.getM_AttributeSetInstance_ID());
+ needSave = true;
+ }
+ }
+ else // Outgoing Trx
+ {
+ String MMPolicy = product.getMMPolicy();
+ MStorage[] storages = MStorage.getWarehouse(getCtx(), getM_Warehouse_ID(), line.getM_Product_ID(), 0,
+ null, MClient.MMPOLICY_FiFo.equals(MMPolicy), true, line.getM_Locator_ID(), get_TrxName());
+ BigDecimal qtyToDeliver = qtyDiff.negate();
+
+ for (MStorage storage: storages)
+ {
+ if (storage.getQtyOnHand().compareTo(qtyToDeliver) >= 0)
+ {
+ MInventoryLineMA ma = new MInventoryLineMA (line,
+ storage.getM_AttributeSetInstance_ID(),
+ qtyToDeliver);
+ if (!ma.save())
+ {
+ throw new IllegalStateException("Error try create ASI Reservation");
+ }
+ qtyToDeliver = Env.ZERO;
+ log.fine( ma + ", QtyToDeliver=" + qtyToDeliver);
+ //return;
+ }
+ else
+ {
+ MInventoryLineMA ma = new MInventoryLineMA (line,
+ storage.getM_AttributeSetInstance_ID(),
+ storage.getQtyOnHand());
+ if (!ma.save())
+ {
+ throw new IllegalStateException("Error try create ASI Reservation");
+ }
+ qtyToDeliver = qtyToDeliver.subtract(storage.getQtyOnHand());
+ log.fine( ma + ", QtyToDeliver=" + qtyToDeliver);
+ }
+ }
+
+ // No AttributeSetInstance found for remainder
+ if (qtyToDeliver.signum() != 0)
+ {
+ MInventoryLineMA ma = new MInventoryLineMA (line, 0 , qtyToDeliver);
+
+ if (!ma.save())
+ throw new IllegalStateException("Error try create ASI Reservation");
+ log.fine("##: " + ma);
+ }
+ } // outgoing Trx
+
+ if (needSave && !line.save())
+ log.severe("NOT saved " + line);
+ } // for all lines
+
+ } // checkMaterialPolicy
+
+ /**
+ * Void Document.
+ * @return false
+ */
+ public boolean voidIt()
+ {
+ log.info(toString());
+ // Before Void
+ m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_BEFORE_VOID);
+ if (m_processMsg != null)
+ return false;
+
+ if (DOCSTATUS_Closed.equals(getDocStatus())
+ || DOCSTATUS_Reversed.equals(getDocStatus())
+ || DOCSTATUS_Voided.equals(getDocStatus()))
+ {
+ m_processMsg = "Document Closed: " + getDocStatus();
+ return false;
+ }
+
+ // Not Processed
+ if (DOCSTATUS_Drafted.equals(getDocStatus())
+ || DOCSTATUS_Invalid.equals(getDocStatus())
+ || DOCSTATUS_InProgress.equals(getDocStatus())
+ || DOCSTATUS_Approved.equals(getDocStatus())
+ || DOCSTATUS_NotApproved.equals(getDocStatus()) )
+ {
+ // Set lines to 0
+ MInventoryLine[] lines = getLines(false);
+ for (int i = 0; i < lines.length; i++)
+ {
+ MInventoryLine line = lines[i];
+ BigDecimal oldCount = line.getQtyCount();
+ BigDecimal oldInternal = line.getQtyInternalUse();
+ if (oldCount.compareTo(line.getQtyBook()) != 0
+ || oldInternal.signum() != 0)
+ {
+ line.setQtyInternalUse(Env.ZERO);
+ line.setQtyCount(line.getQtyBook());
+ line.addDescription("Void (" + oldCount + "/" + oldInternal + ")");
+ line.save(get_TrxName());
+ }
+ }
+ }
+ else
+ {
+ return reverseCorrectIt();
+ }
+
+ // 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
+
+ /**
+ * Close Document.
+ * @return true if success
+ */
+ public boolean closeIt()
+ {
+ log.info(toString());
+ // Before Close
+ m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_BEFORE_CLOSE);
+ if (m_processMsg != null)
+ return false;
+ // After Close
+ m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_AFTER_CLOSE);
+ if (m_processMsg != null)
+ return false;
+
+ setDocAction(DOCACTION_None);
+ return true;
+ } // closeIt
+
+ /**
+ * Reverse Correction
+ * @return false
+ */
+ public boolean reverseCorrectIt()
+ {
+ log.info(toString());
+ // Before reverseCorrect
+ m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_BEFORE_REVERSECORRECT);
+ if (m_processMsg != null)
+ return false;
+
+ MDocType dt = MDocType.get(getCtx(), getC_DocType_ID());
+ if (!MPeriod.isOpen(getCtx(), getMovementDate(), dt.getDocBaseType()))
+ {
+ m_processMsg = "@PeriodClosed@";
+ return false;
+ }
+
+ // Deep Copy
+ MInventory reversal = new MInventory(getCtx(), 0, get_TrxName());
+ copyValues(this, reversal, getAD_Client_ID(), getAD_Org_ID());
+ reversal.setDocStatus(DOCSTATUS_Drafted);
+ reversal.setDocAction(DOCACTION_Complete);
+ reversal.setIsApproved (false);
+ reversal.setPosted(false);
+ reversal.setProcessed(false);
+ reversal.addDescription("{->" + getDocumentNo() + ")");
+ if (!reversal.save())
+ {
+ m_processMsg = "Could not create Inventory Reversal";
+ return false;
+ }
+ reversal.setReversal(true);
+
+ // Reverse Line Qty
+ MInventoryLine[] oLines = getLines(true);
+ for (int i = 0; i < oLines.length; i++)
+ {
+ MInventoryLine oLine = oLines[i];
+ MInventoryLine rLine = new MInventoryLine(getCtx(), 0, get_TrxName());
+ copyValues(oLine, rLine, oLine.getAD_Client_ID(), oLine.getAD_Org_ID());
+ rLine.setM_Inventory_ID(reversal.getM_Inventory_ID());
+ rLine.setParent(reversal);
+ rLine.setQtyBook (oLine.getQtyCount()); // switch
+ rLine.setQtyCount (oLine.getQtyBook());
+ rLine.setQtyInternalUse (oLine.getQtyInternalUse().negate());
+
+ if (!rLine.save())
+ {
+ m_processMsg = "Could not create Inventory Reversal Line";
+ return false;
+ }
+
+ //We need to copy MA
+ if (rLine.getM_AttributeSetInstance_ID() == 0)
+ {
+ MInventoryLineMA mas[] = MInventoryLineMA.get(getCtx(),
+ oLines[i].getM_InventoryLine_ID(), get_TrxName());
+ for (int j = 0; j < mas.length; j++)
+ {
+ MInventoryLineMA ma = new MInventoryLineMA (rLine,
+ mas[j].getM_AttributeSetInstance_ID(),
+ mas[j].getMovementQty().negate());
+ if (!ma.save())
+ throw new IllegalStateException("Error try create ASI Reservation");
+ }
+ }
+ }
+ //
+ if (!reversal.processIt(DocAction.ACTION_Complete))
+ {
+ m_processMsg = "Reversal ERROR: " + reversal.getProcessMsg();
+ return false;
+ }
+ reversal.closeIt();
+ reversal.setDocStatus(DOCSTATUS_Reversed);
+ reversal.setDocAction(DOCACTION_None);
+ reversal.save();
+ m_processMsg = reversal.getDocumentNo();
+
+ // Update Reversed (this)
+ addDescription("(" + reversal.getDocumentNo() + "<-)");
+ // After reverseCorrect
+ m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_AFTER_REVERSECORRECT);
+ if (m_processMsg != null)
+ return false;
+ setProcessed(true);
+ setDocStatus(DOCSTATUS_Reversed); // may come from void
+ setDocAction(DOCACTION_None);
+
+ return true;
+ } // reverseCorrectIt
+
+ /**
+ * Reverse Accrual
+ * @return false
+ */
+ public boolean reverseAccrualIt()
+ {
+ 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 false
+ */
+ public boolean reActivateIt()
+ {
+ 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;
+
+ return false;
+ } // reActivateIt
+
+
+ /*************************************************************************
+ * Get Summary
+ * @return Summary of Document
+ */
+ public String getSummary()
+ {
+ StringBuffer sb = new StringBuffer();
+ sb.append(getDocumentNo());
+ // : Total Lines = 123.00 (#1)
+ sb.append(": ")
+ .append(Msg.translate(getCtx(),"ApprovalAmt")).append("=").append(getApprovalAmt())
+ .append(" (#").append(getLines(false).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 getUpdatedBy();
+ } // getDoc_User_ID
+
+ /**
+ * Get Document Currency
+ * @return C_Currency_ID
+ */
+ public int getC_Currency_ID()
+ {
+ // MPriceList pl = MPriceList.get(getCtx(), getM_PriceList_ID());
+ // return pl.getC_Currency_ID();
+ return 0;
+ } // getC_Currency_ID
+
+ /** Reversal Flag */
+ private boolean m_reversal = false;
+
+ /**
+ * Set Reversal
+ * @param reversal reversal
+ */
+ private void setReversal(boolean reversal)
+ {
+ m_reversal = reversal;
+ } // setReversal
+ /**
+ * Is Reversal
+ * @return reversal
+ */
+ private boolean isReversal()
+ {
+ return m_reversal;
+ } // isReversal
+
+} // MInventory
-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.Properties;
-import java.util.logging.Level;
-
-import org.compiere.process.DocAction;
-import org.compiere.process.DocumentEngine;
-import org.compiere.report.MReportTree;
-import org.compiere.util.CCache;
-import org.compiere.util.DB;
-import org.compiere.util.Env;
-import org.compiere.util.Msg;
-
-/**
- * Physical Inventory Model
- *
- * @author Jorg Janke
- * @version $Id: MInventory.java,v 1.3 2006/07/30 00:51:05 jjanke Exp $
- * @author victor.perez@e-evolution.com, e-Evolution http://www.e-evolution.com
- * FR [ 1948157 ] Is necessary the reference for document reverse
- * FR [ 2520591 ] Support multiples calendar for Org
- * @see http://sourceforge.net/tracker2/?func=detail&atid=879335&aid=2520591&group_id=176962
- * @author Armen Rizal, Goodwill Consulting
- * BF [ 1745154 ] Cost in Reversing Material Related Docs
- * @see http://sourceforge.net/tracker/?func=detail&atid=879335&aid=1948157&group_id=176962
- */
-public class MInventory extends X_M_Inventory implements DocAction
-{
- /**
- * Get Inventory from Cache
- * @param ctx context
- * @param M_Inventory_ID id
- * @return MInventory
- */
- public static MInventory get (Properties ctx, int M_Inventory_ID)
- {
- Integer key = new Integer (M_Inventory_ID);
- MInventory retValue = (MInventory) s_cache.get (key);
- if (retValue != null)
- return retValue;
- retValue = new MInventory (ctx, M_Inventory_ID, null);
- if (retValue.get_ID () != 0)
- s_cache.put (key, retValue);
- return retValue;
- } // get
-
- /** Cache */
- private static CCache s_cache = new CCache("M_Inventory", 5, 5);
-
-
- /**
- * Standard Constructor
- * @param ctx context
- * @param M_Inventory_ID id
- * @param trxName transaction
- */
- public MInventory (Properties ctx, int M_Inventory_ID, String trxName)
- {
- super (ctx, M_Inventory_ID, trxName);
- if (M_Inventory_ID == 0)
- {
- // setName (null);
- // setM_Warehouse_ID (0); // FK
- setMovementDate (new Timestamp(System.currentTimeMillis()));
- setDocAction (DOCACTION_Complete); // CO
- setDocStatus (DOCSTATUS_Drafted); // DR
- setIsApproved (false);
- setMovementDate (new Timestamp(System.currentTimeMillis())); // @#Date@
- setPosted (false);
- setProcessed (false);
- }
- } // MInventory
-
- /**
- * Load Constructor
- * @param ctx context
- * @param rs result set
- * @param trxName transaction
- */
- public MInventory (Properties ctx, ResultSet rs, String trxName)
- {
- super(ctx, rs, trxName);
- } // MInventory
-
- /**
- * Warehouse Constructor
- * @param wh warehouse
- */
- public MInventory (MWarehouse wh)
- {
- this (wh.getCtx(), 0, wh.get_TrxName());
- setClientOrg(wh);
- setM_Warehouse_ID(wh.getM_Warehouse_ID());
- } // MInventory
-
-
- /** Lines */
- private MInventoryLine[] m_lines = null;
-
- /**
- * Get Lines
- * @param requery requery
- * @return array of lines
- */
- public MInventoryLine[] getLines (boolean requery)
- {
- if (m_lines != null && !requery) {
- set_TrxName(m_lines, get_TrxName());
- return m_lines;
- }
- //
- ArrayList list = new ArrayList();
- String sql = "SELECT * FROM M_InventoryLine WHERE M_Inventory_ID=? ORDER BY Line";
- PreparedStatement pstmt = null;
- ResultSet rs = null;
- try
- {
- pstmt = DB.prepareStatement (sql, get_TrxName());
- pstmt.setInt (1, getM_Inventory_ID());
- rs = pstmt.executeQuery ();
- while (rs.next ())
- list.add (new MInventoryLine (getCtx(), rs, get_TrxName()));
- }
- catch (Exception e)
- {
- log.log(Level.SEVERE, sql, e);
- }
- finally
- {
- DB.close(rs, pstmt);
- rs = null; pstmt = null;
- }
-
- m_lines = new MInventoryLine[list.size ()];
- list.toArray (m_lines);
- return m_lines;
- } // getLines
-
- /**
- * Add to Description
- * @param description text
- */
- public void addDescription (String description)
- {
- String desc = getDescription();
- if (desc == null)
- setDescription(description);
- else
- setDescription(desc + " | " + description);
- } // addDescription
-
- /**
- * Overwrite Client/Org - from Import.
- * @param AD_Client_ID client
- * @param AD_Org_ID org
- */
- public void setClientOrg (int AD_Client_ID, int AD_Org_ID)
- {
- super.setClientOrg(AD_Client_ID, AD_Org_ID);
- } // setClientOrg
-
- /**
- * String Representation
- * @return info
- */
- public String toString ()
- {
- StringBuffer sb = new StringBuffer ("MInventory[");
- sb.append (get_ID())
- .append ("-").append (getDocumentNo())
- .append (",M_Warehouse_ID=").append(getM_Warehouse_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.getName() + " " + 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.INVOICE, getC_Invoice_ID());
- // if (re == null)
- return null;
- // return re.getPDF(file);
- } // createPDF
-
-
- /**
- * Before Save
- * @param newRecord new
- * @return true
- */
- protected boolean beforeSave (boolean newRecord)
- {
- if (getC_DocType_ID() == 0)
- {
- MDocType types[] = MDocType.getOfDocBaseType(getCtx(), MDocType.DOCBASETYPE_MaterialPhysicalInventory);
- if (types.length > 0) // get first
- setC_DocType_ID(types[0].getC_DocType_ID());
- else
- {
- log.saveError("Error", Msg.parseTranslation(getCtx(), "@NotFound@ @C_DocType_ID@"));
- return false;
- }
- }
- return true;
- } // beforeSave
-
-
- /**
- * Set Processed.
- * Propergate to Lines/Taxes
- * @param processed processed
- */
- public void setProcessed (boolean processed)
- {
- super.setProcessed (processed);
- if (get_ID() == 0)
- return;
- String sql = "UPDATE M_InventoryLine SET Processed='"
- + (processed ? "Y" : "N")
- + "' WHERE M_Inventory_ID=" + getM_Inventory_ID();
- int noLine = DB.executeUpdate(sql, get_TrxName());
- m_lines = null;
- log.fine("Processed=" + processed + " - Lines=" + noLine);
- } // setProcessed
-
-
- /**************************************************************************
- * 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()
- {
- log.info(toString());
- setProcessing(false);
- return true;
- } // unlockIt
-
- /**
- * Invalidate Document
- * @return true if success
- */
- public boolean invalidateIt()
- {
- log.info(toString());
- setDocAction(DOCACTION_Prepare);
- return true;
- } // invalidateIt
-
- /**
- * Prepare Document
- * @return new status (In Progress or Invalid)
- */
- public String prepareIt()
- {
- log.info(toString());
- m_processMsg = ModelValidationEngine.get().fireDocValidate(this, ModelValidator.TIMING_BEFORE_PREPARE);
- if (m_processMsg != null)
- return DocAction.STATUS_Invalid;
-
- // Std Period open?
- if (!MPeriod.isOpen(getCtx(), getMovementDate(), MDocType.DOCBASETYPE_MaterialPhysicalInventory, getAD_Org_ID()))
- {
- m_processMsg = "@PeriodClosed@";
- return DocAction.STATUS_Invalid;
- }
- MInventoryLine[] lines = getLines(false);
- if (lines.length == 0)
- {
- m_processMsg = "@NoLines@";
- return DocAction.STATUS_Invalid;
- }
-
- // TODO: Add up Amounts
- // setApprovalAmt();
-
- m_processMsg = ModelValidationEngine.get().fireDocValidate(this, ModelValidator.TIMING_AFTER_PREPARE);
- if (m_processMsg != null)
- return DocAction.STATUS_Invalid;
-
- m_justPrepared = true;
- if (!DOCACTION_Complete.equals(getDocAction()))
- setDocAction(DOCACTION_Complete);
- return DocAction.STATUS_InProgress;
- } // prepareIt
-
- /**
- * Approve Document
- * @return true if success
- */
- public boolean approveIt()
- {
- log.info(toString());
- setIsApproved(true);
- return true;
- } // approveIt
-
- /**
- * Reject Approval
- * @return true if success
- */
- public boolean rejectIt()
- {
- log.info(toString());
- setIsApproved(false);
- return true;
- } // rejectIt
-
- /**
- * Complete Document
- * @return new status (Complete, In Progress, Invalid, Waiting ..)
- */
- public String completeIt()
- {
- // Re-Check
- if (!m_justPrepared)
- {
- String status = prepareIt();
- 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();
- log.info(toString());
-
- MInventoryLine[] lines = getLines(false);
- for (MInventoryLine line : lines)
- {
- if (!line.isActive())
- continue;
-
- MProduct product = line.getProduct();
-
- //Get Quantity to Inventory Inernal Use
- BigDecimal qtyDiff = line.getQtyInternalUse().negate();
- //If Quantity to Inventory Internal Use = Zero Then is Physical Inventory Else is Inventory Internal Use
- if (qtyDiff.signum() == 0)
- qtyDiff = line.getQtyCount().subtract(line.getQtyBook());
-
- //Ignore the Material Policy when is Reverse Correction
- if(!isReversal())
- checkMaterialPolicy(line, qtyDiff);
-
- // Stock Movement - Counterpart MOrder.reserveStock
- if (product != null
- && product.isStocked() )
- {
- log.fine("Material Transaction");
- MTransaction mtrx = null;
-
- //If AttributeSetInstance = Zero then create new AttributeSetInstance use Inventory Line MA else use current AttributeSetInstance
- if (line.getM_AttributeSetInstance_ID() == 0 || qtyDiff.compareTo(Env.ZERO) == 0)
- {
- MInventoryLineMA mas[] = MInventoryLineMA.get(getCtx(),
- line.getM_InventoryLine_ID(), get_TrxName());
-
- for (int j = 0; j < mas.length; j++)
- {
- MInventoryLineMA ma = mas[j];
- BigDecimal QtyMA = ma.getMovementQty();
- BigDecimal QtyNew = QtyMA.add(qtyDiff);
- log.fine("Diff=" + qtyDiff
- + " - Instance OnHand=" + QtyMA + "->" + QtyNew);
-
- if (!MStorage.add(getCtx(), getM_Warehouse_ID(),
- line.getM_Locator_ID(),
- line.getM_Product_ID(),
- ma.getM_AttributeSetInstance_ID(), 0,
- QtyMA.negate(), Env.ZERO, Env.ZERO, get_TrxName()))
- {
- m_processMsg = "Cannot correct Inventory (MA)";
- return DocAction.STATUS_Invalid;
- }
-
- // Only Update Date Last Inventory if is a Physical Inventory
- if(line.getQtyInternalUse().compareTo(Env.ZERO) == 0)
- {
- MStorage storage = MStorage.get(getCtx(), line.getM_Locator_ID(),
- line.getM_Product_ID(), ma.getM_AttributeSetInstance_ID(), get_TrxName());
- storage.setDateLastInventory(getMovementDate());
- if (!storage.save(get_TrxName()))
- {
- m_processMsg = "Storage not updated(2)";
- return DocAction.STATUS_Invalid;
- }
- }
-
- String m_MovementType =null;
- if(QtyMA.negate().compareTo(Env.ZERO) > 0 )
- m_MovementType = MTransaction.MOVEMENTTYPE_InventoryIn;
- else
- m_MovementType = MTransaction.MOVEMENTTYPE_InventoryOut;
- // Transaction
- mtrx = new MTransaction (getCtx(), line.getAD_Org_ID(), m_MovementType,
- line.getM_Locator_ID(), line.getM_Product_ID(), ma.getM_AttributeSetInstance_ID(),
- QtyMA.negate(), getMovementDate(), get_TrxName());
-
- mtrx.setM_InventoryLine_ID(line.getM_InventoryLine_ID());
- if (!mtrx.save())
- {
- m_processMsg = "Transaction not inserted(2)";
- return DocAction.STATUS_Invalid;
- }
- if(QtyMA.signum() != 0)
- {
- String err = createCostDetail(line, ma.getM_AttributeSetInstance_ID() , QtyMA.negate());
- if(err != null && err.length() > 0) return err;
- }
-
- qtyDiff = QtyNew;
-
- }
- }
-
- //sLine.getM_AttributeSetInstance_ID() != 0
- // Fallback
- if (mtrx == null)
- {
- //Fallback: Update Storage - see also VMatch.createMatchRecord
- if (!MStorage.add(getCtx(), getM_Warehouse_ID(),
- line.getM_Locator_ID(),
- line.getM_Product_ID(),
- line.getM_AttributeSetInstance_ID(), 0,
- qtyDiff, Env.ZERO, Env.ZERO, get_TrxName()))
- {
- m_processMsg = "Cannot correct Inventory (MA)";
- return DocAction.STATUS_Invalid;
- }
-
- // Only Update Date Last Inventory if is a Physical Inventory
- if(line.getQtyInternalUse().compareTo(Env.ZERO) == 0)
- {
- MStorage storage = MStorage.get(getCtx(), line.getM_Locator_ID(),
- line.getM_Product_ID(), line.getM_AttributeSetInstance_ID(), get_TrxName());
-
- storage.setDateLastInventory(getMovementDate());
- if (!storage.save(get_TrxName()))
- {
- m_processMsg = "Storage not updated(2)";
- return DocAction.STATUS_Invalid;
- }
- }
-
- String m_MovementType =null;
- if(qtyDiff.compareTo(Env.ZERO) > 0 )
- m_MovementType = MTransaction.MOVEMENTTYPE_InventoryIn;
- else
- m_MovementType = MTransaction.MOVEMENTTYPE_InventoryOut;
- // Transaction
- mtrx = new MTransaction (getCtx(), line.getAD_Org_ID(), m_MovementType,
- line.getM_Locator_ID(), line.getM_Product_ID(), line.getM_AttributeSetInstance_ID(),
- qtyDiff, getMovementDate(), get_TrxName());
- mtrx.setM_InventoryLine_ID(line.getM_InventoryLine_ID());
- if (!mtrx.save())
- {
- m_processMsg = "Transaction not inserted(2)";
- return DocAction.STATUS_Invalid;
- }
-
- if(qtyDiff.signum() != 0)
- {
- String err = createCostDetail(line, line.getM_AttributeSetInstance_ID(), qtyDiff);
- if(err != null && err.length() > 0) return err;
- }
- } // Fallback
- } // stock movement
-
- } // for all lines
-
- // User Validation
- String valid = ModelValidationEngine.get().fireDocValidate(this, ModelValidator.TIMING_AFTER_COMPLETE);
- if (valid != null)
- {
- m_processMsg = valid;
- return DocAction.STATUS_Invalid;
- }
-
- // Set the definite document number after completed (if needed)
- setDefiniteDocumentNo();
-
- //
- setProcessed(true);
- setDocAction(DOCACTION_Close);
- return DocAction.STATUS_Completed;
- } // completeIt
-
- /**
- * Set the definite document number after completed
- */
- private void setDefiniteDocumentNo() {
- MDocType dt = MDocType.get(getCtx(), getC_DocType_ID());
- if (dt.isOverwriteDateOnComplete()) {
- setMovementDate(new Timestamp (System.currentTimeMillis()));
- }
- if (dt.isOverwriteSeqOnComplete()) {
- String value = DB.getDocumentNo(getC_DocType_ID(), get_TrxName(), true, this);
- if (value != null)
- setDocumentNo(value);
- }
- }
-
- /**
- * Check Material Policy.
- * (NOT USED)
- * Sets line ASI
- */
- private void checkMaterialPolicy(MInventoryLine line, BigDecimal qtyDiff)
- {
- int no = MInventoryLineMA.deleteInventoryMA(line.getM_InventoryLine_ID(), get_TrxName());
- if (no > 0)
- log.config("Delete old #" + no);
-
-
- // Check Line
- boolean needSave = false;
- BigDecimal qtyASI = Env.ZERO ;
- // Attribute Set Instance
- if (line.getM_AttributeSetInstance_ID() == 0)
- {
- MProduct product = MProduct.get(getCtx(), line.getM_Product_ID());
- if (qtyDiff.signum() > 0) // Incoming Trx
- {
- MAttributeSetInstance asi = new MAttributeSetInstance(getCtx(), 0, get_TrxName());
- asi.setClientOrg(getAD_Client_ID(), 0);
- asi.setM_AttributeSet_ID(product.getM_AttributeSet_ID());
- if (!asi.save())
- {
- throw new IllegalStateException("Error try create ASI Reservation");
- }
- if (asi.save())
- {
- line.setM_AttributeSetInstance_ID(asi.getM_AttributeSetInstance_ID());
- needSave = true;
- }
- }
- else // Outgoing Trx
- {
- String MMPolicy = product.getMMPolicy();
- MStorage[] storages = MStorage.getAllWithASI(getCtx(),
- line.getM_Product_ID(), line.getM_Locator_ID(),
- MClient.MMPOLICY_FiFo.equals(MMPolicy), get_TrxName());
- BigDecimal qtyToDeliver = qtyDiff.negate();
-
- for (MStorage storage: storages)
- {
- //cosume ASI Zero
- if (storage.getM_AttributeSetInstance_ID() == 0)
- {
- qtyASI = qtyASI.add(storage.getQtyOnHand());
- qtyToDeliver = qtyToDeliver.subtract(storage.getQtyOnHand());
- continue;
- }
-
- if (storage.getQtyOnHand().compareTo(qtyToDeliver) >= 0)
- {
- MInventoryLineMA ma = new MInventoryLineMA (line,
- storage.getM_AttributeSetInstance_ID(),
- qtyToDeliver);
- if (!ma.save())
- {
- throw new IllegalStateException("Error try create ASI Reservation");
- }
- qtyToDeliver = Env.ZERO;
- log.fine( ma + ", QtyToDeliver=" + qtyToDeliver);
- //return;
- }
- else
- {
- MInventoryLineMA ma = new MInventoryLineMA (line,
- storage.getM_AttributeSetInstance_ID(),
- storage.getQtyOnHand());
- if (!ma.save())
- {
- throw new IllegalStateException("Error try create ASI Reservation");
- }
- qtyToDeliver = qtyToDeliver.subtract(storage.getQtyOnHand());
- log.fine( ma + ", QtyToDeliver=" + qtyToDeliver);
- }
- }
-
- // No AttributeSetInstance found for remainder
- if (qtyToDeliver.signum() != 0 || qtyASI.signum() != 0)
- {
- MInventoryLineMA ma = new MInventoryLineMA (line, 0 , qtyToDeliver.add(qtyASI));
-
- if (!ma.save())
- ;
- log.fine("##: " + ma);
- }
- } // outgoing Trx
-
- if (needSave && !line.save())
- log.severe("NOT saved " + line);
- } // for all lines
-
- } // checkMaterialPolicy
-
- /**
- * Void Document.
- * @return false
- */
- public boolean voidIt()
- {
- log.info(toString());
- // Before Void
- m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_BEFORE_VOID);
- if (m_processMsg != null)
- return false;
-
- if (DOCSTATUS_Closed.equals(getDocStatus())
- || DOCSTATUS_Reversed.equals(getDocStatus())
- || DOCSTATUS_Voided.equals(getDocStatus()))
- {
- m_processMsg = "Document Closed: " + getDocStatus();
- return false;
- }
-
- // Not Processed
- if (DOCSTATUS_Drafted.equals(getDocStatus())
- || DOCSTATUS_Invalid.equals(getDocStatus())
- || DOCSTATUS_InProgress.equals(getDocStatus())
- || DOCSTATUS_Approved.equals(getDocStatus())
- || DOCSTATUS_NotApproved.equals(getDocStatus()) )
- {
- // Set lines to 0
- MInventoryLine[] lines = getLines(false);
- for (int i = 0; i < lines.length; i++)
- {
- MInventoryLine line = lines[i];
- BigDecimal oldCount = line.getQtyCount();
- BigDecimal oldInternal = line.getQtyInternalUse();
- if (oldCount.compareTo(line.getQtyBook()) != 0
- || oldInternal.signum() != 0)
- {
- line.setQtyInternalUse(Env.ZERO);
- line.setQtyCount(line.getQtyBook());
- line.addDescription("Void (" + oldCount + "/" + oldInternal + ")");
- line.save(get_TrxName());
- }
- }
- }
- else
- {
- return reverseCorrectIt();
- }
-
- // 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
-
- /**
- * Close Document.
- * @return true if success
- */
- public boolean closeIt()
- {
- log.info(toString());
- // Before Close
- m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_BEFORE_CLOSE);
- if (m_processMsg != null)
- return false;
- // After Close
- m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_AFTER_CLOSE);
- if (m_processMsg != null)
- return false;
-
- setDocAction(DOCACTION_None);
- return true;
- } // closeIt
-
- /**
- * Reverse Correction
- * @return false
- */
- public boolean reverseCorrectIt()
- {
- log.info(toString());
- // Before reverseCorrect
- m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_BEFORE_REVERSECORRECT);
- if (m_processMsg != null)
- return false;
-
- MDocType dt = MDocType.get(getCtx(), getC_DocType_ID());
- if (!MPeriod.isOpen(getCtx(), getMovementDate(), dt.getDocBaseType(), getAD_Org_ID()))
- {
- m_processMsg = "@PeriodClosed@";
- return false;
- }
-
- // Deep Copy
- MInventory reversal = new MInventory(getCtx(), 0, get_TrxName());
- copyValues(this, reversal, getAD_Client_ID(), getAD_Org_ID());
- reversal.setDocStatus(DOCSTATUS_Drafted);
- reversal.setDocAction(DOCACTION_Complete);
- reversal.setIsApproved (false);
- reversal.setPosted(false);
- reversal.setProcessed(false);
- reversal.addDescription("{->" + getDocumentNo() + ")");
- //FR1948157
- reversal.setReversal_ID(getM_Inventory_ID());
- if (!reversal.save())
- {
- m_processMsg = "Could not create Inventory Reversal";
- return false;
- }
- reversal.setReversal(true);
-
- // Reverse Line Qty
- MInventoryLine[] oLines = getLines(true);
- for (int i = 0; i < oLines.length; i++)
- {
- MInventoryLine oLine = oLines[i];
- MInventoryLine rLine = new MInventoryLine(getCtx(), 0, get_TrxName());
- copyValues(oLine, rLine, oLine.getAD_Client_ID(), oLine.getAD_Org_ID());
- rLine.setM_Inventory_ID(reversal.getM_Inventory_ID());
- rLine.setParent(reversal);
- //AZ Goodwill
- // store original (voided/reversed) document line
- rLine.setReversalLine_ID(oLine.getM_InventoryLine_ID());
- //
- rLine.setQtyBook (oLine.getQtyCount()); // switch
- rLine.setQtyCount (oLine.getQtyBook());
- rLine.setQtyInternalUse (oLine.getQtyInternalUse().negate());
-
- if (!rLine.save())
- {
- m_processMsg = "Could not create Inventory Reversal Line";
- return false;
- }
-
- //We need to copy MA
- if (rLine.getM_AttributeSetInstance_ID() == 0)
- {
- MInventoryLineMA mas[] = MInventoryLineMA.get(getCtx(),
- oLines[i].getM_InventoryLine_ID(), get_TrxName());
- for (int j = 0; j < mas.length; j++)
- {
- MInventoryLineMA ma = new MInventoryLineMA (rLine,
- mas[j].getM_AttributeSetInstance_ID(),
- mas[j].getMovementQty().negate());
- if (!ma.save())
- ;
- }
- }
- }
- //
- if (!reversal.processIt(DocAction.ACTION_Complete))
- {
- m_processMsg = "Reversal ERROR: " + reversal.getProcessMsg();
- return false;
- }
- reversal.closeIt();
- reversal.setDocStatus(DOCSTATUS_Reversed);
- reversal.setDocAction(DOCACTION_None);
- reversal.save();
- m_processMsg = reversal.getDocumentNo();
-
- // Update Reversed (this)
- addDescription("(" + reversal.getDocumentNo() + "<-)");
- // After reverseCorrect
- m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_AFTER_REVERSECORRECT);
- if (m_processMsg != null)
- return false;
- setProcessed(true);
- //FR1948157
- setReversal_ID(reversal.getM_Inventory_ID());
- setDocStatus(DOCSTATUS_Reversed); // may come from void
- setDocAction(DOCACTION_None);
-
- return true;
- } // reverseCorrectIt
-
- /**
- * Reverse Accrual
- * @return false
- */
- public boolean reverseAccrualIt()
- {
- 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 false
- */
- public boolean reActivateIt()
- {
- 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;
-
- return false;
- } // reActivateIt
-
-
- /*************************************************************************
- * Get Summary
- * @return Summary of Document
- */
- public String getSummary()
- {
- StringBuffer sb = new StringBuffer();
- sb.append(getDocumentNo());
- // : Total Lines = 123.00 (#1)
- sb.append(": ")
- .append(Msg.translate(getCtx(),"ApprovalAmt")).append("=").append(getApprovalAmt())
- .append(" (#").append(getLines(false).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 getUpdatedBy();
- } // getDoc_User_ID
-
- /**
- * Get Document Currency
- * @return C_Currency_ID
- */
- public int getC_Currency_ID()
- {
- // MPriceList pl = MPriceList.get(getCtx(), getM_PriceList_ID());
- // return pl.getC_Currency_ID();
- return 0;
- } // getC_Currency_ID
-
- /** Reversal Flag */
- private boolean m_reversal = false;
-
- /**
- * Set Reversal
- * @param reversal reversal
- */
- private void setReversal(boolean reversal)
- {
- m_reversal = reversal;
- } // setReversal
- /**
- * Is Reversal
- * @return reversal
- */
- private boolean isReversal()
- {
- return m_reversal;
- } // isReversal
-
- /**
- * Create Cost Detail
- * @param line
- * @param Qty
- * @return
- */
- private String createCostDetail(MInventoryLine line,int M_AttributeSetInstance_ID, BigDecimal qty)
- {
- // Get Account Schemas to create MCostDetail
- MAcctSchema[] acctschemas = MAcctSchema.getClientAcctSchema(getCtx(), getAD_Client_ID());
- for(int asn = 0; asn < acctschemas.length; asn++)
- {
- MAcctSchema as = acctschemas[asn];
-
- boolean skip = false;
- if (as.getAD_OrgOnly_ID() != 0)
- {
- if (as.getOnlyOrgs() == null)
- as.setOnlyOrgs(MReportTree.getChildIDs(getCtx(),
- 0, MAcctSchemaElement.ELEMENTTYPE_Organization,
- as.getAD_OrgOnly_ID()));
-
- // Header Level Org
- skip = as.isSkipOrg(getAD_Org_ID());
- // Line Level Org
- skip = as.isSkipOrg(line.getAD_Org_ID());
- }
- if (skip)
- continue;
-
- ProductCost pc = new ProductCost (Env.getCtx(),
- line.getM_Product_ID(), M_AttributeSetInstance_ID, line.get_TrxName());
- pc.setQty(qty);
- BigDecimal costs = pc.getProductCosts(as, line.getAD_Org_ID(), as.getCostingMethod(),
- 0,false);
- if (costs == null || costs.signum() == 0)
- {
- return "No Costs for " + line.getProduct().getName();
- }
-
- // Set Total Amount and Total Quantity from Inventory
- MCostDetail.createInventory(as, line.getAD_Org_ID(),
- line.getM_Product_ID(), M_AttributeSetInstance_ID,
- line.getM_InventoryLine_ID(), 0, // no cost element
- costs.multiply(qty), qty,
- line.getDescription(), line.get_TrxName());
- }
-
- return "";
- }
-} // MInventory
diff --git a/base/src/org/compiere/model/MMovement.java b/base/src/org/compiere/model/MMovement.java
index 32bb132fab..10acd74d4b 100644
--- a/base/src/org/compiere/model/MMovement.java
+++ b/base/src/org/compiere/model/MMovement.java
@@ -658,81 +658,19 @@ public class MMovement extends X_M_Movement implements DocAction
//{
// MMovementLine line = lines[i];
boolean needSave = false;
- BigDecimal qtyASI = Env.ZERO ;
// Attribute Set Instance
if (line.getM_AttributeSetInstance_ID() == 0)
{
MProduct product = MProduct.get(getCtx(), line.getM_Product_ID());
String MMPolicy = product.getMMPolicy();
- MStorage[] storages = MStorage.getAllWithASI(getCtx(),
- line.getM_Product_ID(), line.getM_Locator_ID(),
- MClient.MMPOLICY_FiFo.equals(MMPolicy), get_TrxName());
+ MStorage[] storages = MStorage.getWarehouse(getCtx(), 0, line.getM_Product_ID(), 0,
+ null, MClient.MMPOLICY_FiFo.equals(MMPolicy), true, line.getM_Locator_ID(), get_TrxName());
+
BigDecimal qtyToDeliver = line.getMovementQty();
-
- /*for (int ii = 0; ii < storages.length; ii++)
- {
- MStorage storage = storages[ii];
- if (ii == 0)
- {
- if (storage.getQtyOnHand().compareTo(qtyToDeliver) >= 0)
- {
- line.setM_AttributeSetInstance_ID(storage.getM_AttributeSetInstance_ID());
- needSave = true;
- log.config("Direct - " + line);
- qtyToDeliver = Env.ZERO;
- }
- else
- {
- log.config("Split - " + line);
- MMovementLineMA ma = new MMovementLineMA (line,
- storage.getM_AttributeSetInstance_ID(),
- storage.getQtyOnHand());
- if (!ma.save())
- ;
- qtyToDeliver = qtyToDeliver.subtract(storage.getQtyOnHand());
- log.fine("#" + ii + ": " + ma + ", QtyToDeliver=" + qtyToDeliver);
- }
- }
- else // create addl material allocation
- {
- MMovementLineMA ma = new MMovementLineMA (line,
- storage.getM_AttributeSetInstance_ID(),
- qtyToDeliver);
- if (storage.getQtyOnHand().compareTo(qtyToDeliver) >= 0)
- qtyToDeliver = Env.ZERO;
- else
- {
- ma.setMovementQty(storage.getQtyOnHand());
- qtyToDeliver = qtyToDeliver.subtract(storage.getQtyOnHand());
- }
- if (!ma.save())
- ;
- log.fine("#" + ii + ": " + ma + ", QtyToDeliver=" + qtyToDeliver);
- }
- if (qtyToDeliver.signum() == 0)
- break;
- } // for all storages
-
- // No AttributeSetInstance found for remainder
- if (qtyToDeliver.signum() != 0)
- {
- MMovementLineMA ma = new MMovementLineMA (line,
- 0, qtyToDeliver);
- if (!ma.save())
- ;
- log.fine("##: " + ma);
- }*/
+
for (MStorage storage: storages)
{
- //consume ASI Zero
- if (storage.getM_AttributeSetInstance_ID() == 0)
- {
- qtyASI = qtyASI.add(storage.getQtyOnHand());
- qtyToDeliver = qtyToDeliver.subtract(storage.getQtyOnHand());
- continue;
- }
-
if (storage.getQtyOnHand().compareTo(qtyToDeliver) >= 0)
{
MMovementLineMA ma = new MMovementLineMA (line,
@@ -761,12 +699,12 @@ public class MMovement extends X_M_Movement implements DocAction
}
// No AttributeSetInstance found for remainder
- if (qtyToDeliver.signum() != 0 || qtyASI.signum() != 0)
+ if (qtyToDeliver.signum() != 0)
{
- MMovementLineMA ma = new MMovementLineMA (line, 0 , qtyToDeliver.add(qtyASI));
+ MMovementLineMA ma = new MMovementLineMA (line, 0 , qtyToDeliver);
if (!ma.save())
- ;
+ throw new IllegalStateException("Error try create ASI Reservation");
log.fine("##: " + ma);
}
} // attributeSetInstance
diff --git a/base/src/org/compiere/model/MStorage.java b/base/src/org/compiere/model/MStorage.java
index 23589a8c45..13e12bd254 100644
--- a/base/src/org/compiere/model/MStorage.java
+++ b/base/src/org/compiere/model/MStorage.java
@@ -78,7 +78,6 @@ public class MStorage extends X_M_Storage
DB.close(rs, pstmt);
rs = null; pstmt = null;
}
- pstmt = null;
if (retValue == null)
s_log.fine("Not Found - M_Locator_ID=" + M_Locator_ID
+ ", M_Product_ID=" + M_Product_ID + ", M_AttributeSetInstance_ID=" + M_AttributeSetInstance_ID);
@@ -89,7 +88,7 @@ public class MStorage extends X_M_Storage
} // get
/**
- * Get all Storages for Product with ASI and QtyOnHand > 0
+ * Get all Storages for Product with ASI and QtyOnHand <> 0
* @param ctx context
* @param M_Product_ID product
* @param M_Locator_ID locator
@@ -103,13 +102,9 @@ public class MStorage extends X_M_Storage
ArrayList list = new ArrayList();
String sql = "SELECT * FROM M_Storage "
+ "WHERE M_Product_ID=? AND M_Locator_ID=?"
- // Remove for management rightly FIFO/LIFO now you can consume a layer with ASI ID = zero and Qty onhand in negative
- // + " AND M_AttributeSetInstance_ID > 0"
- // + " AND QtyOnHand > 0 "
- + " AND QtyOnHand <> 0 "
+ + " AND M_AttributeSetInstance_ID > 0 "
+ + " AND QtyOnHand <> 0 "
+ "ORDER BY M_AttributeSetInstance_ID";
- if (!FiFo)
- sql += " DESC";
PreparedStatement pstmt = null;
ResultSet rs = null;
try
@@ -130,14 +125,13 @@ public class MStorage extends X_M_Storage
DB.close(rs, pstmt);
rs = null; pstmt = null;
}
- pstmt = null;
MStorage[] retValue = new MStorage[list.size()];
list.toArray(retValue);
return retValue;
} // getAllWithASI
/**
- * Get all Storages for Product
+ * Get all Storages for Product where QtyOnHand <> 0
* @param ctx context
* @param M_Product_ID product
* @param M_Locator_ID locator
@@ -172,7 +166,6 @@ public class MStorage extends X_M_Storage
DB.close(rs, pstmt);
rs = null; pstmt = null;
}
- pstmt = null;
MStorage[] retValue = new MStorage[list.size()];
list.toArray(retValue);
return retValue;
@@ -227,23 +220,41 @@ public class MStorage extends X_M_Storage
* @param FiFo first in-first-out
* @param trxName transaction
* @return existing - ordered by location priority (desc) and/or guarantee date
+ *
+ * @deprecated
*/
public static MStorage[] getWarehouse (Properties ctx, int M_Warehouse_ID,
int M_Product_ID, int M_AttributeSetInstance_ID, int M_AttributeSet_ID,
boolean allAttributeInstances, Timestamp minGuaranteeDate,
boolean FiFo, String trxName)
{
- if (M_Warehouse_ID == 0 || M_Product_ID == 0)
+ return getWarehouse(ctx, M_Warehouse_ID, M_Product_ID, M_AttributeSetInstance_ID,
+ minGuaranteeDate, FiFo, false, 0, trxName);
+ }
+
+ /**
+ * Get Storage Info for Warehouse or locator
+ * @param ctx context
+ * @param M_Warehouse_ID ignore if M_Locator_ID > 0
+ * @param M_Product_ID product
+ * @param M_AttributeSetInstance_ID instance id, 0 to retrieve all instance
+ * @param minGuaranteeDate optional minimum guarantee date if all attribute instances
+ * @param FiFo first in-first-out
+ * @param positiveOnly if true, only return storage records with qtyOnHand > 0
+ * @param M_Locator_ID optional locator id
+ * @param trxName transaction
+ * @return existing - ordered by location priority (desc) and/or guarantee date
+ */
+ public static MStorage[] getWarehouse (Properties ctx, int M_Warehouse_ID,
+ int M_Product_ID, int M_AttributeSetInstance_ID, Timestamp minGuaranteeDate,
+ boolean FiFo, boolean positiveOnly, int M_Locator_ID, String trxName)
+ {
+ if ((M_Warehouse_ID == 0 && M_Locator_ID == 0) || M_Product_ID == 0)
return new MStorage[0];
- if (M_AttributeSet_ID == 0)
- allAttributeInstances = true;
- else
- {
- MAttributeSet mas = MAttributeSet.get(ctx, M_AttributeSet_ID);
- if (!mas.isInstanceAttribute())
- allAttributeInstances = true;
- }
+ boolean allAttributeInstances = false;
+ if (M_AttributeSetInstance_ID == 0)
+ allAttributeInstances = true;
ArrayList list = new ArrayList();
// Specific Attribute Set Instance
@@ -251,11 +262,18 @@ public class MStorage extends X_M_Storage
+ "s.AD_Client_ID,s.AD_Org_ID,s.IsActive,s.Created,s.CreatedBy,s.Updated,s.UpdatedBy,"
+ "s.QtyOnHand,s.QtyReserved,s.QtyOrdered,s.DateLastInventory "
+ "FROM M_Storage s"
- + " INNER JOIN M_Locator l ON (l.M_Locator_ID=s.M_Locator_ID) "
- + "WHERE l.M_Warehouse_ID=?"
- + " AND s.M_Product_ID=?"
- + " AND COALESCE(s.M_AttributeSetInstance_ID,0)=? "
- + "ORDER BY l.PriorityNo DESC, M_AttributeSetInstance_ID";
+ + " INNER JOIN M_Locator l ON (l.M_Locator_ID=s.M_Locator_ID) ";
+ if (M_Locator_ID > 0)
+ sql += "WHERE l.M_Locator_ID = ?";
+ else
+ sql += "WHERE l.M_Warehouse_ID=?";
+ sql += " AND s.M_Product_ID=?"
+ + " AND COALESCE(s.M_AttributeSetInstance_ID,0)=? ";
+ if (positiveOnly)
+ {
+ sql += " AND s.QtyOnHand > 0 ";
+ }
+ sql += "ORDER BY l.PriorityNo DESC, M_AttributeSetInstance_ID";
if (!FiFo)
sql += " DESC";
// All Attribute Set Instances
@@ -266,19 +284,31 @@ public class MStorage extends X_M_Storage
+ "s.QtyOnHand,s.QtyReserved,s.QtyOrdered,s.DateLastInventory "
+ "FROM M_Storage s"
+ " INNER JOIN M_Locator l ON (l.M_Locator_ID=s.M_Locator_ID)"
- + " LEFT OUTER JOIN M_AttributeSetInstance asi ON (s.M_AttributeSetInstance_ID=asi.M_AttributeSetInstance_ID) "
- + "WHERE l.M_Warehouse_ID=?"
- + " AND s.M_Product_ID=? ";
+ + " LEFT OUTER JOIN M_AttributeSetInstance asi ON (s.M_AttributeSetInstance_ID=asi.M_AttributeSetInstance_ID) ";
+ if (M_Locator_ID > 0)
+ sql += "WHERE l.M_Locator_ID = ?";
+ else
+ sql += "WHERE l.M_Warehouse_ID=?";
+ sql += " AND s.M_Product_ID=? ";
if (minGuaranteeDate != null)
{
- sql += "AND (asi.GuaranteeDate IS NULL OR asi.GuaranteeDate>?) "
- + "ORDER BY asi.GuaranteeDate, M_AttributeSetInstance_ID";
+ sql += "AND (asi.GuaranteeDate IS NULL OR asi.GuaranteeDate>?) ";
+ if (positiveOnly)
+ {
+ sql += " AND s.QtyOnHand > 0 ";
+ }
+ sql += "ORDER BY l.PriorityNo DESC, " +
+ "asi.GuaranteeDate, M_AttributeSetInstance_ID";
if (!FiFo)
sql += " DESC";
- sql += ", l.PriorityNo DESC, s.QtyOnHand DESC";
+ sql += ", s.QtyOnHand DESC";
}
else
{
+ if (positiveOnly)
+ {
+ sql += " AND s.QtyOnHand > 0 ";
+ }
sql += "ORDER BY l.PriorityNo DESC, l.M_Locator_ID, s.M_AttributeSetInstance_ID";
if (!FiFo)
sql += " DESC";
@@ -290,12 +320,16 @@ public class MStorage extends X_M_Storage
try
{
pstmt = DB.prepareStatement(sql, trxName);
- pstmt.setInt(1, M_Warehouse_ID);
+ pstmt.setInt(1, M_Locator_ID > 0 ? M_Locator_ID : M_Warehouse_ID);
pstmt.setInt(2, M_Product_ID);
if (!allAttributeInstances)
+ {
pstmt.setInt(3, M_AttributeSetInstance_ID);
+ }
else if (minGuaranteeDate != null)
+ {
pstmt.setTimestamp(3, minGuaranteeDate);
+ }
rs = pstmt.executeQuery();
while (rs.next())
list.add (new MStorage (ctx, rs, trxName));
diff --git a/base/src/org/compiere/process/InOutGenerate.java b/base/src/org/compiere/process/InOutGenerate.java
index 8d1b95962b..0e932712c2 100644
--- a/base/src/org/compiere/process/InOutGenerate.java
+++ b/base/src/org/compiere/process/InOutGenerate.java
@@ -1,696 +1,678 @@
-/******************************************************************************
- * 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.process;
+/******************************************************************************
+ * 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.process;
+
+import java.math.*;
+import java.sql.*;
+import java.util.*;
+import java.util.logging.*;
+
+import org.compiere.model.*;
+import org.compiere.util.*;
+
+/**
+ * Generate Shipments.
+ * Manual or Automatic
+ *
+ * @author Jorg Janke
+ * @version $Id: InOutGenerate.java,v 1.2 2006/07/30 00:51:01 jjanke Exp $
+ */
+public class InOutGenerate extends SvrProcess
+{
+ /** Manual Selection */
+ private boolean p_Selection = false;
+ /** Warehouse */
+ private int p_M_Warehouse_ID = 0;
+ /** BPartner */
+ private int p_C_BPartner_ID = 0;
+ /** Promise Date */
+ private Timestamp p_DatePromised = null;
+ /** Include Orders w. unconfirmed Shipments */
+ private boolean p_IsUnconfirmedInOut = false;
+ /** DocAction */
+ private String p_docAction = DocAction.ACTION_Complete;
+ /** Consolidate */
+ private boolean p_ConsolidateDocument = true;
+ /** Shipment Date */
+ private Timestamp p_DateShipped = null;
+
+ /** The current Shipment */
+ private MInOut m_shipment = null;
+ /** Numner of Shipments */
+ private int m_created = 0;
+ /** Line Number */
+ private int m_line = 0;
+ /** Movement Date */
+ private Timestamp m_movementDate = null;
+ /** Last BP Location */
+ private int m_lastC_BPartner_Location_ID = -1;
+
+ /** The Query sql */
+ private String m_sql = null;
+
+
+ /** Storages temp space */
+ private HashMap m_map = new HashMap();
+ /** Last Parameter */
+ private SParameter m_lastPP = null;
+ /** Last Storage */
+ private MStorage[] m_lastStorages = null;
+
+
+ /**
+ * Prepare - e.g., get Parameters.
+ */
+ protected void prepare()
+ {
+ ProcessInfoParameter[] para = getParameter();
+ for (int i = 0; i < para.length; i++)
+ {
+ String name = para[i].getParameterName();
+ if (para[i].getParameter() == null)
+ ;
+ else if (name.equals("M_Warehouse_ID"))
+ p_M_Warehouse_ID = para[i].getParameterAsInt();
+ else if (name.equals("C_BPartner_ID"))
+ p_C_BPartner_ID = para[i].getParameterAsInt();
+ else if (name.equals("DatePromised"))
+ p_DatePromised = (Timestamp)para[i].getParameter();
+ else if (name.equals("Selection"))
+ p_Selection = "Y".equals(para[i].getParameter());
+ else if (name.equals("IsUnconfirmedInOut"))
+ p_IsUnconfirmedInOut = "Y".equals(para[i].getParameter());
+ else if (name.equals("ConsolidateDocument"))
+ p_ConsolidateDocument = "Y".equals(para[i].getParameter());
+ else if (name.equals("DocAction"))
+ p_docAction = (String)para[i].getParameter();
+ else if (name.equals("MovementDate"))
+ p_DateShipped = (Timestamp)para[i].getParameter();
+ else
+ log.log(Level.SEVERE, "Unknown Parameter: " + name);
+
+ // juddm - added ability to specify a shipment date from Generate Shipments
+ if (p_DateShipped == null) {
+ m_movementDate = Env.getContextAsDate(getCtx(), "#Date");
+ if (m_movementDate == null)
+ m_movementDate = new Timestamp(System.currentTimeMillis());
+ } else
+ m_movementDate = p_DateShipped;
+ // DocAction check
+ if (!DocAction.ACTION_Complete.equals(p_docAction))
+ p_docAction = DocAction.ACTION_Prepare;
+ }
+ } // prepare
+
+ /**
+ * Generate Shipments
+ * @return info
+ * @throws Exception
+ */
+ protected String doIt () throws Exception
+ {
+ log.info("Selection=" + p_Selection
+ + ", M_Warehouse_ID=" + p_M_Warehouse_ID
+ + ", C_BPartner_ID=" + p_C_BPartner_ID
+ + ", Consolidate=" + p_ConsolidateDocument
+ + ", IsUnconfirmed=" + p_IsUnconfirmedInOut
+ + ", Movement=" + m_movementDate);
+
+ if (p_M_Warehouse_ID == 0)
+ throw new AdempiereUserError("@NotFound@ @M_Warehouse_ID@");
+
+ if (p_Selection) // VInOutGen
+ {
+ m_sql = "SELECT C_Order.* FROM C_Order, T_Selection "
+ + "WHERE C_Order.DocStatus='CO' AND C_Order.IsSOTrx='Y' AND C_Order.AD_Client_ID=? "
+ + "AND C_Order.C_Order_ID = T_Selection.T_Selection_ID "
+ + "AND T_Selection.AD_PInstance_ID=? ";
+ }
+ else
+ {
+ m_sql = "SELECT * FROM C_Order o "
+ + "WHERE DocStatus='CO' AND IsSOTrx='Y'"
+ // No Offer,POS
+ + " AND o.C_DocType_ID IN (SELECT C_DocType_ID FROM C_DocType "
+ + "WHERE DocBaseType='SOO' AND DocSubTypeSO NOT IN ('ON','OB','WR'))"
+ + " AND o.IsDropShip='N'"
+ // No Manual
+ + " AND o.DeliveryRule<>'M'"
+ // Open Order Lines with Warehouse
+ + " AND EXISTS (SELECT * FROM C_OrderLine ol "
+ + "WHERE ol.M_Warehouse_ID=?"; // #1
+ if (p_DatePromised != null)
+ m_sql += " AND TRUNC(ol.DatePromised)<=?"; // #2
+ m_sql += " AND o.C_Order_ID=ol.C_Order_ID AND ol.QtyOrdered<>ol.QtyDelivered)";
+ //
+ if (p_C_BPartner_ID != 0)
+ m_sql += " AND o.C_BPartner_ID=?"; // #3
+ }
+ m_sql += " ORDER BY M_Warehouse_ID, PriorityRule, M_Shipper_ID, C_BPartner_ID, C_BPartner_Location_ID, C_Order_ID";
+ // m_sql += " FOR UPDATE";
+
+ PreparedStatement pstmt = null;
+ try
+ {
+ pstmt = DB.prepareStatement (m_sql, get_TrxName());
+ int index = 1;
+ if (p_Selection)
+ {
+ pstmt.setInt(index++, Env.getAD_Client_ID(getCtx()));
+ pstmt.setInt(index++, getAD_PInstance_ID());
+ }
+ else
+ {
+ pstmt.setInt(index++, p_M_Warehouse_ID);
+ if (p_DatePromised != null)
+ pstmt.setTimestamp(index++, p_DatePromised);
+ if (p_C_BPartner_ID != 0)
+ pstmt.setInt(index++, p_C_BPartner_ID);
+ }
+ }
+ catch (Exception e)
+ {
+ log.log(Level.SEVERE, m_sql, e);
+ }
+ return generate(pstmt);
+ } // doIt
+
+ /**
+ * Generate Shipments
+ * @param pstmt Order Query
+ * @return info
+ */
+ private String generate (PreparedStatement pstmt)
+ {
+ try
+ {
+ ResultSet rs = pstmt.executeQuery ();
+ while (rs.next ()) // Order
+ {
+ MOrder order = new MOrder (getCtx(), rs, get_TrxName());
+ // New Header different Shipper, Shipment Location
+ if (!p_ConsolidateDocument
+ || (m_shipment != null
+ && (m_shipment.getC_BPartner_Location_ID() != order.getC_BPartner_Location_ID()
+ || m_shipment.getM_Shipper_ID() != order.getM_Shipper_ID() )))
+ completeShipment();
+ log.fine("check: " + order + " - DeliveryRule=" + order.getDeliveryRule());
+ //
+ Timestamp minGuaranteeDate = m_movementDate;
+ boolean completeOrder = MOrder.DELIVERYRULE_CompleteOrder.equals(order.getDeliveryRule());
+ // OrderLine WHERE
+ String where = " AND M_Warehouse_ID=" + p_M_Warehouse_ID;
+ if (p_DatePromised != null)
+ where += " AND (TRUNC(DatePromised)<=" + DB.TO_DATE(p_DatePromised, true)
+ + " OR DatePromised IS NULL)";
+ // Exclude Auto Delivery if not Force
+ if (!MOrder.DELIVERYRULE_Force.equals(order.getDeliveryRule()))
+ where += " AND (C_OrderLine.M_Product_ID IS NULL"
+ + " OR EXISTS (SELECT * FROM M_Product p "
+ + "WHERE C_OrderLine.M_Product_ID=p.M_Product_ID"
+ + " AND IsExcludeAutoDelivery='N'))";
+ // Exclude Unconfirmed
+ if (!p_IsUnconfirmedInOut)
+ where += " AND NOT EXISTS (SELECT * FROM M_InOutLine iol"
+ + " INNER JOIN M_InOut io ON (iol.M_InOut_ID=io.M_InOut_ID) "
+ + "WHERE iol.C_OrderLine_ID=C_OrderLine.C_OrderLine_ID AND io.DocStatus IN ('IP','WC'))";
+ // Deadlock Prevention - Order by M_Product_ID
+ MOrderLine[] lines = order.getLines (where, "ORDER BY C_BPartner_Location_ID, M_Product_ID");
+ for (int i = 0; i < lines.length; i++)
+ {
+ MOrderLine line = lines[i];
+ if (line.getM_Warehouse_ID() != p_M_Warehouse_ID)
+ continue;
+ log.fine("check: " + line);
+ BigDecimal onHand = Env.ZERO;
+ BigDecimal toDeliver = line.getQtyOrdered()
+ .subtract(line.getQtyDelivered());
+ MProduct product = line.getProduct();
+ // Nothing to Deliver
+ if (product != null && toDeliver.signum() == 0)
+ continue;
+
+ // or it's a charge - Bug#: 1603966
+ if (line.getC_Charge_ID()!=0 && toDeliver.signum() == 0)
+ continue;
+
+ // Check / adjust for confirmations
+ BigDecimal unconfirmedShippedQty = Env.ZERO;
+ if (p_IsUnconfirmedInOut && product != null && toDeliver.signum() != 0)
+ {
+ String where2 = "EXISTS (SELECT * FROM M_InOut io WHERE io.M_InOut_ID=M_InOutLine.M_InOut_ID AND io.DocStatus IN ('IP','WC'))";
+ MInOutLine[] iols = MInOutLine.getOfOrderLine(getCtx(),
+ line.getC_OrderLine_ID(), where2, null);
+ for (int j = 0; j < iols.length; j++)
+ unconfirmedShippedQty = unconfirmedShippedQty.add(iols[j].getMovementQty());
+ String logInfo = "Unconfirmed Qty=" + unconfirmedShippedQty
+ + " - ToDeliver=" + toDeliver + "->";
+ toDeliver = toDeliver.subtract(unconfirmedShippedQty);
+ logInfo += toDeliver;
+ if (toDeliver.signum() < 0)
+ {
+ toDeliver = Env.ZERO;
+ logInfo += " (set to 0)";
+ }
+ // Adjust On Hand
+ onHand = onHand.subtract(unconfirmedShippedQty);
+ log.fine(logInfo);
+ }
+
+ // Comments & lines w/o product & services
+ if ((product == null || !product.isStocked())
+ && (line.getQtyOrdered().signum() == 0 // comments
+ || toDeliver.signum() != 0)) // lines w/o product
+ {
+ if (!MOrder.DELIVERYRULE_CompleteOrder.equals(order.getDeliveryRule())) // printed later
+ createLine (order, line, toDeliver, null, false);
+ continue;
+ }
+
+ // Stored Product
+ String MMPolicy = product.getMMPolicy();
+ MStorage[] storages = getStorages(line.getM_Warehouse_ID(),
+ line.getM_Product_ID(), line.getM_AttributeSetInstance_ID(),
+ minGuaranteeDate, MClient.MMPOLICY_FiFo.equals(MMPolicy));
+
+ for (int j = 0; j < storages.length; j++)
+ {
+ MStorage storage = storages[j];
+ onHand = onHand.add(storage.getQtyOnHand());
+ }
+ boolean fullLine = onHand.compareTo(toDeliver) >= 0
+ || toDeliver.signum() < 0;
+
+ // Complete Order
+ if (completeOrder && !fullLine)
+ {
+ log.fine("Failed CompleteOrder - OnHand=" + onHand
+ + " (Unconfirmed=" + unconfirmedShippedQty
+ + "), ToDeliver=" + toDeliver + " - " + line);
+ completeOrder = false;
+ break;
+ }
+ // Complete Line
+ else if (fullLine && MOrder.DELIVERYRULE_CompleteLine.equals(order.getDeliveryRule()))
+ {
+ log.fine("CompleteLine - OnHand=" + onHand
+ + " (Unconfirmed=" + unconfirmedShippedQty
+ + ", ToDeliver=" + toDeliver + " - " + line);
+ //
+ createLine (order, line, toDeliver, storages, false);
+ }
+ // Availability
+ else if (MOrder.DELIVERYRULE_Availability.equals(order.getDeliveryRule())
+ && (onHand.signum() > 0
+ || toDeliver.signum() < 0))
+ {
+ BigDecimal deliver = toDeliver;
+ if (deliver.compareTo(onHand) > 0)
+ deliver = onHand;
+ log.fine("Available - OnHand=" + onHand
+ + " (Unconfirmed=" + unconfirmedShippedQty
+ + "), ToDeliver=" + toDeliver
+ + ", Delivering=" + deliver + " - " + line);
+ //
+ createLine (order, line, deliver, storages, false);
+ }
+ // Force
+ else if (MOrder.DELIVERYRULE_Force.equals(order.getDeliveryRule()))
+ {
+ BigDecimal deliver = toDeliver;
+ log.fine("Force - OnHand=" + onHand
+ + " (Unconfirmed=" + unconfirmedShippedQty
+ + "), ToDeliver=" + toDeliver
+ + ", Delivering=" + deliver + " - " + line);
+ //
+ createLine (order, line, deliver, storages, true);
+ }
+ // Manual
+ else if (MOrder.DELIVERYRULE_Manual.equals(order.getDeliveryRule()))
+ log.fine("Manual - OnHand=" + onHand
+ + " (Unconfirmed=" + unconfirmedShippedQty
+ + ") - " + line);
+ else
+ log.fine("Failed: " + order.getDeliveryRule() + " - OnHand=" + onHand
+ + " (Unconfirmed=" + unconfirmedShippedQty
+ + "), ToDeliver=" + toDeliver + " - " + line);
+ } // for all order lines
+
+ // Complete Order successful
+ if (completeOrder && MOrder.DELIVERYRULE_CompleteOrder.equals(order.getDeliveryRule()))
+ {
+ for (int i = 0; i < lines.length; i++)
+ {
+ MOrderLine line = lines[i];
+ if (line.getM_Warehouse_ID() != p_M_Warehouse_ID)
+ continue;
+ MProduct product = line.getProduct();
+ BigDecimal toDeliver = line.getQtyOrdered().subtract(line.getQtyDelivered());
+ //
+ MStorage[] storages = null;
+ if (product != null && product.isStocked())
+ {
+ String MMPolicy = product.getMMPolicy();
+ storages = getStorages(line.getM_Warehouse_ID(),
+ line.getM_Product_ID(), line.getM_AttributeSetInstance_ID(),
+ minGuaranteeDate, MClient.MMPOLICY_FiFo.equals(MMPolicy));
+ }
+ //
+ createLine (order, line, toDeliver, storages, false);
+ }
+ }
+ m_line += 1000;
+ } // while order
+ rs.close ();
+ pstmt.close ();
+ pstmt = null;
+ }
+ catch (Exception e)
+ {
+ log.log(Level.SEVERE, m_sql, e);
+ }
+ try
+ {
+ if (pstmt != null)
+ pstmt.close ();
+ pstmt = null;
+ }
+ catch (Exception e)
+ {
+ pstmt = null;
+ }
+ completeShipment();
+ return "@Created@ = " + m_created;
+ } // generate
+
+
+
+ /**************************************************************************
+ * Create Line
+ * @param order order
+ * @param orderLine line
+ * @param qty qty
+ * @param storages storage info
+ * @param force force delivery
+ */
+ private void createLine (MOrder order, MOrderLine orderLine, BigDecimal qty,
+ MStorage[] storages, boolean force)
+ {
+ // Complete last Shipment - can have multiple shipments
+ if (m_lastC_BPartner_Location_ID != orderLine.getC_BPartner_Location_ID() )
+ completeShipment();
+ m_lastC_BPartner_Location_ID = orderLine.getC_BPartner_Location_ID();
+ // Create New Shipment
+ if (m_shipment == null)
+ {
+ m_shipment = new MInOut (order, 0, m_movementDate);
+ m_shipment.setM_Warehouse_ID(orderLine.getM_Warehouse_ID()); // sets Org too
+ if (order.getC_BPartner_ID() != orderLine.getC_BPartner_ID())
+ m_shipment.setC_BPartner_ID(orderLine.getC_BPartner_ID());
+ if (order.getC_BPartner_Location_ID() != orderLine.getC_BPartner_Location_ID())
+ m_shipment.setC_BPartner_Location_ID(orderLine.getC_BPartner_Location_ID());
+ if (!m_shipment.save())
+ throw new IllegalStateException("Could not create Shipment");
+ }
+ // Non Inventory Lines
+ if (storages == null)
+ {
+ MInOutLine line = new MInOutLine (m_shipment);
+ line.setOrderLine(orderLine, 0, Env.ZERO);
+ line.setQty(qty); // Correct UOM
+ if (orderLine.getQtyEntered().compareTo(orderLine.getQtyOrdered()) != 0)
+ line.setQtyEntered(qty
+ .multiply(orderLine.getQtyEntered())
+ .divide(orderLine.getQtyOrdered(), 12, BigDecimal.ROUND_HALF_UP));
+ line.setLine(m_line + orderLine.getLine());
+ if (!line.save())
+ throw new IllegalStateException("Could not create Shipment Line");
+ log.fine(line.toString());
+ return;
+ }
+
+ // Inventory Lines
+ ArrayList list = new ArrayList();
+ BigDecimal toDeliver = qty;
+ for (int i = 0; i < storages.length; i++)
+ {
+ MStorage storage = storages[i];
+
+ BigDecimal deliver = toDeliver;
+ // Not enough On Hand
+ if (deliver.compareTo(storage.getQtyOnHand()) > 0
+ && storage.getQtyOnHand().signum() >= 0) // positive storage
+ {
+ if (!force // Adjust to OnHand Qty
+ || (force && i+1 != storages.length)) // if force not on last location
+ deliver = storage.getQtyOnHand();
+ }
+ if (deliver.signum() == 0) // zero deliver
+ continue;
+ int M_Locator_ID = storage.getM_Locator_ID();
+ //
+ MInOutLine line = null;
+ if (orderLine.getM_AttributeSetInstance_ID() == 0) // find line with Locator
+ {
+ for (int ll = 0; ll < list.size(); ll++)
+ {
+ MInOutLine test = (MInOutLine)list.get(ll);
+ if (test.getM_Locator_ID() == M_Locator_ID && test.getM_AttributeSetInstance_ID() == 0)
+ {
+ line = test;
+ break;
+ }
+ }
+ }
+ if (line == null) // new line
+ {
+ line = new MInOutLine (m_shipment);
+ line.setOrderLine(orderLine, M_Locator_ID, order.isSOTrx() ? deliver : Env.ZERO);
+ line.setQty(deliver);
+ list.add(line);
+ }
+ else // existing line
+ line.setQty(line.getMovementQty().add(deliver));
+ if (orderLine.getQtyEntered().compareTo(orderLine.getQtyOrdered()) != 0)
+ line.setQtyEntered(line.getMovementQty().multiply(orderLine.getQtyEntered())
+ .divide(orderLine.getQtyOrdered(), 12, BigDecimal.ROUND_HALF_UP));
+ line.setLine(m_line + orderLine.getLine());
+
+ if (!line.save())
+ throw new IllegalStateException("Could not create Shipment Line");
+ log.fine("ToDeliver=" + qty + "/" + deliver + " - " + line);
+ toDeliver = toDeliver.subtract(deliver);
+ // Temp adjustment, actual update happen in MInOut.completeIt
+ storage.setQtyOnHand(storage.getQtyOnHand().subtract(deliver));
+ //
+ if (toDeliver.signum() == 0)
+ break;
+ }
+ if (toDeliver.signum() != 0 )
+ {
+ if (!force)
+ {
+ throw new IllegalStateException("Not All Delivered - Remainder=" + toDeliver);
+ }
+ else
+ {
+ MInOutLine line = new MInOutLine (m_shipment);
+ line.setOrderLine(orderLine, 0, order.isSOTrx() ? toDeliver : Env.ZERO);
+ line.setQty(toDeliver);
+ if (!line.save())
+ throw new IllegalStateException("Could not create Shipment Line");
+
+ }
+ }
+ } // createLine
+
+
+ /**
+ * Get Storages
+ * @param M_Warehouse_ID
+ * @param M_Product_ID
+ * @param M_AttributeSetInstance_ID
+ * @param minGuaranteeDate
+ * @param FiFo
+ * @return storages
+ */
+ private MStorage[] getStorages(int M_Warehouse_ID,
+ int M_Product_ID, int M_AttributeSetInstance_ID,
+ Timestamp minGuaranteeDate, boolean FiFo)
+ {
+ m_lastPP = new SParameter(M_Warehouse_ID,
+ M_Product_ID, M_AttributeSetInstance_ID,
+ minGuaranteeDate, FiFo);
+ //
+ m_lastStorages = m_map.get(m_lastPP);
+
+ if (m_lastStorages == null)
+ {
+ m_lastStorages = MStorage.getWarehouse(getCtx(),
+ M_Warehouse_ID, M_Product_ID, M_AttributeSetInstance_ID,
+ minGuaranteeDate, FiFo, true, 0 , get_TrxName());
+ m_map.put(m_lastPP, m_lastStorages);
+ }
+ return m_lastStorages;
+ } // getStorages
+
+
+ /**
+ * Complete Shipment
+ */
+ private void completeShipment()
+ {
+ if (m_shipment != null)
+ {
+ // Fails if there is a confirmation
+ if (!m_shipment.processIt(p_docAction))
+ log.warning("Failed: " + m_shipment);
+ m_shipment.save();
+ //
+ addLog(m_shipment.getM_InOut_ID(), m_shipment.getMovementDate(), null, m_shipment.getDocumentNo());
+ m_created++;
+
+ //reset storage cache as MInOut.completeIt will update m_storage
+ m_map = new HashMap();
+ m_lastPP = null;
+ m_lastStorages = null;
+ }
+ m_shipment = null;
+ m_line = 0;
+ } // completeOrder
+
+ /**
+ * InOutGenerate Parameter
+ */
+ class SParameter
+ {
+ /**
+ * Parameter
+ * @param p_Warehouse_ID warehouse
+ * @param p_Product_ID
+ * @param p_AttributeSetInstance_ID
+ * @param p_minGuaranteeDate
+ * @param p_FiFo
+ */
+ protected SParameter (int p_Warehouse_ID,
+ int p_Product_ID, int p_AttributeSetInstance_ID,
+ Timestamp p_minGuaranteeDate, boolean p_FiFo)
+ {
+ this.M_Warehouse_ID = p_Warehouse_ID;
+ this.M_Product_ID = p_Product_ID;
+ this.M_AttributeSetInstance_ID = p_AttributeSetInstance_ID;
+ this.minGuaranteeDate = p_minGuaranteeDate;
+ this.FiFo = p_FiFo;
+ }
+ /** Warehouse */
+ public int M_Warehouse_ID;
+ /** Product */
+ public int M_Product_ID;
+ /** ASI */
+ public int M_AttributeSetInstance_ID;
+ /** AS */
+ public int M_AttributeSet_ID;
+ /** All instances */
+ public boolean allAttributeInstances;
+ /** Mon Guarantee Date */
+ public Timestamp minGuaranteeDate;
+ /** FiFo */
+ public boolean FiFo;
+
+ /**
+ * Equals
+ * @param obj
+ * @return true if equal
+ */
+ public boolean equals (Object obj)
+ {
+ if (obj != null && obj instanceof SParameter)
+ {
+ SParameter cmp = (SParameter)obj;
+ boolean eq = cmp.M_Warehouse_ID == M_Warehouse_ID
+ && cmp.M_Product_ID == M_Product_ID
+ && cmp.M_AttributeSetInstance_ID == M_AttributeSetInstance_ID
+ && cmp.M_AttributeSet_ID == M_AttributeSet_ID
+ && cmp.allAttributeInstances == allAttributeInstances
+ && cmp.FiFo == FiFo;
+ if (eq)
+ {
+ if (cmp.minGuaranteeDate == null && minGuaranteeDate == null)
+ ;
+ else if (cmp.minGuaranteeDate != null && minGuaranteeDate != null
+ && cmp.minGuaranteeDate.equals(minGuaranteeDate))
+ ;
+ else
+ eq = false;
+ }
+ return eq;
+ }
+ return false;
+ } // equals
+
+ /**
+ * hashCode
+ * @return hash code
+ */
+ public int hashCode ()
+ {
+ long hash = M_Warehouse_ID
+ + (M_Product_ID * 2)
+ + (M_AttributeSetInstance_ID * 3)
+ + (M_AttributeSet_ID * 4);
+
+ if (allAttributeInstances)
+ hash *= -1;
+ if (FiFo);
+ hash *= -2;
+ if (hash < 0)
+ hash = -hash + 7;
+ while (hash > Integer.MAX_VALUE)
+ hash -= Integer.MAX_VALUE;
+ //
+ if (minGuaranteeDate != null)
+ {
+ hash += minGuaranteeDate.hashCode();
+ while (hash > Integer.MAX_VALUE)
+ hash -= Integer.MAX_VALUE;
+ }
+
+ return (int)hash;
+ } // hashCode
+
+ } // Parameter
+
+} // InOutGenerate
-import java.math.BigDecimal;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.Timestamp;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.logging.Level;
-
-import org.compiere.model.MAttributeSet;
-import org.compiere.model.MClient;
-import org.compiere.model.MInOut;
-import org.compiere.model.MInOutLine;
-import org.compiere.model.MOrder;
-import org.compiere.model.MOrderLine;
-import org.compiere.model.MProduct;
-import org.compiere.model.MStorage;
-import org.compiere.util.AdempiereUserError;
-import org.compiere.util.DB;
-import org.compiere.util.Env;
-
-/**
- * Generate Shipments.
- * Manual or Automatic
- *
- * @author Jorg Janke
- * @version $Id: InOutGenerate.java,v 1.2 2006/07/30 00:51:01 jjanke Exp $
- */
-public class InOutGenerate extends SvrProcess
-{
- /** Manual Selection */
- private boolean p_Selection = false;
- /** Warehouse */
- private int p_M_Warehouse_ID = 0;
- /** BPartner */
- private int p_C_BPartner_ID = 0;
- /** Promise Date */
- private Timestamp p_DatePromised = null;
- /** Include Orders w. unconfirmed Shipments */
- private boolean p_IsUnconfirmedInOut = false;
- /** DocAction */
- private String p_docAction = DocAction.ACTION_Complete;
- /** Consolidate */
- private boolean p_ConsolidateDocument = true;
- /** Shipment Date */
- private Timestamp p_DateShipped = null;
-
- /** The current Shipment */
- private MInOut m_shipment = null;
- /** Numner of Shipments */
- private int m_created = 0;
- /** Line Number */
- private int m_line = 0;
- /** Movement Date */
- private Timestamp m_movementDate = null;
- /** Last BP Location */
- private int m_lastC_BPartner_Location_ID = -1;
-
- /** The Query sql */
- private String m_sql = null;
-
-
- /** Storages temp space */
- private HashMap m_map = new HashMap();
- /** Last Parameter */
- private SParameter m_lastPP = null;
- /** Last Storage */
- private MStorage[] m_lastStorages = null;
-
-
- /**
- * Prepare - e.g., get Parameters.
- */
- protected void prepare()
- {
- ProcessInfoParameter[] para = getParameter();
- for (int i = 0; i < para.length; i++)
- {
- String name = para[i].getParameterName();
- if (para[i].getParameter() == null)
- ;
- else if (name.equals("M_Warehouse_ID"))
- p_M_Warehouse_ID = para[i].getParameterAsInt();
- else if (name.equals("C_BPartner_ID"))
- p_C_BPartner_ID = para[i].getParameterAsInt();
- else if (name.equals("DatePromised"))
- p_DatePromised = (Timestamp)para[i].getParameter();
- else if (name.equals("Selection"))
- p_Selection = "Y".equals(para[i].getParameter());
- else if (name.equals("IsUnconfirmedInOut"))
- p_IsUnconfirmedInOut = "Y".equals(para[i].getParameter());
- else if (name.equals("ConsolidateDocument"))
- p_ConsolidateDocument = "Y".equals(para[i].getParameter());
- else if (name.equals("DocAction"))
- p_docAction = (String)para[i].getParameter();
- else if (name.equals("MovementDate"))
- p_DateShipped = (Timestamp)para[i].getParameter();
- else
- log.log(Level.SEVERE, "Unknown Parameter: " + name);
-
- // juddm - added ability to specify a shipment date from Generate Shipments
- if (p_DateShipped == null) {
- m_movementDate = Env.getContextAsDate(getCtx(), "#Date");
- if (m_movementDate == null)
- m_movementDate = new Timestamp(System.currentTimeMillis());
- } else
- m_movementDate = p_DateShipped;
- // DocAction check
- if (!DocAction.ACTION_Complete.equals(p_docAction))
- p_docAction = DocAction.ACTION_Prepare;
- }
- } // prepare
-
- /**
- * Generate Shipments
- * @return info
- * @throws Exception
- */
- protected String doIt () throws Exception
- {
- log.info("Selection=" + p_Selection
- + ", M_Warehouse_ID=" + p_M_Warehouse_ID
- + ", C_BPartner_ID=" + p_C_BPartner_ID
- + ", Consolidate=" + p_ConsolidateDocument
- + ", IsUnconfirmed=" + p_IsUnconfirmedInOut
- + ", Movement=" + m_movementDate);
-
- if (p_M_Warehouse_ID == 0)
- throw new AdempiereUserError("@NotFound@ @M_Warehouse_ID@");
-
- if (p_Selection) // VInOutGen
- {
- m_sql = "SELECT C_Order.* FROM C_Order, T_Selection "
- + "WHERE C_Order.DocStatus='CO' AND C_Order.IsSOTrx='Y' AND C_Order.AD_Client_ID=? "
- + "AND C_Order.C_Order_ID = T_Selection.T_Selection_ID "
- + "AND T_Selection.AD_PInstance_ID=? ";
- }
- else
- {
- m_sql = "SELECT * FROM C_Order o "
- + "WHERE DocStatus='CO' AND IsSOTrx='Y'"
- // No Offer,POS
- + " AND o.C_DocType_ID IN (SELECT C_DocType_ID FROM C_DocType "
- + "WHERE DocBaseType='SOO' AND DocSubTypeSO NOT IN ('ON','OB','WR'))"
- + " AND o.IsDropShip='N'"
- // No Manual
- + " AND o.DeliveryRule<>'M'"
- // Open Order Lines with Warehouse
- + " AND EXISTS (SELECT * FROM C_OrderLine ol "
- + "WHERE ol.M_Warehouse_ID=?"; // #1
- if (p_DatePromised != null)
- m_sql += " AND TRUNC(ol.DatePromised)<=?"; // #2
- m_sql += " AND o.C_Order_ID=ol.C_Order_ID AND ol.QtyOrdered<>ol.QtyDelivered)";
- //
- if (p_C_BPartner_ID != 0)
- m_sql += " AND o.C_BPartner_ID=?"; // #3
- }
- m_sql += " ORDER BY M_Warehouse_ID, PriorityRule, M_Shipper_ID, C_BPartner_ID, C_BPartner_Location_ID, C_Order_ID";
- // m_sql += " FOR UPDATE";
-
- PreparedStatement pstmt = null;
- try
- {
- pstmt = DB.prepareStatement (m_sql, get_TrxName());
- int index = 1;
- if (p_Selection)
- {
- pstmt.setInt(index++, Env.getAD_Client_ID(getCtx()));
- pstmt.setInt(index++, getAD_PInstance_ID());
- }
- else
- {
- pstmt.setInt(index++, p_M_Warehouse_ID);
- if (p_DatePromised != null)
- pstmt.setTimestamp(index++, p_DatePromised);
- if (p_C_BPartner_ID != 0)
- pstmt.setInt(index++, p_C_BPartner_ID);
- }
- }
- catch (Exception e)
- {
- log.log(Level.SEVERE, m_sql, e);
- }
- return generate(pstmt);
- } // doIt
-
- /**
- * Generate Shipments
- * @param pstmt Order Query
- * @return info
- */
- private String generate (PreparedStatement pstmt)
- {
- MClient client = MClient.get(getCtx());
- try
- {
- ResultSet rs = pstmt.executeQuery ();
- while (rs.next ()) // Order
- {
- MOrder order = new MOrder (getCtx(), rs, get_TrxName());
- // New Header different Shipper, Shipment Location
- if (!p_ConsolidateDocument
- || (m_shipment != null
- && (m_shipment.getC_BPartner_Location_ID() != order.getC_BPartner_Location_ID()
- || m_shipment.getM_Shipper_ID() != order.getM_Shipper_ID() )))
- completeShipment();
- log.fine("check: " + order + " - DeliveryRule=" + order.getDeliveryRule());
- //
- Timestamp minGuaranteeDate = m_movementDate;
- boolean completeOrder = MOrder.DELIVERYRULE_CompleteOrder.equals(order.getDeliveryRule());
- // OrderLine WHERE
- String where = " AND M_Warehouse_ID=" + p_M_Warehouse_ID;
- if (p_DatePromised != null)
- where += " AND (TRUNC(DatePromised)<=" + DB.TO_DATE(p_DatePromised, true)
- + " OR DatePromised IS NULL)";
- // Exclude Auto Delivery if not Force
- if (!MOrder.DELIVERYRULE_Force.equals(order.getDeliveryRule()))
- where += " AND (C_OrderLine.M_Product_ID IS NULL"
- + " OR EXISTS (SELECT * FROM M_Product p "
- + "WHERE C_OrderLine.M_Product_ID=p.M_Product_ID"
- + " AND IsExcludeAutoDelivery='N'))";
- // Exclude Unconfirmed
- if (!p_IsUnconfirmedInOut)
- where += " AND NOT EXISTS (SELECT * FROM M_InOutLine iol"
- + " INNER JOIN M_InOut io ON (iol.M_InOut_ID=io.M_InOut_ID) "
- + "WHERE iol.C_OrderLine_ID=C_OrderLine.C_OrderLine_ID AND io.DocStatus IN ('IP','WC'))";
- // Deadlock Prevention - Order by M_Product_ID
- MOrderLine[] lines = order.getLines (where, "C_BPartner_Location_ID, M_Product_ID");
- for (int i = 0; i < lines.length; i++)
- {
- MOrderLine line = lines[i];
- if (line.getM_Warehouse_ID() != p_M_Warehouse_ID)
- continue;
- log.fine("check: " + line);
- BigDecimal onHand = Env.ZERO;
- BigDecimal toDeliver = line.getQtyOrdered()
- .subtract(line.getQtyDelivered());
- MProduct product = line.getProduct();
- // Nothing to Deliver
- if (product != null && toDeliver.signum() == 0)
- continue;
-
- // or it's a charge - Bug#: 1603966
- if (line.getC_Charge_ID()!=0 && toDeliver.signum() == 0)
- continue;
-
- // Check / adjust for confirmations
- BigDecimal unconfirmedShippedQty = Env.ZERO;
- if (p_IsUnconfirmedInOut && product != null && toDeliver.signum() != 0)
- {
- String where2 = "EXISTS (SELECT * FROM M_InOut io WHERE io.M_InOut_ID=M_InOutLine.M_InOut_ID AND io.DocStatus IN ('IP','WC'))";
- MInOutLine[] iols = MInOutLine.getOfOrderLine(getCtx(),
- line.getC_OrderLine_ID(), where2, null);
- for (int j = 0; j < iols.length; j++)
- unconfirmedShippedQty = unconfirmedShippedQty.add(iols[j].getMovementQty());
- String logInfo = "Unconfirmed Qty=" + unconfirmedShippedQty
- + " - ToDeliver=" + toDeliver + "->";
- toDeliver = toDeliver.subtract(unconfirmedShippedQty);
- logInfo += toDeliver;
- if (toDeliver.signum() < 0)
- {
- toDeliver = Env.ZERO;
- logInfo += " (set to 0)";
- }
- // Adjust On Hand
- onHand = onHand.subtract(unconfirmedShippedQty);
- log.fine(logInfo);
- }
-
- // Comments & lines w/o product & services
- if ((product == null || !product.isStocked())
- && (line.getQtyOrdered().signum() == 0 // comments
- || toDeliver.signum() != 0)) // lines w/o product
- {
- if (!MOrder.DELIVERYRULE_CompleteOrder.equals(order.getDeliveryRule())) // printed later
- createLine (order, line, toDeliver, null, false);
- continue;
- }
-
- // Stored Product
- String MMPolicy = product.getMMPolicy();
- MStorage[] storages = getStorages(line.getM_Warehouse_ID(),
- line.getM_Product_ID(), line.getM_AttributeSetInstance_ID(),
- product.getM_AttributeSet_ID(),
- line.getM_AttributeSetInstance_ID()==0, minGuaranteeDate,
- MClient.MMPOLICY_FiFo.equals(MMPolicy));
-
- for (int j = 0; j < storages.length; j++)
- {
- MStorage storage = storages[j];
- onHand = onHand.add(storage.getQtyOnHand());
- }
- boolean fullLine = onHand.compareTo(toDeliver) >= 0
- || toDeliver.signum() < 0;
-
- // Complete Order
- if (completeOrder && !fullLine)
- {
- log.fine("Failed CompleteOrder - OnHand=" + onHand
- + " (Unconfirmed=" + unconfirmedShippedQty
- + "), ToDeliver=" + toDeliver + " - " + line);
- completeOrder = false;
- break;
- }
- // Complete Line
- else if (fullLine && MOrder.DELIVERYRULE_CompleteLine.equals(order.getDeliveryRule()))
- {
- log.fine("CompleteLine - OnHand=" + onHand
- + " (Unconfirmed=" + unconfirmedShippedQty
- + ", ToDeliver=" + toDeliver + " - " + line);
- //
- createLine (order, line, toDeliver, storages, false);
- }
- // Availability
- else if (MOrder.DELIVERYRULE_Availability.equals(order.getDeliveryRule())
- && (onHand.signum() > 0
- || toDeliver.signum() < 0))
- {
- BigDecimal deliver = toDeliver;
- if (deliver.compareTo(onHand) > 0)
- deliver = onHand;
- log.fine("Available - OnHand=" + onHand
- + " (Unconfirmed=" + unconfirmedShippedQty
- + "), ToDeliver=" + toDeliver
- + ", Delivering=" + deliver + " - " + line);
- //
- createLine (order, line, deliver, storages, false);
- }
- // Force
- else if (MOrder.DELIVERYRULE_Force.equals(order.getDeliveryRule()))
- {
- BigDecimal deliver = toDeliver;
- log.fine("Force - OnHand=" + onHand
- + " (Unconfirmed=" + unconfirmedShippedQty
- + "), ToDeliver=" + toDeliver
- + ", Delivering=" + deliver + " - " + line);
- //
- createLine (order, line, deliver, storages, true);
- }
- // Manual
- else if (MOrder.DELIVERYRULE_Manual.equals(order.getDeliveryRule()))
- log.fine("Manual - OnHand=" + onHand
- + " (Unconfirmed=" + unconfirmedShippedQty
- + ") - " + line);
- else
- log.fine("Failed: " + order.getDeliveryRule() + " - OnHand=" + onHand
- + " (Unconfirmed=" + unconfirmedShippedQty
- + "), ToDeliver=" + toDeliver + " - " + line);
- } // for all order lines
-
- // Complete Order successful
- if (completeOrder && MOrder.DELIVERYRULE_CompleteOrder.equals(order.getDeliveryRule()))
- {
- for (int i = 0; i < lines.length; i++)
- {
- MOrderLine line = lines[i];
- if (line.getM_Warehouse_ID() != p_M_Warehouse_ID)
- continue;
- MProduct product = line.getProduct();
- BigDecimal toDeliver = line.getQtyOrdered().subtract(line.getQtyDelivered());
- //
- MStorage[] storages = null;
- if (product != null && product.isStocked())
- {
- String MMPolicy = product.getMMPolicy();
- storages = getStorages(line.getM_Warehouse_ID(),
- line.getM_Product_ID(), line.getM_AttributeSetInstance_ID(),
- product.getM_AttributeSet_ID(),
- line.getM_AttributeSetInstance_ID()==0, minGuaranteeDate,
- MClient.MMPOLICY_FiFo.equals(MMPolicy));
- }
- //
- createLine (order, line, toDeliver, storages, false);
- }
- }
- m_line += 1000;
- } // while order
- rs.close ();
- pstmt.close ();
- pstmt = null;
- }
- catch (Exception e)
- {
- log.log(Level.SEVERE, m_sql, e);
- }
- try
- {
- if (pstmt != null)
- pstmt.close ();
- pstmt = null;
- }
- catch (Exception e)
- {
- pstmt = null;
- }
- completeShipment();
- return "@Created@ = " + m_created;
- } // generate
-
-
-
- /**************************************************************************
- * Create Line
- * @param order order
- * @param orderLine line
- * @param qty qty
- * @param storages storage info
- * @param force force delivery
- */
- private void createLine (MOrder order, MOrderLine orderLine, BigDecimal qty,
- MStorage[] storages, boolean force)
- {
- // Complete last Shipment - can have multiple shipments
- if (m_lastC_BPartner_Location_ID != orderLine.getC_BPartner_Location_ID() )
- completeShipment();
- m_lastC_BPartner_Location_ID = orderLine.getC_BPartner_Location_ID();
- // Create New Shipment
- if (m_shipment == null)
- {
- m_shipment = new MInOut (order, 0, m_movementDate);
- m_shipment.setM_Warehouse_ID(orderLine.getM_Warehouse_ID()); // sets Org too
- if (order.getC_BPartner_ID() != orderLine.getC_BPartner_ID())
- m_shipment.setC_BPartner_ID(orderLine.getC_BPartner_ID());
- if (order.getC_BPartner_Location_ID() != orderLine.getC_BPartner_Location_ID())
- m_shipment.setC_BPartner_Location_ID(orderLine.getC_BPartner_Location_ID());
- if (!m_shipment.save())
- throw new IllegalStateException("Could not create Shipment");
- }
- // Non Inventory Lines
- if (storages == null)
- {
- MInOutLine line = new MInOutLine (m_shipment);
- line.setOrderLine(orderLine, 0, Env.ZERO);
- line.setQty(qty); // Correct UOM
- if (orderLine.getQtyEntered().compareTo(orderLine.getQtyOrdered()) != 0)
- line.setQtyEntered(qty
- .multiply(orderLine.getQtyEntered())
- .divide(orderLine.getQtyOrdered(), 12, BigDecimal.ROUND_HALF_UP));
- line.setLine(m_line + orderLine.getLine());
- if (!line.save())
- throw new IllegalStateException("Could not create Shipment Line");
- log.fine(line.toString());
- return;
- }
-
- // Product
- MProduct product = orderLine.getProduct();
- boolean linePerASI = false;
- if (product.getM_AttributeSet_ID() != 0)
- {
- MAttributeSet mas = MAttributeSet.get(getCtx(), product.getM_AttributeSet_ID());
- linePerASI = mas.isInstanceAttribute();
- }
-
- // Inventory Lines
- ArrayList list = new ArrayList();
- BigDecimal toDeliver = qty;
- for (int i = 0; i < storages.length; i++)
- {
- MStorage storage = storages[i];
- BigDecimal deliver = toDeliver;
- // Not enough On Hand
- if (deliver.compareTo(storage.getQtyOnHand()) > 0
- && storage.getQtyOnHand().signum() >= 0) // positive storage
- {
- if (!force // Adjust to OnHand Qty
- || (force && i+1 != storages.length)) // if force not on last location
- deliver = storage.getQtyOnHand();
- }
- if (deliver.signum() == 0) // zero deliver
- continue;
- int M_Locator_ID = storage.getM_Locator_ID();
- //
- MInOutLine line = null;
- if (!linePerASI) // find line with Locator
- {
- for (int ll = 0; ll < list.size(); ll++)
- {
- MInOutLine test = (MInOutLine)list.get(ll);
- if (test.getM_Locator_ID() == M_Locator_ID)
- {
- line = test;
- break;
- }
- }
- }
- if (line == null) // new line
- {
- line = new MInOutLine (m_shipment);
- line.setOrderLine(orderLine, M_Locator_ID, order.isSOTrx() ? deliver : Env.ZERO);
- line.setQty(deliver);
- list.add(line);
- }
- else // existing line
- line.setQty(line.getMovementQty().add(deliver));
- if (orderLine.getQtyEntered().compareTo(orderLine.getQtyOrdered()) != 0)
- line.setQtyEntered(line.getMovementQty().multiply(orderLine.getQtyEntered())
- .divide(orderLine.getQtyOrdered(), 12, BigDecimal.ROUND_HALF_UP));
- line.setLine(m_line + orderLine.getLine());
- if (linePerASI)
- line.setM_AttributeSetInstance_ID(storage.getM_AttributeSetInstance_ID());
- if (!line.save())
- throw new IllegalStateException("Could not create Shipment Line");
- log.fine("ToDeliver=" + qty + "/" + deliver + " - " + line);
- toDeliver = toDeliver.subtract(deliver);
- // Temp adjustment
- storage.setQtyOnHand(storage.getQtyOnHand().subtract(deliver));
- //
- if (toDeliver.signum() == 0)
- break;
- }
- if (toDeliver.signum() != 0)
- throw new IllegalStateException("Not All Delivered - Remainder=" + toDeliver);
- } // createLine
-
-
- /**
- * Get Storages
- * @param M_Warehouse_ID
- * @param M_Product_ID
- * @param M_AttributeSetInstance_ID
- * @param M_AttributeSet_ID
- * @param allAttributeInstances
- * @param minGuaranteeDate
- * @param FiFo
- * @return storages
- */
- private MStorage[] getStorages(int M_Warehouse_ID,
- int M_Product_ID, int M_AttributeSetInstance_ID, int M_AttributeSet_ID,
- boolean allAttributeInstances, Timestamp minGuaranteeDate,
- boolean FiFo)
- {
- m_lastPP = new SParameter(M_Warehouse_ID,
- M_Product_ID, M_AttributeSetInstance_ID, M_AttributeSet_ID,
- allAttributeInstances, minGuaranteeDate, FiFo);
- //
- m_lastStorages = m_map.get(m_lastPP);
-
- if (m_lastStorages == null)
- {
- m_lastStorages = MStorage.getWarehouse(getCtx(),
- M_Warehouse_ID, M_Product_ID, M_AttributeSetInstance_ID,
- M_AttributeSet_ID, allAttributeInstances, minGuaranteeDate,
- FiFo, get_TrxName());
- m_map.put(m_lastPP, m_lastStorages);
- }
- return m_lastStorages;
- } // getStorages
-
-
- /**
- * Complete Shipment
- */
- private void completeShipment()
- {
- if (m_shipment != null)
- {
- // Fails if there is a confirmation
- if (!m_shipment.processIt(p_docAction))
- log.warning("Failed: " + m_shipment);
- m_shipment.save();
- //
- addLog(m_shipment.getM_InOut_ID(), m_shipment.getMovementDate(), null, m_shipment.getDocumentNo());
- m_created++;
- m_map = new HashMap();
- if (m_lastPP != null && m_lastStorages != null)
- m_map.put(m_lastPP, m_lastStorages);
- }
- m_shipment = null;
- m_line = 0;
- } // completeOrder
-
- /**
- * InOutGenerate Parameter
- */
- class SParameter
- {
- /**
- * Parameter
- * @param p_Warehouse_ID warehouse
- * @param p_Product_ID
- * @param p_AttributeSetInstance_ID
- * @param p_AttributeSet_ID
- * @param p_allAttributeInstances
- * @param p_minGuaranteeDate
- * @param p_FiFo
- */
- protected SParameter (int p_Warehouse_ID,
- int p_Product_ID, int p_AttributeSetInstance_ID, int p_AttributeSet_ID,
- boolean p_allAttributeInstances, Timestamp p_minGuaranteeDate,
- boolean p_FiFo)
- {
- this.M_Warehouse_ID = p_Warehouse_ID;
- this.M_Product_ID = p_Product_ID;
- this.M_AttributeSetInstance_ID = p_AttributeSetInstance_ID;
- this.M_AttributeSet_ID = p_AttributeSet_ID;
- this.allAttributeInstances = p_allAttributeInstances;
- this.minGuaranteeDate = p_minGuaranteeDate;
- this.FiFo = p_FiFo;
- }
- /** Warehouse */
- public int M_Warehouse_ID;
- /** Product */
- public int M_Product_ID;
- /** ASI */
- public int M_AttributeSetInstance_ID;
- /** AS */
- public int M_AttributeSet_ID;
- /** All instances */
- public boolean allAttributeInstances;
- /** Mon Guarantee Date */
- public Timestamp minGuaranteeDate;
- /** FiFo */
- public boolean FiFo;
-
- /**
- * Equals
- * @param obj
- * @return true if equal
- */
- public boolean equals (Object obj)
- {
- if (obj != null && obj instanceof SParameter)
- {
- SParameter cmp = (SParameter)obj;
- boolean eq = cmp.M_Warehouse_ID == M_Warehouse_ID
- && cmp.M_Product_ID == M_Product_ID
- && cmp.M_AttributeSetInstance_ID == M_AttributeSetInstance_ID
- && cmp.M_AttributeSet_ID == M_AttributeSet_ID
- && cmp.allAttributeInstances == allAttributeInstances
- && cmp.FiFo == FiFo;
- if (eq)
- {
- if (cmp.minGuaranteeDate == null && minGuaranteeDate == null)
- ;
- else if (cmp.minGuaranteeDate != null && minGuaranteeDate != null
- && cmp.minGuaranteeDate.equals(minGuaranteeDate))
- ;
- else
- eq = false;
- }
- return eq;
- }
- return false;
- } // equals
-
- /**
- * hashCode
- * @return hash code
- */
- public int hashCode ()
- {
- long hash = M_Warehouse_ID
- + (M_Product_ID * 2)
- + (M_AttributeSetInstance_ID * 3)
- + (M_AttributeSet_ID * 4);
-
- if (allAttributeInstances)
- hash *= -1;
- if (FiFo);
- hash *= -2;
- if (hash < 0)
- hash = -hash + 7;
- while (hash > Integer.MAX_VALUE)
- hash -= Integer.MAX_VALUE;
- //
- if (minGuaranteeDate != null)
- {
- hash += minGuaranteeDate.hashCode();
- while (hash > Integer.MAX_VALUE)
- hash -= Integer.MAX_VALUE;
- }
-
- return (int)hash;
- } // hashCode
-
- } // Parameter
-
-} // InOutGenerate