diff --git a/org.adempiere.base/src/org/compiere/model/MInOut.java b/org.adempiere.base/src/org/compiere/model/MInOut.java index 31fc959547..f9fe2dd676 100644 --- a/org.adempiere.base/src/org/compiere/model/MInOut.java +++ b/org.adempiere.base/src/org/compiere/model/MInOut.java @@ -1508,7 +1508,15 @@ public class MInOut extends X_M_InOut implements DocAction // Correct Order Line if (product != null && oLine != null) // other in VMatch.createMatchRecord { - oLine.setQtyReserved(oLine.getQtyReserved().subtract(sLine.getMovementQty().subtract(sLine.getQtyOverReceipt()))); + if (oLine.getQtyOrdered().signum() > 0) + { + oLine.setQtyReserved(oLine.getQtyReserved().subtract(sLine.getMovementQty().subtract(sLine.getQtyOverReceipt()))); + + if (oLine.getQtyReserved().signum() == -1) + oLine.setQtyReserved(Env.ZERO); + else if (oLine.getQtyDelivered().compareTo(oLine.getQtyOrdered()) > 0) + oLine.setQtyReserved(Env.ZERO); + } } // Update Sales Order Line diff --git a/org.idempiere.test/src/org/idempiere/test/model/SalesOrderTest.java b/org.idempiere.test/src/org/idempiere/test/model/SalesOrderTest.java index d025c22983..4edd36c382 100644 --- a/org.idempiere.test/src/org/idempiere/test/model/SalesOrderTest.java +++ b/org.idempiere.test/src/org/idempiere/test/model/SalesOrderTest.java @@ -32,6 +32,8 @@ import java.math.BigDecimal; import java.sql.Timestamp; import org.compiere.model.MBPartner; +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; @@ -159,4 +161,121 @@ public class SalesOrderTest extends AbstractTestCase { rollback(); } + + @Test + public void testQtyReservedForOverAndNegativeShipment() { + MOrder order = new MOrder(Env.getCtx(), 0, getTrxName()); + //Joe Block + order.setBPartner(MBPartner.get(Env.getCtx(), 118)); + 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(); + + MOrderLine line1 = new MOrderLine(order); + line1.setLine(10); + //Azalea Bush + line1.setProduct(MProduct.get(Env.getCtx(), 128)); + line1.setQty(new BigDecimal("1")); + line1.setDatePromised(today); + line1.saveEx(); + + ProcessInfo info = MWorkflow.runDocumentActionWorkflow(order, DocAction.ACTION_Complete); + assertFalse(info.isError()); + order.load(getTrxName()); + assertEquals(DocAction.STATUS_Completed, order.getDocStatus()); + line1.load(getTrxName()); + assertEquals(1, line1.getQtyReserved().intValue()); + + MInOut shipment = new MInOut(order, 120, order.getDateOrdered()); + shipment.setDocStatus(DocAction.STATUS_Drafted); + shipment.setDocAction(DocAction.ACTION_Complete); + shipment.saveEx(); + + //over shipment + MInOutLine shipmentLine = new MInOutLine(shipment); + shipmentLine.setOrderLine(line1, 0, new BigDecimal("2")); + shipmentLine.setQty(new BigDecimal("2")); + shipmentLine.saveEx(); + + info = MWorkflow.runDocumentActionWorkflow(shipment, DocAction.ACTION_Complete); + assertFalse(info.isError()); + shipment.load(getTrxName()); + assertEquals(DocAction.STATUS_Completed, shipment.getDocStatus()); + + line1.load(getTrxName()); + assertEquals(0, line1.getQtyReserved().intValue()); + + shipment = new MInOut(order, 120, order.getDateOrdered()); + shipment.setDocStatus(DocAction.STATUS_Drafted); + shipment.setDocAction(DocAction.ACTION_Complete); + shipment.saveEx(); + + //-1 to correct over shipment + shipmentLine = new MInOutLine(shipment); + shipmentLine.setOrderLine(line1, 0, new BigDecimal("-1")); + shipmentLine.setQty(new BigDecimal("-1")); + shipmentLine.saveEx(); + + info = MWorkflow.runDocumentActionWorkflow(shipment, DocAction.ACTION_Complete); + assertFalse(info.isError()); + shipment.load(getTrxName()); + assertEquals(DocAction.STATUS_Completed, shipment.getDocStatus()); + + line1.load(getTrxName()); + assertEquals(0, line1.getQtyReserved().intValue()); + } + + @Test + public void testQtyReservedForNegativeOrderAndShipment() { + MOrder order = new MOrder(Env.getCtx(), 0, getTrxName()); + //Joe Block + order.setBPartner(MBPartner.get(Env.getCtx(), 118)); + 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(); + + MOrderLine line1 = new MOrderLine(order); + line1.setLine(10); + //Azalea Bush + line1.setProduct(MProduct.get(Env.getCtx(), 128)); + line1.setQty(new BigDecimal("-1")); + line1.setDatePromised(today); + line1.saveEx(); + + ProcessInfo info = MWorkflow.runDocumentActionWorkflow(order, DocAction.ACTION_Complete); + assertFalse(info.isError()); + order.load(getTrxName()); + assertEquals(DocAction.STATUS_Completed, order.getDocStatus()); + line1.load(getTrxName()); + assertEquals(0, line1.getQtyReserved().intValue()); + + MInOut shipment = new MInOut(order, 120, order.getDateOrdered()); + shipment.setDocStatus(DocAction.STATUS_Drafted); + shipment.setDocAction(DocAction.ACTION_Complete); + shipment.saveEx(); + + //over shipment + MInOutLine shipmentLine = new MInOutLine(shipment); + shipmentLine.setOrderLine(line1, 0, new BigDecimal("-1")); + shipmentLine.setQty(new BigDecimal("-1")); + shipmentLine.saveEx(); + + info = MWorkflow.runDocumentActionWorkflow(shipment, DocAction.ACTION_Complete); + assertFalse(info.isError()); + shipment.load(getTrxName()); + assertEquals(DocAction.STATUS_Completed, shipment.getDocStatus()); + + line1.load(getTrxName()); + assertEquals(0, line1.getQtyReserved().intValue()); + } }