IDEMPIERE-5040 Stall M_InOutLine.QtyOverReceipt (#1005)

* IDEMPIERE-5040 Stall M_InOutLine.QtyOverReceipt

* IDEMPIERE-5040 Stall M_InOutLine.QtyOverReceipt

Drop the user of M_InOutLine.QtyOverReceipt column
This commit is contained in:
hengsin 2021-11-29 23:01:52 +08:00 committed by GitHub
parent 744e84ccc5
commit 05447b38ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 194 additions and 59 deletions

View File

@ -0,0 +1,23 @@
SET SQLBLANKLINES ON
SET DEFINE OFF
-- IDEMPIERE-5040 Stall M_InOutLine.QtyOverReceipt
-- Nov 19, 2021, 11:00:44 PM MYT
INSERT INTO AD_TableIndex (AD_Client_ID,AD_Org_ID,AD_TableIndex_ID,AD_TableIndex_UU,Created,CreatedBy,EntityType,IsActive,Name,Updated,UpdatedBy,AD_Table_ID,IsCreateConstraint,IsUnique,Processing,TableIndexDrop,IsKey) VALUES (0,0,201096,'c97e6bf9-5754-485c-a983-5cb01429032f',TO_DATE('2021-11-19 23:00:43','YYYY-MM-DD HH24:MI:SS'),100,'D','Y','m_inoutline_orderline_idx',TO_DATE('2021-11-19 23:00:43','YYYY-MM-DD HH24:MI:SS'),100,320,'N','N','N','N','N')
;
-- Nov 19, 2021, 11:00:58 PM MYT
INSERT INTO AD_IndexColumn (AD_Client_ID,AD_Org_ID,AD_IndexColumn_ID,AD_IndexColumn_UU,Created,CreatedBy,EntityType,IsActive,Updated,UpdatedBy,AD_Column_ID,AD_TableIndex_ID,SeqNo) VALUES (0,0,201443,'4c920b11-27f2-40a5-b30f-cc8b525d942b',TO_DATE('2021-11-19 23:00:57','YYYY-MM-DD HH24:MI:SS'),100,'D','Y',TO_DATE('2021-11-19 23:00:57','YYYY-MM-DD HH24:MI:SS'),100,3811,201096,10)
;
-- Nov 19, 2021, 11:01:04 PM MYT
CREATE INDEX m_inoutline_orderline_idx ON M_InOutLine (C_OrderLine_ID)
;
-- Nov 26, 2021, 6:14:22 AM MYT
UPDATE AD_Column SET IsActive='N',Updated=TO_DATE('2021-11-26 06:14:22','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=210888
;
SELECT register_migration_script('202111210850_IDEMPIERE-5040.sql') FROM dual
;

View File

@ -0,0 +1,20 @@
-- IDEMPIERE-5040 Stall M_InOutLine.QtyOverReceipt
-- Nov 19, 2021, 11:00:44 PM MYT
INSERT INTO AD_TableIndex (AD_Client_ID,AD_Org_ID,AD_TableIndex_ID,AD_TableIndex_UU,Created,CreatedBy,EntityType,IsActive,Name,Updated,UpdatedBy,AD_Table_ID,IsCreateConstraint,IsUnique,Processing,TableIndexDrop,IsKey) VALUES (0,0,201096,'c97e6bf9-5754-485c-a983-5cb01429032f',TO_TIMESTAMP('2021-11-19 23:00:43','YYYY-MM-DD HH24:MI:SS'),100,'D','Y','m_inoutline_orderline_idx',TO_TIMESTAMP('2021-11-19 23:00:43','YYYY-MM-DD HH24:MI:SS'),100,320,'N','N','N','N','N')
;
-- Nov 19, 2021, 11:00:58 PM MYT
INSERT INTO AD_IndexColumn (AD_Client_ID,AD_Org_ID,AD_IndexColumn_ID,AD_IndexColumn_UU,Created,CreatedBy,EntityType,IsActive,Updated,UpdatedBy,AD_Column_ID,AD_TableIndex_ID,SeqNo) VALUES (0,0,201443,'4c920b11-27f2-40a5-b30f-cc8b525d942b',TO_TIMESTAMP('2021-11-19 23:00:57','YYYY-MM-DD HH24:MI:SS'),100,'D','Y',TO_TIMESTAMP('2021-11-19 23:00:57','YYYY-MM-DD HH24:MI:SS'),100,3811,201096,10)
;
-- Nov 19, 2021, 11:01:04 PM MYT
CREATE INDEX m_inoutline_orderline_idx ON M_InOutLine (C_OrderLine_ID)
;
-- Nov 26, 2021, 6:14:22 AM MYT
UPDATE AD_Column SET IsActive='N',Updated=TO_TIMESTAMP('2021-11-26 06:14:22','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=210888
;
SELECT register_migration_script('202111210850_IDEMPIERE-5040.sql') FROM dual
;

View File

@ -447,19 +447,6 @@ public interface I_M_InOutLine
*/
public BigDecimal getQtyEntered();
/** Column name QtyOverReceipt */
public static final String COLUMNNAME_QtyOverReceipt = "QtyOverReceipt";
/** Set Over Receipt.
* Over Receipt Quantity
*/
public void setQtyOverReceipt (BigDecimal QtyOverReceipt);
/** Get Over Receipt.
* Over Receipt Quantity
*/
public BigDecimal getQtyOverReceipt();
/** Column name Ref_InOutLine_ID */
public static final String COLUMNNAME_Ref_InOutLine_ID = "Ref_InOutLine_ID";

View File

@ -762,8 +762,6 @@ public class MInOut extends X_M_InOut implements DocAction
}
}
line.setQtyOverReceipt(fromLine.getQtyOverReceipt());
//
line.setProcessed(false);
if (line.save(get_TrxName()))
@ -1358,8 +1356,6 @@ public class MInOut extends X_M_InOut implements DocAction
log.fine("Material Transaction");
MTransaction mtrx = null;
//
BigDecimal overReceipt = BigDecimal.ZERO;
if (!isReversal())
{
if (oLine != null)
@ -1368,21 +1364,25 @@ public class MInOut extends X_M_InOut implements DocAction
.subtract(oLine.getQtyDelivered());
if (toDelivered.signum() < 0) // IDEMPIERE-2889
toDelivered = Env.ZERO;
if (sLine.getMovementQty().compareTo(toDelivered) > 0)
overReceipt = sLine.getMovementQty().subtract(
toDelivered);
if (overReceipt.signum() != 0)
{
sLine.setQtyOverReceipt(overReceipt);
sLine.saveEx();
}
}
}
else
BigDecimal storageReservationToUpdate = sLine.getMovementQty();
if (oLine != null)
{
overReceipt = sLine.getQtyOverReceipt();
if (!isReversal())
{
if (storageReservationToUpdate.compareTo(oLine.getQtyReserved()) > 0)
storageReservationToUpdate = oLine.getQtyReserved();
}
else
{
BigDecimal tmp = storageReservationToUpdate.negate().add(oLine.getQtyReserved());
if (tmp.compareTo(oLine.getQtyOrdered()) > 0)
storageReservationToUpdate = oLine.getQtyOrdered().subtract(oLine.getQtyReserved());
}
}
BigDecimal orderedQtyToUpdate = sLine.getMovementQty().subtract(overReceipt);
//
if (sLine.getM_AttributeSetInstance_ID() == 0)
{
@ -1421,7 +1421,8 @@ public class MInOut extends X_M_InOut implements DocAction
}
}
if (oLine!=null && mtrx!=null && oLine.getQtyOrdered().signum() >= 0)
if (oLine!=null && mtrx!=null &&
((!isReversal() && oLine.getQtyReserved().signum() > 0) || (isReversal() && oLine.getQtyOrdered().signum() > 0)))
{
if (sLine.getC_OrderLine_ID() != 0 && oLine.getM_Product_ID() > 0)
{
@ -1436,7 +1437,7 @@ public class MInOut extends X_M_InOut implements DocAction
if (!MStorageReservation.add(getCtx(), oLine.getM_Warehouse_ID(),
oLine.getM_Product_ID(),
oLine.getM_AttributeSetInstance_ID(),
orderedQtyToUpdate.negate(),
storageReservationToUpdate.negate(),
isSOTrx(),
get_TrxName(), tracer))
{
@ -1510,7 +1511,8 @@ 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 && oLine.getM_Product_ID() > 0)
if (oLine!=null && oLine.getM_Product_ID() > 0 &&
((!isReversal() && oLine.getQtyReserved().signum() > 0) || (isReversal() && oLine.getQtyOrdered().signum() > 0)))
{
IReservationTracer tracer = null;
IReservationTracerFactory factory = Core.getReservationTracerFactory();
@ -1523,7 +1525,7 @@ public class MInOut extends X_M_InOut implements DocAction
if (!MStorageReservation.add(getCtx(), oLine.getM_Warehouse_ID(),
oLine.getM_Product_ID(),
oLine.getM_AttributeSetInstance_ID(),
orderedQtyToUpdate.negate(), isSOTrx(), get_TrxName(), tracer))
storageReservationToUpdate.negate(), isSOTrx(), get_TrxName(), tracer))
{
m_processMsg = "Cannot correct Inventory Reserved " + (isSOTrx()? "Reserved [" :"Ordered [") + product.getValue() + "]";
return DocAction.STATUS_Invalid;
@ -1549,7 +1551,7 @@ public class MInOut extends X_M_InOut implements DocAction
{
if (oLine.getQtyOrdered().signum() >= 0)
{
oLine.setQtyReserved(oLine.getQtyReserved().subtract(sLine.getMovementQty().subtract(sLine.getQtyOverReceipt())));
oLine.setQtyReserved(oLine.getQtyReserved().subtract(sLine.getMovementQty()));
if (oLine.getQtyReserved().signum() == -1)
oLine.setQtyReserved(Env.ZERO);
@ -2312,7 +2314,6 @@ public class MInOut extends X_M_InOut implements DocAction
MInOutLine rLine = rLines[i];
rLine.setQtyEntered(rLine.getQtyEntered().negate());
rLine.setMovementQty(rLine.getMovementQty().negate());
rLine.setQtyOverReceipt(rLine.getQtyOverReceipt().negate());
rLine.setM_AttributeSetInstance_ID(sLines[i].getM_AttributeSetInstance_ID());
// Goodwill: store original (voided/reversed) document line
rLine.setReversalLine_ID(sLines[i].getM_InOutLine_ID());

View File

@ -2003,6 +2003,8 @@ public class MOrder extends X_C_Order implements DocAction
}
}
updateOverReceipt();
setProcessed(true);
m_processMsg = info.toString();
//
@ -2010,7 +2012,15 @@ public class MOrder extends X_C_Order implements DocAction
return DocAction.STATUS_Completed;
} // completeIt
private void updateOverReceipt() {
for(MOrderLine line : m_lines) {
if (line.getM_Product_ID() <= 0) continue;
if (line.getQtyDelivered().signum() > 0 && line.getQtyOrdered().compareTo(line.getQtyDelivered()) >= 0) {
DB.executeUpdateEx("UPDATE M_InOutLine Set QtyOverReceipt=0 WHERE C_OrderLine_ID=? AND QtyOverReceipt>0",
new Object[] {line.getC_OrderLine_ID()}, get_TrxName());
}
}
}
protected String landedCostAllocation() {
MOrderLandedCost[] landedCosts = MOrderLandedCost.getOfOrder(getC_Order_ID(), get_TrxName());

View File

@ -33,7 +33,7 @@ public class X_M_InOutLine extends PO implements I_M_InOutLine, I_Persistent
/**
*
*/
private static final long serialVersionUID = 20211106L;
private static final long serialVersionUID = 20211126L;
/** Standard Constructor */
public X_M_InOutLine (Properties ctx, int M_InOutLine_ID, String trxName)
@ -742,26 +742,6 @@ public class X_M_InOutLine extends PO implements I_M_InOutLine, I_Persistent
return bd;
}
/** Set Over Receipt.
@param QtyOverReceipt
Over Receipt Quantity
*/
public void setQtyOverReceipt (BigDecimal QtyOverReceipt)
{
set_Value (COLUMNNAME_QtyOverReceipt, QtyOverReceipt);
}
/** Get Over Receipt.
@return Over Receipt Quantity
*/
public BigDecimal getQtyOverReceipt ()
{
BigDecimal bd = (BigDecimal)get_Value(COLUMNNAME_QtyOverReceipt);
if (bd == null)
return Env.ZERO;
return bd;
}
/** Set Referenced Shipment Line.
@param Ref_InOutLine_ID Referenced Shipment Line */
public void setRef_InOutLine_ID (int Ref_InOutLine_ID)

View File

@ -487,14 +487,23 @@ public class Match
{
// Update Order Line
MOrderLine oLine = new MOrderLine(Env.getCtx(), Line_ID, trxName);
BigDecimal storageReservationToUpdate = null;
if (oLine.get_ID() != 0) // other in MInOut.completeIt
{
storageReservationToUpdate = oLine.getQtyReserved();
oLine.setQtyReserved(oLine.getQtyReserved().subtract(qty));
if (oLine.getQtyReserved().signum() == -1)
oLine.setQtyReserved(Env.ZERO);
else if (oLine.getQtyDelivered().compareTo(oLine.getQtyOrdered()) > 0)
oLine.setQtyReserved(Env.ZERO);
oLine.saveEx();
storageReservationToUpdate = storageReservationToUpdate.subtract(oLine.getQtyReserved());
}
// Update Shipment Line
BigDecimal toDeliver = oLine.getQtyOrdered().subtract(oLine.getQtyDelivered());
if (toDeliver.signum() < 0)
toDeliver = Env.ZERO;
if (sLine.getMovementQty().compareTo(toDeliver) <= 0)
{
sLine.setC_OrderLine_ID(Line_ID);
@ -525,7 +534,7 @@ public class Match
{
success = true;
// Correct Ordered Qty for Stocked Products (see MOrder.reserveStock / MInOut.processIt)
if (oLine.get_ID() > 0 && oLine.getM_Product_ID() > 0 && oLine.getProduct().isStocked()) {
if (oLine.get_ID() > 0 && oLine.getM_Product_ID() > 0 && oLine.getProduct().isStocked() && storageReservationToUpdate != null) {
IReservationTracer tracer = null;
IReservationTracerFactory factory = Core.getReservationTracerFactory();
if (factory != null) {
@ -537,7 +546,7 @@ public class Match
success = MStorageReservation.add (Env.getCtx(), oLine.getM_Warehouse_ID(),
oLine.getM_Product_ID(),
oLine.getM_AttributeSetInstance_ID(),
qty.negate(), oLine.getParent().isSOTrx(), trxName, tracer);
storageReservationToUpdate.negate(), oLine.getParent().isSOTrx(), trxName, tracer);
}
}
}

View File

@ -168,7 +168,7 @@ public class MatchInvTest extends AbstractTestCase {
info = MWorkflow.runDocumentActionWorkflow(delivery, DocAction.ACTION_Complete);
delivery.load(getTrxName());
assertFalse(info.isError());
assertFalse(info.isError(), info.getSummary());
assertEquals(DocAction.STATUS_Completed, delivery.getDocStatus());
if (!delivery.isPosted()) {

View File

@ -46,9 +46,12 @@ import org.compiere.model.MProduct;
import org.compiere.model.MStorageOnHand;
import org.compiere.model.MStorageReservation;
import org.compiere.model.MStorageReservationLog;
import org.compiere.model.MSysConfig;
import org.compiere.model.Query;
import org.compiere.process.DocAction;
import org.compiere.process.ProcessInfo;
import org.compiere.util.CacheMgt;
import org.compiere.util.DB;
import org.compiere.util.Env;
import org.compiere.util.TimeUtil;
import org.compiere.wf.MWorkflow;
@ -482,4 +485,106 @@ public class PurchaseOrderTest extends AbstractTestCase {
ordered = MStorageReservation.get(Env.getCtx(), line1.getM_Warehouse_ID(), PRODUCT_WEEDER, 0, false, getTrxName());
assertTrue(log.getNewQty().equals(ordered.getQty()), "New Qty from MStorageReservationLog != Qty from MStorageReservation");
}
@Test
public void testQtyOverReceipt() {
Properties ctx = Env.getCtx();
String trxName = getTrxName();
DB.executeUpdateEx("UPDATE AD_SysConfig SET Value='N' WHERE AD_Client_ID=0 AND Name=?",
new Object[] {MSysConfig.VALIDATE_MATCHING_TO_ORDERED_QTY}, null);
CacheMgt.get().reset();
BigDecimal initialQtyOrdered = getQtyOrdered(Env.getCtx(), PRODUCT_MULCH, getTrxName());
try {
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(new BigDecimal("1"));
line1.setDatePromised(today);
line1.saveEx();
ProcessInfo info = MWorkflow.runDocumentActionWorkflow(order, DocAction.ACTION_Complete);
assertFalse(info.isError(), info.getSummary());
order.load(trxName);
assertEquals(DocAction.STATUS_Completed, order.getDocStatus(), "Order not completed");
line1.load(trxName);
assertEquals(1, line1.getQtyReserved().intValue(), "Wrong Order line qty reserved value");
BigDecimal newQtyOrdered = getQtyOrdered(Env.getCtx(), PRODUCT_MULCH, getTrxName());
assertEquals(initialQtyOrdered.intValue()+1, newQtyOrdered.intValue(), "Quantiy Ordered not updated as expected");
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, new BigDecimal("2"));
receiptLine1.setQty(new BigDecimal("2"));
receiptLine1.saveEx();
info = MWorkflow.runDocumentActionWorkflow(receipt1, DocAction.ACTION_Complete);
assertFalse(info.isError(), info.getSummary());
receipt1.load(trxName);
assertEquals(DocAction.STATUS_Completed, receipt1.getDocStatus(), "Material receipt not completed");
line1.load(trxName);
assertEquals(0, line1.getQtyReserved().intValue(), "Wrong order line qty reserved value");
newQtyOrdered = getQtyOrdered(Env.getCtx(), PRODUCT_MULCH, getTrxName());
assertEquals(initialQtyOrdered.intValue(), newQtyOrdered.intValue(), "Quantiy Ordered not updated as expected");
// reactivate the purchase order
info = MWorkflow.runDocumentActionWorkflow(order, DocAction.ACTION_ReActivate);
assertFalse(info.isError(), info.getSummary());
order.load(trxName);
assertEquals(DocAction.STATUS_InProgress, order.getDocStatus(), "Order not reactivated");
// change the line quantity to 2
line1.load(trxName);
line1.setQty(new BigDecimal("2"));
line1.saveEx();
// complete the order again
info = MWorkflow.runDocumentActionWorkflow(order, DocAction.ACTION_Complete);
assertFalse(info.isError(), info.getSummary());
order.load(trxName);
assertEquals(DocAction.STATUS_Completed, order.getDocStatus(), "Order not completed");
line1.load(trxName);
assertEquals(0, line1.getQtyReserved().intValue(), "Wrong order line qty reserved value");
assertEquals(2, line1.getQtyOrdered().intValue(), "Wrong order line qty ordered value");
newQtyOrdered = getQtyOrdered(Env.getCtx(), PRODUCT_MULCH, getTrxName());
assertEquals(initialQtyOrdered.intValue(), newQtyOrdered.intValue(), "Quantiy Ordered not updated as expected");
//reverse MR
receiptLine1.load(trxName);
assertEquals(2, receiptLine1.getMovementQty().intValue(), "Wrong receipt line movement qty value");
receipt1.load(trxName);
receipt1.getLines(true);
info = MWorkflow.runDocumentActionWorkflow(receipt1, DocAction.ACTION_Reverse_Accrual);
assertFalse(info.isError(), info.getSummary());
receipt1.load(trxName);
assertEquals(DocAction.STATUS_Reversed, receipt1.getDocStatus(), "Material receipt not reversed");
line1.load(trxName);
assertEquals(2, line1.getQtyReserved().intValue(), "Wrong order line qty reserved value");
assertEquals(0, line1.getQtyDelivered().intValue(), "Wrong order line qty delivered value");
newQtyOrdered = getQtyOrdered(Env.getCtx(), PRODUCT_MULCH, getTrxName());
assertEquals(initialQtyOrdered.intValue()+2, newQtyOrdered.intValue(), "Quantiy Ordered not updated as expected");
} finally {
DB.executeUpdateEx("UPDATE AD_SysConfig SET Value='Y' WHERE AD_Client_ID=0 AND Name=?",
new Object[] {MSysConfig.VALIDATE_MATCHING_TO_ORDERED_QTY}, null);
CacheMgt.get().reset();
}
}
}