IDEMPIERE-5776 Cannot generate shipment for an order with multiple lines for same product and Complete Order delivery rule (#1900)
This commit is contained in:
parent
86207d12ab
commit
3641e398ca
|
@ -362,6 +362,10 @@ public class InOutGenerate extends SvrProcess
|
|||
{
|
||||
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
|
||||
|
@ -426,6 +430,9 @@ public class InOutGenerate extends SvrProcess
|
|||
// 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];
|
||||
|
@ -638,6 +645,15 @@ public class InOutGenerate extends SvrProcess
|
|||
return m_lastStorages;
|
||||
} // getStorages
|
||||
|
||||
/**
|
||||
* Reset in memory map, array and parameters
|
||||
*/
|
||||
public void resetStorageCache()
|
||||
{
|
||||
m_map = new HashMap<SParameter,MStorageOnHand[]>();
|
||||
m_lastPP = null;
|
||||
m_lastStorages = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete Shipment
|
||||
|
@ -660,9 +676,7 @@ public class InOutGenerate extends SvrProcess
|
|||
m_created++;
|
||||
|
||||
//reset storage cache as MInOut.completeIt will update m_storage
|
||||
m_map = new HashMap<SParameter,MStorageOnHand[]>();
|
||||
m_lastPP = null;
|
||||
m_lastStorages = null;
|
||||
resetStorageCache();
|
||||
}
|
||||
m_shipment = null;
|
||||
m_line = 0;
|
||||
|
|
|
@ -406,8 +406,11 @@ public class MStorageOnHand extends X_M_StorageOnHand
|
|||
allAttributeInstances = true;
|
||||
|
||||
ArrayList<MStorageOnHand> list = new ArrayList<MStorageOnHand>();
|
||||
String sql;
|
||||
if (! allAttributeInstances)
|
||||
{
|
||||
// Specific Attribute Set Instance
|
||||
String sql = "SELECT s.M_Product_ID,s.M_Locator_ID,s.M_AttributeSetInstance_ID,"
|
||||
sql = "SELECT s.M_Product_ID,s.M_Locator_ID,s.M_AttributeSetInstance_ID,"
|
||||
+ "s.AD_Client_ID,s.AD_Org_ID,s.IsActive,s.Created,s.CreatedBy,s.Updated,s.UpdatedBy,"
|
||||
+ "s.QtyOnHand,s.DateLastInventory,s.M_StorageOnHand_UU,s.DateMaterialPolicy "
|
||||
+ "FROM M_StorageOnHand s"
|
||||
|
@ -431,9 +434,10 @@ public class MStorageOnHand extends X_M_StorageOnHand
|
|||
sql += " DESC, s.M_AttributeSetInstance_ID DESC ";
|
||||
else
|
||||
sql += ", s.M_AttributeSetInstance_ID ";
|
||||
// All Attribute Set Instances
|
||||
if (allAttributeInstances)
|
||||
}
|
||||
else
|
||||
{
|
||||
// All Attribute Set Instances
|
||||
sql = "SELECT s.M_Product_ID,s.M_Locator_ID,s.M_AttributeSetInstance_ID,"
|
||||
+ " s.AD_Client_ID,s.AD_Org_ID,s.IsActive,s.Created,s.CreatedBy,s.Updated,s.UpdatedBy,"
|
||||
+ " s.QtyOnHand,s.DateLastInventory,s.M_StorageOnHand_UU,s.DateMaterialPolicy "
|
||||
|
@ -453,14 +457,11 @@ public class MStorageOnHand extends X_M_StorageOnHand
|
|||
{
|
||||
sql += " AND s.QtyOnHand <> 0 ";
|
||||
}
|
||||
|
||||
if (minGuaranteeDate != null)
|
||||
{
|
||||
sql += " AND (asi.GuaranteeDate IS NULL OR asi.GuaranteeDate>?) ";
|
||||
}
|
||||
|
||||
MProduct product = MProduct.get(Env.getCtx(), M_Product_ID);
|
||||
|
||||
if(product.isUseGuaranteeDateForMPolicy()){
|
||||
sql += " ORDER BY l.PriorityNo DESC, COALESCE(asi.GuaranteeDate,s.DateMaterialPolicy)";
|
||||
if (!FiFo)
|
||||
|
@ -476,7 +477,6 @@ public class MStorageOnHand extends X_M_StorageOnHand
|
|||
else
|
||||
sql += ", s.M_AttributeSetInstance_ID ";
|
||||
}
|
||||
|
||||
sql += ", s.QtyOnHand DESC";
|
||||
}
|
||||
PreparedStatement pstmt = null;
|
||||
|
|
|
@ -1526,4 +1526,74 @@ public class SalesOrderTest extends AbstractTestCase {
|
|||
}
|
||||
assertEquals(orderTaxes.length, match, "MOrdexTax record doesn't match child tax records");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenerateShipmentCompleteMultiSameLine() {
|
||||
// CompleteOrder with 2 lines with almost the available on hand
|
||||
MOrder order = new MOrder(Env.getCtx(), 0, getTrxName());
|
||||
//Joe Block
|
||||
order.setBPartner(MBPartner.get(Env.getCtx(), DictionaryIDs.C_BPartner.JOE_BLOCK.id));
|
||||
order.setC_DocTypeTarget_ID(MOrder.DocSubTypeSO_Standard);
|
||||
order.setDeliveryRule(MOrder.DELIVERYRULE_CompleteOrder);
|
||||
order.setDocStatus(DocAction.STATUS_Drafted);
|
||||
order.setDocAction(DocAction.ACTION_Complete);
|
||||
Timestamp today = TimeUtil.getDay(System.currentTimeMillis());
|
||||
order.setDateOrdered(today);
|
||||
order.setDatePromised(today);
|
||||
order.saveEx();
|
||||
|
||||
BigDecimal qtyOnHandMinusOne = MStorageOnHand.getQtyOnHandForShipping(DictionaryIDs.M_Product.AZALEA_BUSH.id, order.getM_Warehouse_ID(), 0, getTrxName());
|
||||
if (qtyOnHandMinusOne.signum() > 0)
|
||||
qtyOnHandMinusOne = qtyOnHandMinusOne.subtract(Env.ONE);
|
||||
|
||||
MOrderLine line1 = new MOrderLine(order);
|
||||
line1.setLine(10);
|
||||
line1.setProduct(MProduct.get(Env.getCtx(), DictionaryIDs.M_Product.AZALEA_BUSH.id));
|
||||
line1.setQty(qtyOnHandMinusOne);
|
||||
line1.setDatePromised(today);
|
||||
line1.saveEx();
|
||||
|
||||
MOrderLine line2 = new MOrderLine(order);
|
||||
line2.setLine(20);
|
||||
line2.setProduct(MProduct.get(Env.getCtx(), DictionaryIDs.M_Product.AZALEA_BUSH.id));
|
||||
line2.setQty(qtyOnHandMinusOne);
|
||||
line2.setDatePromised(today);
|
||||
line2.saveEx();
|
||||
|
||||
ProcessInfo info = MWorkflow.runDocumentActionWorkflow(order, DocAction.ACTION_Complete);
|
||||
assertFalse(info.isError(), info.getSummary());
|
||||
order.load(getTrxName());
|
||||
assertEquals(DocAction.STATUS_Completed, order.getDocStatus());
|
||||
|
||||
int AD_Process_ID = PROCESS_M_INOUT_GENERATE_MANUAL;
|
||||
MPInstance instance = new MPInstance(Env.getCtx(), AD_Process_ID, 0);
|
||||
instance.saveEx();
|
||||
|
||||
String insert = "INSERT INTO T_SELECTION(AD_PINSTANCE_ID, T_SELECTION_ID) Values (?, ?)";
|
||||
DB.executeUpdateEx(insert, new Object[] {instance.getAD_PInstance_ID(), order.getC_Order_ID()}, null);
|
||||
|
||||
//call process
|
||||
ProcessInfo pi = new ProcessInfo ("InOutGen", AD_Process_ID);
|
||||
pi.setAD_PInstance_ID (instance.getAD_PInstance_ID());
|
||||
|
||||
// Add Parameter - Selection=Y
|
||||
MPInstancePara ip = new MPInstancePara(instance, 10);
|
||||
ip.setParameter("Selection","Y");
|
||||
ip.saveEx();
|
||||
//Add Document action parameter
|
||||
ip = new MPInstancePara(instance, 20);
|
||||
ip.setParameter("DocAction", "PR");
|
||||
ip.saveEx();
|
||||
// Add Parameter - M_Warehouse_ID=x
|
||||
ip = new MPInstancePara(instance, 30);
|
||||
ip.setParameter("M_Warehouse_ID", getM_Warehouse_ID());
|
||||
ip.saveEx();
|
||||
|
||||
ServerProcessCtl processCtl = new ServerProcessCtl(pi, getTrx());
|
||||
processCtl.setManagedTrxForJavaProcess(false);
|
||||
processCtl.run();
|
||||
|
||||
assertFalse(pi.isError(), pi.getSummary());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue