/****************************************************************************** * 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.BigDecimal; import java.math.RoundingMode; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.Timestamp; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.logging.Level; import org.adempiere.exceptions.AdempiereException; import org.compiere.model.MClient; import org.compiere.model.MInOut; import org.compiere.model.MInOutLine; import org.compiere.model.MLocator; import org.compiere.model.MLocatorType; import org.compiere.model.MOrder; import org.compiere.model.MOrderLine; import org.compiere.model.MProcessPara; import org.compiere.model.MProduct; import org.compiere.model.MStorageOnHand; import org.compiere.model.Query; import org.compiere.util.AdempiereUserError; import org.compiere.util.DB; import org.compiere.util.Env; import org.compiere.util.Msg; /** * Generate Shipments. * Manual or Automatic * * @author Jorg Janke * @version $Id: InOutGenerate.java,v 1.2 2006/07/30 00:51:01 jjanke Exp $ */ @org.adempiere.base.annotation.Process 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; /** Reserve on hand for this inout */ private boolean p_SubtractOnHand = false; /** DocAction */ private String p_docAction = DocAction.ACTION_None; /** Consolidate */ private boolean p_ConsolidateDocument = true; /** Shipment Date */ private Timestamp p_DateShipped = null; /** The current Shipment */ private MInOut m_shipment = null; /** Number of Shipments being created */ 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 StringBuffer m_sql = null; /** Storages temp space */ private HashMap m_map = new HashMap(); /** Last Parameter */ private SParameter m_lastPP = null; /** Last Storage */ private MStorageOnHand[] 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("SubtractOnHand")) p_SubtractOnHand = "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 MProcessPara.validateUnknownParameter(getProcessInfo().getAD_Process_ID(), para[i]); } // juddm - added ability to specify a shipment date from Generate Shipments if (p_DateShipped == null) { m_movementDate = Env.getContextAsDate(getCtx(), Env.DATE); if (m_movementDate == null) m_movementDate = new Timestamp(System.currentTimeMillis()); } else m_movementDate = p_DateShipped; } // prepare /** * Generate Shipments * @return info * @throws Exception */ protected String doIt () throws Exception { if (log.isLoggable(Level.INFO)) 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 ((getProcessInfo().getAD_InfoWindow_ID() > 0) || (getProcessInfo().getAD_InfoWindow_ID()==0 && p_Selection)) { p_Selection = true; m_sql = new StringBuffer("SELECT C_Order.* FROM C_Order, T_Selection ") .append("WHERE C_Order.DocStatus='CO' AND C_Order.IsSOTrx='Y' AND C_Order.AD_Client_ID=? ") .append("AND C_Order.C_Order_ID = T_Selection.T_Selection_ID ") .append("AND T_Selection.AD_PInstance_ID=? "); } else { if (p_M_Warehouse_ID == 0) throw new AdempiereUserError("@NotFound@ @M_Warehouse_ID@"); m_sql = new StringBuffer("SELECT o.* FROM m_inout_candidate_v ioc JOIN C_Order o ON o.C_Order_ID = ioc.C_Order_ID" + " LEFT JOIN M_Shipper ship ON ship.M_Shipper_ID = o.M_Shipper_ID" + " WHERE DocStatus='CO' AND IsSOTrx='Y' " + " AND ioc.AD_Client_ID = " + getAD_Client_ID()) // No Offer,POS .append(" AND o.C_DocType_ID IN (SELECT C_DocType_ID FROM C_DocType ") .append("WHERE DocBaseType='SOO' AND DocSubTypeSO NOT IN ('ON','OB','WR'))") // No Manual .append(" AND o.DeliveryRule<>'M'") // Open Order Lines with Warehouse .append(" AND EXISTS (SELECT * FROM C_OrderLine ol ") .append("WHERE ol.M_Warehouse_ID=? AND ioc.DocSource = 'O' "); // #1 if (p_DatePromised != null) m_sql.append(" AND TRUNC(ol.DatePromised)<=?"); // #2 m_sql.append(" AND o.C_Order_ID=ol.C_Order_ID AND ol.QtyOrdered<>ol.QtyDelivered)"); // if (p_C_BPartner_ID != 0) m_sql.append(" AND o.C_BPartner_ID=?"); // #3 } m_sql.append(" ORDER BY M_Warehouse_ID, PriorityRule, M_Shipper_ID, C_BPartner_ID, C_BPartner_Location_ID, C_Order_ID"); PreparedStatement pstmt = null; try { pstmt = DB.prepareStatement (m_sql.toString(), 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) { DB.close(pstmt); throw new AdempiereException(e); } return generate(pstmt); } // doIt /** * Generate Shipments * @param pstmt Order Query * @return info */ private String generate (PreparedStatement pstmt) { ResultSet rs = null; try { rs = pstmt.executeQuery (); while (rs.next ()) // Order { MOrder order = new MOrder (getCtx(), rs, get_TrxName()); statusUpdate(Msg.getMsg(getCtx(), "Processing") + " " + order.getDocumentInfo()); if (MOrder.DELIVERYRULE_AfterPayment.equals(order.getDeliveryRule())) { BigDecimal payment = order.getPaymentAmt(); if (payment == null || payment.compareTo(order.getGrandTotal()) < 0) continue; } //load warehouse if(p_M_Warehouse_ID == 0) p_M_Warehouse_ID = order.getM_Warehouse_ID(); // 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(); if (log.isLoggable(Level.FINE)) log.fine("check: " + order + " - DeliveryRule=" + order.getDeliveryRule()); // Timestamp minGuaranteeDate = m_movementDate; boolean completeOrder = MOrder.DELIVERYRULE_CompleteOrder.equals(order.getDeliveryRule()); // OrderLine WHERE StringBuilder where = new StringBuilder(" AND M_Warehouse_ID=").append(p_M_Warehouse_ID); if (p_DatePromised != null) where.append(" AND (TRUNC(DatePromised)<=").append(DB.TO_DATE(p_DatePromised, true)) .append(" OR DatePromised IS NULL)"); // Exclude Auto Delivery if not Force if (!MOrder.DELIVERYRULE_Force.equals(order.getDeliveryRule())) where.append(" AND (C_OrderLine.M_Product_ID IS NULL") .append(" OR EXISTS (SELECT * FROM M_Product p ") .append("WHERE C_OrderLine.M_Product_ID=p.M_Product_ID") .append(" AND IsExcludeAutoDelivery='N'))"); // Exclude Unconfirmed if (!p_IsUnconfirmedInOut) where.append(" AND NOT EXISTS (SELECT * FROM M_InOutLine iol") .append(" INNER JOIN M_InOut io ON (iol.M_InOut_ID=io.M_InOut_ID) ") .append("WHERE iol.C_OrderLine_ID=C_OrderLine.C_OrderLine_ID AND io.DocStatus IN ('DR','IN','IP','WC'))"); // Deadlock Prevention - Order by M_Product_ID MOrderLine[] lines = order.getLines (where.toString(), "C_BPartner_Location_ID, M_Product_ID, Line"); for (int i = 0; i < lines.length; i++) { MOrderLine line = lines[i]; if (line.getM_Warehouse_ID() != p_M_Warehouse_ID) continue; if (log.isLoggable(Level.FINE)) 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; BigDecimal totalunconfirmedShippedQty = Env.ZERO; StringBuilder logInfo = null; 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 ('DR','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()); if (log.isLoggable(Level.FINE)) logInfo = new StringBuilder("Unconfirmed Qty=").append(unconfirmedShippedQty) .append(" - ToDeliver=").append(toDeliver).append("->"); toDeliver = toDeliver.subtract(unconfirmedShippedQty); if (log.isLoggable(Level.FINE)) logInfo.append(toDeliver); if (toDeliver.signum() < 0) { toDeliver = Env.ZERO; if (log.isLoggable(Level.FINE)) logInfo.append(" (set to 0)"); } if (log.isLoggable(Level.FINE) && logInfo.length() > 0) log.fine(logInfo.toString()); if (toDeliver.signum() == 0) { if (completeOrder) completeOrder = false; continue; } } if (product != null && toDeliver.signum() != 0) { // Adjust On Hand if(p_SubtractOnHand) { StringBuilder where3 = new StringBuilder ( "EXISTS (SELECT * FROM M_InOut io " + "WHERE io.M_InOut_ID=M_InOutLine.M_InOut_ID " + "AND io.IsSOTrx = 'Y' " + "AND io.DocStatus IN ('IP','WC') " + "AND io.M_Warehouse_ID=").append(p_M_Warehouse_ID).append (") " + "AND M_Product_ID = ").append(line.getM_Product_ID()); totalunconfirmedShippedQty = new Query(getCtx(), MInOutLine.Table_Name, where3.toString(), get_TrxName()) .aggregate(MInOutLine.COLUMNNAME_MovementQty, Query.AGGREGATE_SUM); onHand = onHand.subtract(totalunconfirmedShippedQty); } else if (unconfirmedShippedQty.signum() != 0){ onHand = onHand.subtract(unconfirmedShippedQty); } } // 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; } if (product == null) { continue; } // Stored Product String MMPolicy = product.getMMPolicy(); MStorageOnHand[] 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++) { MStorageOnHand storage = storages[j]; onHand = onHand.add(storage.getQtyOnHand()); if (completeOrder && j == 0) { // CompleteOrder is created at the end, so we need to subtract here to keep track of what is "consumed" storage.setQtyOnHand(storage.getQtyOnHand().subtract(toDeliver)); } } boolean autoProduce = product.isBOM() && product.isVerified() && product.isAutoProduce(); boolean fullLine = onHand.compareTo(toDeliver) >= 0 || toDeliver.signum() < 0 || autoProduce; // Complete Order if (completeOrder && !fullLine) { if (log.isLoggable(Level.FINE)) 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())) { if (log.isLoggable(Level.FINE)) 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()) || MOrder.DELIVERYRULE_AfterPayment.equals(order.getDeliveryRule())) && (onHand.signum() > 0 || toDeliver.signum() < 0 || autoProduce)) { BigDecimal deliver = toDeliver; if (deliver.compareTo(onHand) > 0 && !autoProduce) deliver = onHand; if (log.isLoggable(Level.FINE)) 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; if (log.isLoggable(Level.FINE)) 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())) { if (log.isLoggable(Level.FINE)) log.fine("Manual - OnHand=" + onHand + " (Unconfirmed=" + unconfirmedShippedQty + ") - " + line); } else { if (log.isLoggable(Level.FINE)) 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())) { // reset storage cache - it was updated in memory above resetStorageCache(); 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()); // MStorageOnHand[] 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 } catch (Exception e) { throw new AdempiereException(e); } finally { DB.close(rs, pstmt); rs = null; pstmt = null; } completeShipment(); StringBuilder msgreturn = new StringBuilder("@Created@ = ").append(m_created); return msgreturn.toString(); } // 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, MStorageOnHand[] 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, RoundingMode.HALF_UP)); line.setLine(m_line + orderLine.getLine()); if (!line.save()) throw new IllegalStateException("Could not create Shipment Line"); if (log.isLoggable(Level.FINE)) log.fine(line.toString()); return; } // Inventory Lines ArrayList list = new ArrayList(); BigDecimal toDeliver = qty; for (int i = 0; i < storages.length; i++) { MStorageOnHand storage = storages[i]; BigDecimal deliver = toDeliver; //skip negative storage record if (storage.getQtyOnHand().signum() < 0) continue; // 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; int olAsiID = orderLine.getM_AttributeSetInstance_ID(); 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() == olAsiID) { 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, RoundingMode.HALF_UP)); line.setLine(m_line + orderLine.getLine()); if (!line.save()) throw new IllegalStateException("Could not create Shipment Line"); if (log.isLoggable(Level.FINE)) log.fine("ToDeliver=" + qty + "/" + deliver + " - " + line); toDeliver = toDeliver.subtract(deliver); // Temp adjustment, actual update happen in MInOut.completeIt - just in memory - not saved storage.setQtyOnHand(storage.getQtyOnHand().subtract(deliver)); // if (toDeliver.signum() == 0) break; } if (toDeliver.signum() != 0) { MProduct product = MProduct.get(orderLine.getM_Product_ID()); boolean autoProduce = product.isBOM() && product.isVerified() && product.isAutoProduce(); if (!force && toDeliver.signum() > 0 && !autoProduce) { 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 (orderLine.getQtyEntered().compareTo(orderLine.getQtyOrdered()) != 0) line.setQtyEntered(line.getMovementQty().multiply(orderLine.getQtyEntered()) .divide(orderLine.getQtyOrdered(), 12, RoundingMode.HALF_UP)); line.setLine(m_line + orderLine.getLine()); 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 MStorageOnHand[] 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) { MStorageOnHand[] tmpStorages = MStorageOnHand.getWarehouse(getCtx(), M_Warehouse_ID, M_Product_ID, M_AttributeSetInstance_ID, minGuaranteeDate, FiFo,false, 0, get_TrxName()); /* IDEMPIERE-2668 - filter just locators enabled for shipping */ List m_storagesForShipping = new ArrayList(); for (MStorageOnHand soh : tmpStorages) { MLocator loc = MLocator.get(getCtx(), soh.getM_Locator_ID()); MLocatorType lt = null; if (loc.getM_LocatorType_ID() > 0) lt = MLocatorType.get(getCtx(), loc.getM_LocatorType_ID()); if (lt == null || lt.isAvailableForShipping()) m_storagesForShipping.add(soh); } m_lastStorages = new MStorageOnHand[m_storagesForShipping.size()]; m_storagesForShipping.toArray(m_lastStorages); m_map.put(m_lastPP, m_lastStorages); } return m_lastStorages; } // getStorages /** * Reset in memory map, array and parameters */ public void resetStorageCache() { m_map = new HashMap(); m_lastPP = null; m_lastStorages = null; } /** * Complete Shipment */ private void completeShipment() { if (m_shipment != null) { if (!DocAction.ACTION_None.equals(p_docAction)) { // Fails if there is a confirmation if (!m_shipment.processIt(p_docAction)) { log.warning("Failed: " + m_shipment); throw new IllegalStateException("Shipment Process Failed: " + m_shipment + " - " + m_shipment.getProcessMsg()); } } m_shipment.saveEx(); String message = Msg.parseTranslation(getCtx(), "@ShipmentProcessed@ " + m_shipment.getDocumentNo()); addBufferLog(m_shipment.getM_InOut_ID(), m_shipment.getMovementDate(), null, message, m_shipment.get_Table_ID(),m_shipment.getM_InOut_ID()); m_created++; //reset storage cache as MInOut.completeIt will update m_storage resetStorageCache(); } m_shipment = null; m_line = 0; } // completeOrder /** * InOutGenerate Parameter */ static 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