IDEMPIERE-5812 Reversal of Material Receipt for a Closed PO leave quantity ordered of product in a bad state (#1964)
This commit is contained in:
parent
472032fa44
commit
e46d57e1ea
|
@ -1643,8 +1643,8 @@ public class MInOut extends X_M_InOut implements DocAction, IDocsPostProcess
|
|||
if (log.isLoggable(Level.FINE)) log.fine("OrderLine - Reserved=" + oLine.getQtyReserved()
|
||||
+ ", Delivered=" + oLine.getQtyDelivered());
|
||||
}
|
||||
|
||||
|
||||
boolean orderClosed = oLine != null && DocAction.STATUS_Closed.equals(oLine.getParent().getDocStatus());
|
||||
|
||||
// Load RMA Line
|
||||
MRMALine rmaLine = null;
|
||||
|
||||
|
@ -1726,7 +1726,7 @@ public class MInOut extends X_M_InOut implements DocAction, IDocsPostProcess
|
|||
return status;
|
||||
}
|
||||
|
||||
// Update Storage - see also VMatch.createMatchRecord
|
||||
// Update Storage - see also Match.createMatchRecord
|
||||
if (!MStorageOnHand.add(getCtx(),
|
||||
sLine.getM_Locator_ID(),
|
||||
sLine.getM_Product_ID(),
|
||||
|
@ -1760,8 +1760,8 @@ public class MInOut extends X_M_InOut implements DocAction, IDocsPostProcess
|
|||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
if (oLine!=null && mtrx!=null &&
|
||||
|
||||
if (oLine!=null && mtrx!=null && !orderClosed &&
|
||||
((!isReversal() && oLine.getQtyReserved().signum() > 0) || (isReversal() && oLine.getQtyOrdered().signum() > 0)))
|
||||
{
|
||||
if (sLine.getC_OrderLine_ID() != 0 && oLine.getM_Product_ID() > 0)
|
||||
|
@ -1847,7 +1847,7 @@ public class MInOut extends X_M_InOut implements DocAction, IDocsPostProcess
|
|||
if (dateMPolicy == null)
|
||||
dateMPolicy = getMovementDate();
|
||||
|
||||
// Fallback: Update Storage - see also VMatch.createMatchRecord
|
||||
// Fallback: Update Storage - see also Match.createMatchRecord
|
||||
if (pendingQty.signum() != 0 &&
|
||||
!MStorageOnHand.add(getCtx(),
|
||||
sLine.getM_Locator_ID(),
|
||||
|
@ -1859,7 +1859,7 @@ public class MInOut extends X_M_InOut implements DocAction, IDocsPostProcess
|
|||
m_processMsg = "Cannot correct Inventory OnHand [" + product.getValue() + "] - " + lastError;
|
||||
return DocAction.STATUS_Invalid;
|
||||
}
|
||||
if (oLine!=null && oLine.getM_Product_ID() > 0 &&
|
||||
if (oLine!=null && oLine.getM_Product_ID() > 0 && !orderClosed &&
|
||||
((!isReversal() && oLine.getQtyReserved().signum() > 0) || (isReversal() && oLine.getQtyOrdered().signum() > 0)))
|
||||
{
|
||||
IReservationTracer tracer = null;
|
||||
|
@ -1903,7 +1903,7 @@ public class MInOut extends X_M_InOut implements DocAction, IDocsPostProcess
|
|||
} // stock movement
|
||||
|
||||
// Correct Order Line
|
||||
if (product != null && oLine != null) // other in VMatch.createMatchRecord
|
||||
if (product != null && oLine != null && !orderClosed) // other in Match.createMatchRecord
|
||||
{
|
||||
if (oLine.getQtyOrdered().signum() >= 0)
|
||||
{
|
||||
|
|
|
@ -29,6 +29,7 @@ import org.adempiere.base.IProductPricing;
|
|||
import org.adempiere.exceptions.AdempiereException;
|
||||
import org.adempiere.exceptions.ProductNotOnPriceListException;
|
||||
import org.adempiere.model.ITaxProvider;
|
||||
import org.compiere.process.DocAction;
|
||||
import org.compiere.util.CLogger;
|
||||
import org.compiere.util.DB;
|
||||
import org.compiere.util.Env;
|
||||
|
@ -897,6 +898,20 @@ public class MOrderLine extends X_C_OrderLine
|
|||
}
|
||||
}
|
||||
|
||||
//sync qtyordered and qtylostsales for closed order
|
||||
if (!newRecord && DocAction.STATUS_Closed.equals(getParent().getDocStatus()) && is_ValueChanged(COLUMNNAME_QtyDelivered)
|
||||
&& !getParent().is_ValueChanged(MOrder.COLUMNNAME_DocStatus)) {
|
||||
if (getQtyOrdered().compareTo(getQtyDelivered()) > 0)
|
||||
{
|
||||
setQtyLostSales(getQtyLostSales().add(getQtyOrdered().subtract(getQtyDelivered())));
|
||||
setQtyOrdered(getQtyDelivered());
|
||||
}
|
||||
else
|
||||
{
|
||||
setQtyLostSales(Env.ZERO);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
} // beforeSave
|
||||
|
||||
|
|
|
@ -960,4 +960,92 @@ public class MatchPOTest extends AbstractTestCase {
|
|||
receipt.load(getTrxName());
|
||||
assertEquals(0, receipt.getC_Order_ID(), "Material receipt: order not clear after void of purchase order");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReverseReceiptAfterClosePO() {
|
||||
MBPartner bpartner = MBPartner.get(Env.getCtx(), DictionaryIDs.C_BPartner.TREE_FARM.id);
|
||||
MProduct product = MProduct.get(Env.getCtx(), DictionaryIDs.M_Product.MULCH.id);
|
||||
|
||||
//Create PO of 4
|
||||
MOrder order = new MOrder(Env.getCtx(), 0, getTrxName());
|
||||
order.setBPartner(bpartner);
|
||||
order.setIsSOTrx(false);
|
||||
order.setC_DocTypeTarget_ID();
|
||||
order.setDocStatus(DocAction.STATUS_Drafted);
|
||||
order.setDocAction(DocAction.ACTION_Complete);
|
||||
order.saveEx();
|
||||
|
||||
MOrderLine orderLine = new MOrderLine(order);
|
||||
orderLine.setLine(10);
|
||||
orderLine.setProduct(product);
|
||||
orderLine.setQty(new BigDecimal("4"));
|
||||
orderLine.saveEx();
|
||||
|
||||
BigDecimal qtyOrdered = MStorageReservation.getQty(product.get_ID(), order.getM_Warehouse_ID(), 0, false, getTrxName());
|
||||
|
||||
ProcessInfo info = MWorkflow.runDocumentActionWorkflow(order, DocAction.ACTION_Complete);
|
||||
assertFalse(info.isError(), info.getSummary());
|
||||
order.load(getTrxName());
|
||||
assertEquals(DocAction.STATUS_Completed, order.getDocStatus());
|
||||
|
||||
BigDecimal qtyOrdered1 = MStorageReservation.getQty(product.get_ID(), order.getM_Warehouse_ID(), 0, false, getTrxName());
|
||||
assertEquals(4, qtyOrdered1.subtract(qtyOrdered).intValue(), "QtyOrdered not increase as expected");
|
||||
|
||||
//Create MR
|
||||
MInOut receipt = new MInOut(order, DictionaryIDs.C_DocType.MM_RECEIPT.id, order.getDateOrdered()); // MM Receipt
|
||||
receipt.saveEx();
|
||||
|
||||
MWarehouse wh = MWarehouse.get(Env.getCtx(), receipt.getM_Warehouse_ID());
|
||||
int M_Locator_ID = wh.getDefaultLocator().getM_Locator_ID();
|
||||
|
||||
MInOutLine receiptLine = new MInOutLine(receipt);
|
||||
receiptLine.setOrderLine(orderLine, M_Locator_ID, new BigDecimal("2"));
|
||||
receiptLine.setLine(10);
|
||||
receiptLine.setQty(new BigDecimal("2"));
|
||||
receiptLine.saveEx();
|
||||
|
||||
info = MWorkflow.runDocumentActionWorkflow(receipt, DocAction.ACTION_Complete);
|
||||
assertFalse(info.isError(), info.getSummary());
|
||||
receipt.load(getTrxName());
|
||||
assertEquals(DocAction.STATUS_Completed, receipt.getDocStatus());
|
||||
|
||||
qtyOrdered1 = MStorageReservation.getQty(product.get_ID(), order.getM_Warehouse_ID(), 0, false, getTrxName());
|
||||
assertEquals(qtyOrdered.intValue()+2, qtyOrdered1.intValue(), "QtyOrdered not release as expected");
|
||||
|
||||
orderLine.load(getTrxName());
|
||||
assertEquals(2, orderLine.getQtyDelivered().intValue(), "Unexpected QtyDelivered");
|
||||
assertEquals(2, orderLine.getQtyReserved().intValue(), "Unexpected QtyReserved");
|
||||
|
||||
//Close PO
|
||||
order.load(getTrxName());
|
||||
info = MWorkflow.runDocumentActionWorkflow(order, DocAction.ACTION_Close);
|
||||
assertFalse(info.isError(), info.getSummary());
|
||||
order.load(getTrxName());
|
||||
assertEquals(DocAction.STATUS_Closed, order.getDocStatus());
|
||||
orderLine.load(getTrxName());
|
||||
assertEquals(4, orderLine.getQtyEntered().intValue(), "Unexpected QtyEntered");
|
||||
assertEquals(2, orderLine.getQtyDelivered().intValue(), "Unexpected QtyDelivered");
|
||||
assertEquals(2, orderLine.getQtyOrdered().intValue(), "Unexpected QtyOrdered");
|
||||
assertEquals(2, orderLine.getQtyLostSales().intValue(), "Unexpected QtyLostSales");
|
||||
assertEquals(0, orderLine.getQtyReserved().intValue(), "Unexpected QtyReserved");
|
||||
|
||||
qtyOrdered1 = MStorageReservation.getQty(product.get_ID(), order.getM_Warehouse_ID(), 0, false, getTrxName());
|
||||
assertEquals(qtyOrdered.intValue(), qtyOrdered1.intValue(), "Unexpected change in QtyOrdered");
|
||||
|
||||
//Reverse MR
|
||||
info = MWorkflow.runDocumentActionWorkflow(receipt, DocAction.ACTION_Reverse_Accrual);
|
||||
assertFalse(info.isError(), info.getSummary());
|
||||
receipt.load(getTrxName());
|
||||
assertEquals(DocAction.STATUS_Reversed, receipt.getDocStatus());
|
||||
|
||||
orderLine.load(getTrxName());
|
||||
assertEquals(4, orderLine.getQtyEntered().intValue(), "Unexpected QtyEntered");
|
||||
assertEquals(0, orderLine.getQtyDelivered().intValue(), "Unexpected QtyDelivered");
|
||||
assertEquals(0, orderLine.getQtyOrdered().intValue(), "Unexpected QtyOrdered");
|
||||
assertEquals(4, orderLine.getQtyLostSales().intValue(), "Unexpected QtyLostSales");
|
||||
assertEquals(0, orderLine.getQtyReserved().intValue(), "Unexpected QtyReserved");
|
||||
|
||||
qtyOrdered1 = MStorageReservation.getQty(product.get_ID(), order.getM_Warehouse_ID(), 0, false, getTrxName());
|
||||
assertEquals(qtyOrdered.intValue(), qtyOrdered1.intValue(), "Unexpected change in QtyOrdered");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue