IDEMPIERE-4587 Wrong ordered qty when reactivating a purchase order and setting a line to zero (#445)

This commit is contained in:
Carlos Ruiz 2020-12-09 20:49:01 +01:00 committed by GitHub
parent 9ed69583e8
commit d654ed5791
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 126 additions and 3 deletions

View File

@ -1416,7 +1416,7 @@ public class MInOut extends X_M_InOut implements DocAction
}
}
if (oLine!=null && mtrx!=null && oLine.getQtyOrdered().signum() > 0)
if (oLine!=null && mtrx!=null && oLine.getQtyOrdered().signum() >= 0)
{
if (sLine.getC_OrderLine_ID() != 0)
{
@ -1467,7 +1467,7 @@ public class MInOut extends X_M_InOut implements DocAction
m_processMsg = "Cannot correct Inventory OnHand [" + product.getValue() + "] - " + lastError;
return DocAction.STATUS_Invalid;
}
if (oLine!=null && oLine.getQtyOrdered().signum() > 0)
if (oLine!=null && oLine.getQtyOrdered().signum() >= 0)
{
if (!MStorageReservation.add(getCtx(), oLine.getM_Warehouse_ID(),
sLine.getM_Product_ID(),
@ -1496,7 +1496,7 @@ public class MInOut extends X_M_InOut implements DocAction
// Correct Order Line
if (product != null && oLine != null) // other in VMatch.createMatchRecord
{
if (oLine.getQtyOrdered().signum() > 0)
if (oLine.getQtyOrdered().signum() >= 0)
{
oLine.setQtyReserved(oLine.getQtyReserved().subtract(sLine.getMovementQty().subtract(sLine.getQtyOverReceipt())));

View File

@ -2188,6 +2188,10 @@ public class MOrder extends X_C_Order implements DocAction
MInOutLine ioLine = new MInOutLine(shipment);
// Qty = Ordered - Delivered
BigDecimal MovementQty = oLine.getQtyOrdered().subtract(oLine.getQtyDelivered());
if (MovementQty.signum() == 0 && getProcessedOn().signum() != 0) {
// do not create lines with qty = 0 when the order is reactivated and completed again
continue;
}
// Location
int M_Locator_ID = MStorageOnHand.getM_Locator_ID (oLine.getM_Warehouse_ID(),
oLine.getM_Product_ID(), oLine.getM_AttributeSetInstance_ID(),

View File

@ -39,6 +39,8 @@ import org.compiere.model.MInvoiceLine;
import org.compiere.model.MOrder;
import org.compiere.model.MOrderLine;
import org.compiere.model.MProduct;
import org.compiere.model.MStorageOnHand;
import org.compiere.model.MStorageReservation;
import org.compiere.process.DocAction;
import org.compiere.process.ProcessInfo;
import org.compiere.util.Env;
@ -61,7 +63,10 @@ public class PurchaseOrderTest extends AbstractTestCase {
private static final int DOCTYPE_AP_INVOICE = 123;
private static final int PRODUCT_SEEDER = 143;
private static final int PRODUCT_WEEDER = 141;
private static final int PRODUCT_MULCH = 137;
private static final int USER_GARDENADMIN = 101;
private static final BigDecimal THREE = new BigDecimal("3");
private static final BigDecimal MINUS_THREE = new BigDecimal("-3");
/**
* https://idempiere.atlassian.net/browse/IDEMPIERE-4575
@ -198,4 +203,118 @@ public class PurchaseOrderTest extends AbstractTestCase {
}
/*
* IDEMPIERE-4587
*/
@Test
public void testOrderedStorageForReactivatedOrder() {
Properties ctx = Env.getCtx();
String trxName = getTrxName();
BigDecimal qtyOrderedOriginal = getQtyOrdered(ctx, PRODUCT_MULCH, trxName);
MOrder order = new MOrder(ctx, 0, trxName);
order.setBPartner(MBPartner.get(ctx, BP_PATIO));
order.setC_DocTypeTarget_ID(DOCTYPE_PO);
order.setIsSOTrx(false);
order.setSalesRep_ID(USER_GARDENADMIN);
order.setDocStatus(DocAction.STATUS_Drafted);
order.setDocAction(DocAction.ACTION_Complete);
Timestamp today = TimeUtil.getDay(System.currentTimeMillis());
order.setDateOrdered(today);
order.setDatePromised(today);
order.saveEx();
MOrderLine line1 = new MOrderLine(order);
line1.setLine(10);
line1.setProduct(MProduct.get(ctx, PRODUCT_MULCH));
line1.setQty(THREE);
line1.setDatePromised(today);
line1.saveEx();
ProcessInfo info = MWorkflow.runDocumentActionWorkflow(order, DocAction.ACTION_Complete);
assertFalse(info.isError());
order.load(trxName);
assertEquals(DocAction.STATUS_Completed, order.getDocStatus());
line1.load(trxName);
assertEquals(0, line1.getQtyReserved().compareTo(THREE));
BigDecimal newQtyOrdered = getQtyOrdered(ctx, PRODUCT_MULCH, trxName);
assertEquals(0, qtyOrderedOriginal.add(THREE).compareTo(newQtyOrdered));
MInOut receipt1 = new MInOut(order, DOCTYPE_RECEIPT, order.getDateOrdered());
receipt1.setDocStatus(DocAction.STATUS_Drafted);
receipt1.setDocAction(DocAction.ACTION_Complete);
receipt1.saveEx();
MInOutLine receiptLine1 = new MInOutLine(receipt1);
receiptLine1.setOrderLine(line1, 0, THREE);
receiptLine1.setQty(THREE);
receiptLine1.saveEx();
info = MWorkflow.runDocumentActionWorkflow(receipt1, DocAction.ACTION_Complete);
assertFalse(info.isError());
receipt1.load(trxName);
assertEquals(DocAction.STATUS_Completed, receipt1.getDocStatus());
line1.load(trxName);
assertEquals(0, line1.getQtyReserved().compareTo(Env.ZERO));
newQtyOrdered = getQtyOrdered(ctx, PRODUCT_MULCH, trxName);
assertEquals(0, qtyOrderedOriginal.compareTo(newQtyOrdered));
// reactivate the purchase order
info = MWorkflow.runDocumentActionWorkflow(order, DocAction.ACTION_ReActivate);
assertFalse(info.isError());
order.load(trxName);
assertEquals(DocAction.STATUS_InProgress, order.getDocStatus());
// change the line quantity to zero
line1.load(trxName);
line1.setQty(Env.ZERO);
line1.saveEx();
// complete the order again
info = MWorkflow.runDocumentActionWorkflow(order, DocAction.ACTION_Complete);
assertFalse(info.isError());
order.load(trxName);
assertEquals(DocAction.STATUS_Completed, order.getDocStatus());
line1.load(trxName);
assertEquals(0, line1.getQtyReserved().compareTo(MINUS_THREE));
newQtyOrdered = getQtyOrdered(ctx, PRODUCT_MULCH, trxName);
assertEquals(0, qtyOrderedOriginal.add(MINUS_THREE).compareTo(newQtyOrdered));
// create a new material receipt for the -3 reversed
MInOut receipt2 = new MInOut(order, DOCTYPE_RECEIPT, order.getDateOrdered());
receipt2.setDocStatus(DocAction.STATUS_Drafted);
receipt2.setDocAction(DocAction.ACTION_Complete);
receipt2.saveEx();
MInOutLine receiptLine2 = new MInOutLine(receipt2);
receiptLine2.setOrderLine(line1, 0, MINUS_THREE);
receiptLine2.setQty(MINUS_THREE);
receiptLine2.saveEx();
info = MWorkflow.runDocumentActionWorkflow(receipt2, DocAction.ACTION_Complete);
assertFalse(info.isError());
receipt2.load(trxName);
assertEquals(DocAction.STATUS_Completed, receipt2.getDocStatus());
line1.load(trxName);
assertEquals(0, line1.getQtyReserved().compareTo(Env.ZERO));
newQtyOrdered = getQtyOrdered(ctx, PRODUCT_MULCH, trxName);
assertEquals(0, qtyOrderedOriginal.compareTo(newQtyOrdered));
}
private BigDecimal getQtyOrdered(Properties ctx, int M_Product_ID, String trxName) {
BigDecimal qtyOrdered = Env.ZERO;
for (MStorageReservation rs : MStorageReservation.getOfProduct(ctx, M_Product_ID, trxName)) {
if (! rs.isSOTrx())
qtyOrdered = qtyOrdered.add(rs.getQty());
}
return qtyOrdered;
}
}