From 35303516012c991995281cc7c9033eddf77a6c47 Mon Sep 17 00:00:00 2001 From: hengsin Date: Wed, 8 Dec 2021 23:18:44 +0800 Subject: [PATCH] =?UTF-8?q?IDEMPIERE-2172=20Attribute=20set=20with=20manda?= =?UTF-8?q?tory=20type=20=3D=20When=20Shipping=20not=20=E2=80=A6=20(#1040)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * IDEMPIERE-2172 Attribute set with mandatory type = When Shipping not working Fix reversal and add more unit test * IDEMPIERE-2172 Attribute set with mandatory type = When Shipping not working Use constant for movement type checking --- .../src/org/compiere/model/MInOut.java | 161 ++++++++------- .../org/idempiere/test/model/PaymentTest.java | 1 - .../idempiere/test/model/SalesOrderTest.java | 186 +++++++++++++++++- 3 files changed, 270 insertions(+), 78 deletions(-) diff --git a/org.adempiere.base/src/org/compiere/model/MInOut.java b/org.adempiere.base/src/org/compiere/model/MInOut.java index 524c399c07..a757cb67e1 100644 --- a/org.adempiere.base/src/org/compiere/model/MInOut.java +++ b/org.adempiere.base/src/org/compiere/model/MInOut.java @@ -1421,7 +1421,7 @@ public class MInOut extends X_M_InOut implements DocAction, IDocsPostProcess if (MovementType.charAt(1) == '-') // C- Customer Shipment - V- Vendor Return QtyMA = QtyMA.negate(); - if (product != null && QtyMA.signum() < 0 && MovementType.equals("C-") && ma.getM_AttributeSetInstance_ID() > 0 + if (product != null && QtyMA.signum() < 0 && MovementType.equals(MOVEMENTTYPE_CustomerShipment) && ma.getM_AttributeSetInstance_ID() > 0 && oLine != null && oLine.getM_AttributeSetInstance_ID()==0 && !ma.isAutoGenerated() && !isReversal()) { String status = moveOnHandToShipmentASI(product, sLine.getM_Locator_ID(), ma.getM_AttributeSetInstance_ID(), QtyMA.negate(), ma.getDateMaterialPolicy(), @@ -1455,7 +1455,7 @@ public class MInOut extends X_M_InOut implements DocAction, IDocsPostProcess return DocAction.STATUS_Invalid; } - if (product != null && QtyMA.signum() > 0 && MovementType.equals("C-") && ma.getM_AttributeSetInstance_ID() > 0 + if (product != null && QtyMA.signum() > 0 && MovementType.equals(MOVEMENTTYPE_CustomerShipment) && ma.getM_AttributeSetInstance_ID() > 0 && oLine != null && oLine.getM_AttributeSetInstance_ID()==0 && !ma.isAutoGenerated() && isReversal()) { String status = moveOnHandToShipmentASI(product, sLine.getM_Locator_ID(), ma.getM_AttributeSetInstance_ID(), QtyMA.negate(), ma.getDateMaterialPolicy(), @@ -1496,7 +1496,7 @@ public class MInOut extends X_M_InOut implements DocAction, IDocsPostProcess if (mtrx == null) { - if (product != null && MovementType.equals("C-") && sLine.getM_AttributeSetInstance_ID() > 0 && Qty.signum() < 0 + if (product != null && MovementType.equals(MOVEMENTTYPE_CustomerShipment) && sLine.getM_AttributeSetInstance_ID() > 0 && Qty.signum() < 0 && oLine != null && oLine.getM_AttributeSetInstance_ID()==0 && !isReversal()) { String status = moveOnHandToShipmentASI(product, sLine.getM_Locator_ID(), sLine.getM_AttributeSetInstance_ID(), Qty.negate(), null, sLine.get_ID(), false, get_TrxName()); @@ -1596,10 +1596,10 @@ public class MInOut extends X_M_InOut implements DocAction, IDocsPostProcess return DocAction.STATUS_Invalid; } - if (product != null && MovementType.equals("C-") && sLine.getM_AttributeSetInstance_ID() > 0 && Qty.signum() > 0 + if (product != null && MovementType.equals(MOVEMENTTYPE_CustomerShipment) && sLine.getM_AttributeSetInstance_ID() > 0 && Qty.signum() > 0 && oLine != null && oLine.getM_AttributeSetInstance_ID()==0 && isReversal()) { - String status = moveOnHandToShipmentASI(product, sLine.getM_Locator_ID(), sLine.getM_AttributeSetInstance_ID(), Qty.negate(), null, sLine.get_ID(), true, get_TrxName()); + String status = moveOnHandToShipmentASI(product, sLine.getM_Locator_ID(), sLine.getM_AttributeSetInstance_ID(), Qty.negate(), getMovementDate(), sLine.get_ID(), true, get_TrxName()); if (status != null) return status; } @@ -2392,7 +2392,7 @@ public class MInOut extends X_M_InOut implements DocAction, IDocsPostProcess { MInOutLineMA ma = new MInOutLineMA (rLine, mas[j].getM_AttributeSetInstance_ID(), - mas[j].getMovementQty().negate(),mas[j].getDateMaterialPolicy(),true); + mas[j].getMovementQty().negate(),mas[j].getDateMaterialPolicy(),mas[j].isAutoGenerated()); ma.saveEx(); } } @@ -2625,7 +2625,7 @@ public class MInOut extends X_M_InOut implements DocAction, IDocsPostProcess /** * For product with mix of No ASI and ASI inventory, this move Non ASI on hand to the new ASI created at shipment line or shipment line ma * @param product - * @param M_Locator_ID + * @param M_Locator_ID shipment line locator id * @param M_AttributeSetInstance_ID * @param qty * @param dateMaterialPolicy @@ -2642,14 +2642,13 @@ public class MInOut extends X_M_InOut implements DocAction, IDocsPostProcess return null; if (dateMaterialPolicy != null) { MStorageOnHand asi = MStorageOnHand.get(getCtx(), M_Locator_ID, product.getM_Product_ID(), M_AttributeSetInstance_ID, dateMaterialPolicy, trxName); - if (asi != null && asi.getQtyOnHand().signum() != 0) + if (asi != null && asi.getQtyOnHand().signum() != 0 && !reversal) return null; - MStorageOnHand noasi = MStorageOnHand.get(getCtx(), M_Locator_ID, product.getM_Product_ID(), 0, dateMaterialPolicy, trxName); - if (noasi != null && noasi.getM_AttributeSetInstance_ID()==0 && (noasi.getQtyOnHand().compareTo(qty) >= 0 || reversal)) { - if (!(MStorageOnHand.add(getCtx(), getM_Warehouse_ID(), M_Locator_ID, product.getM_Product_ID(), 0, qty.negate(), dateMaterialPolicy, trxName))) { + if (reversal) { + if (!MStorageOnHand.add(getCtx(), getM_Warehouse_ID(), M_Locator_ID, product.getM_Product_ID(), 0, qty.negate(), dateMaterialPolicy, trxName)) { String lastError = CLogger.retrieveErrorString(""); - m_processMsg = "Cannot move Inventory OnHand (MA) to Shipment ASI [" + product.getValue() + "] - " + lastError; + m_processMsg = "Cannot move Inventory OnHand to Non ASI [" + product.getValue() + "] - " + lastError; return DocAction.STATUS_Invalid; } MTransaction trxFrom = new MTransaction (Env.getCtx(), getAD_Org_ID(), getMovementType(), M_Locator_ID, product.getM_Product_ID(), 0, @@ -2659,70 +2658,6 @@ public class MInOut extends X_M_InOut implements DocAction, IDocsPostProcess m_processMsg = "Transaction From not inserted (MA) [" + product.getValue() + "] - "; return DocAction.STATUS_Invalid; } - - if (!(MStorageOnHand.add(getCtx(), getM_Warehouse_ID(), M_Locator_ID, product.getM_Product_ID(), M_AttributeSetInstance_ID, qty, dateMaterialPolicy, trxName))) { - String lastError = CLogger.retrieveErrorString(""); - m_processMsg = "Cannot move Inventory OnHand (MA) to Shipment ASI [" + product.getValue() + "] - " + lastError; - return DocAction.STATUS_Invalid; - } - MTransaction trxTo = new MTransaction (Env.getCtx(), getAD_Org_ID(), getMovementType(), M_Locator_ID, product.getM_Product_ID(), M_AttributeSetInstance_ID, - qty, getMovementDate(), trxName); - trxTo.setM_InOutLine_ID(M_InOutLine_ID); - if (!trxTo.save()) { - m_processMsg = "Transaction To not inserted (MA) [" + product.getValue() + "] - "; - return DocAction.STATUS_Invalid; - } - } - } else { - BigDecimal totalASI = BigDecimal.ZERO; - BigDecimal totalOnHand = BigDecimal.ZERO; - MStorageOnHand[] storages = MStorageOnHand.getWarehouse(getCtx(), 0, - product.getM_Product_ID(), M_AttributeSetInstance_ID, null, - MClient.MMPOLICY_FiFo.equals(product.getMMPolicy()), false, - M_Locator_ID, get_TrxName()); - for (MStorageOnHand onhand : storages) { - totalASI = totalASI.add(onhand.getQtyOnHand()); - } - if (!reversal && totalASI.signum() != 0) - return null; - else if (reversal && (totalASI.compareTo(qty) < 0)) - return null; - - storages = MStorageOnHand.getWarehouse(getCtx(), 0, - product.getM_Product_ID(), 0, null, - MClient.MMPOLICY_FiFo.equals(product.getMMPolicy()), true, - M_Locator_ID, get_TrxName()); - List nonASIList = new ArrayList<>(); - for (MStorageOnHand storage : storages) { - if (storage.getM_AttributeSetInstance_ID() == 0) { - totalOnHand = totalOnHand.add(storage.getQtyOnHand()); - nonASIList.add(storage); - } - } - if (totalOnHand.compareTo(qty) >= 0 || reversal) { - BigDecimal totalToMove = qty; - for (MStorageOnHand onhand : nonASIList) { - BigDecimal toMove = totalToMove; - if (!reversal && toMove.compareTo(onhand.getQtyOnHand()) >= 0) { - toMove = onhand.getQtyOnHand(); - } - if (!MStorageOnHand.add(getCtx(), getM_Warehouse_ID(), M_Locator_ID, product.getM_Product_ID(), 0, toMove.negate(), onhand.getDateMaterialPolicy(), trxName)) { - String lastError = CLogger.retrieveErrorString(""); - m_processMsg = "Cannot move Inventory OnHand to Shipment ASI [" + product.getValue() + "] - " + lastError; - return DocAction.STATUS_Invalid; - } - MTransaction trxFrom = new MTransaction (Env.getCtx(), getAD_Org_ID(), getMovementType(), M_Locator_ID, product.getM_Product_ID(), 0, - toMove.negate(), getMovementDate(), trxName); - trxFrom.setM_InOutLine_ID(M_InOutLine_ID); - if (!trxFrom.save()) { - m_processMsg = "Transaction From not inserted (MA) [" + product.getValue() + "] - "; - return DocAction.STATUS_Invalid; - } - dateMaterialPolicy = onhand.getDateMaterialPolicy(); - totalToMove = totalToMove.subtract(toMove); - if ((!reversal && totalToMove.signum() <= 0) || (reversal && totalToMove.signum() >= 0)) - break; - } if (!MStorageOnHand.add(getCtx(), getM_Warehouse_ID(), M_Locator_ID, product.getM_Product_ID(), M_AttributeSetInstance_ID, qty, dateMaterialPolicy, trxName)) { String lastError = CLogger.retrieveErrorString(""); m_processMsg = "Cannot move Inventory OnHand to Shipment ASI [" + product.getValue() + "] - " + lastError; @@ -2735,9 +2670,83 @@ public class MInOut extends X_M_InOut implements DocAction, IDocsPostProcess m_processMsg = "Transaction To not inserted (MA) [" + product.getValue() + "] - "; return DocAction.STATUS_Invalid; } + } else { + return doMove(product, M_Locator_ID, M_AttributeSetInstance_ID, dateMaterialPolicy, qty, M_InOutLine_ID, reversal, trxName); } + } else { + BigDecimal totalASI = BigDecimal.ZERO; + MStorageOnHand[] storages = MStorageOnHand.getWarehouse(getCtx(), 0, + product.getM_Product_ID(), M_AttributeSetInstance_ID, null, + MClient.MMPOLICY_FiFo.equals(product.getMMPolicy()), false, + M_Locator_ID, get_TrxName()); + for (MStorageOnHand onhand : storages) { + totalASI = totalASI.add(onhand.getQtyOnHand()); + } + if (!reversal && totalASI.signum() != 0) + return null; + else if (reversal && (totalASI.compareTo(qty) < 0)) + return null; + + return doMove(product, M_Locator_ID, M_AttributeSetInstance_ID, dateMaterialPolicy, qty, M_InOutLine_ID, reversal, trxName); } return null; } + + private String doMove(MProduct product, int M_Locator_ID, int M_AttributeSetInstance_ID, Timestamp dateMaterialPolicy, BigDecimal qty, + int M_InOutLine_ID, boolean reversal, String trxName) { + MStorageOnHand[] storages; + BigDecimal totalOnHand = BigDecimal.ZERO; + Timestamp onHandDateMaterialPolicy = null; + storages = MStorageOnHand.getWarehouse(getCtx(), 0, + product.getM_Product_ID(), 0, null, + MClient.MMPOLICY_FiFo.equals(product.getMMPolicy()), true, + M_Locator_ID, get_TrxName()); + List nonASIList = new ArrayList<>(); + for (MStorageOnHand storage : storages) { + if (storage.getM_AttributeSetInstance_ID() == 0) { + totalOnHand = totalOnHand.add(storage.getQtyOnHand()); + nonASIList.add(storage); + } + } + if (totalOnHand.compareTo(qty) >= 0 || reversal) { + BigDecimal totalToMove = qty; + for (MStorageOnHand onhand : nonASIList) { + BigDecimal toMove = totalToMove; + if (!reversal && toMove.compareTo(onhand.getQtyOnHand()) >= 0) { + toMove = onhand.getQtyOnHand(); + } + if (!MStorageOnHand.add(getCtx(), getM_Warehouse_ID(), M_Locator_ID, product.getM_Product_ID(), 0, toMove.negate(), onhand.getDateMaterialPolicy(), trxName)) { + String lastError = CLogger.retrieveErrorString(""); + m_processMsg = "Cannot move Inventory OnHand to Non ASI [" + product.getValue() + "] - " + lastError; + return DocAction.STATUS_Invalid; + } + MTransaction trxFrom = new MTransaction (Env.getCtx(), getAD_Org_ID(), getMovementType(), M_Locator_ID, product.getM_Product_ID(), 0, + toMove.negate(), getMovementDate(), trxName); + trxFrom.setM_InOutLine_ID(M_InOutLine_ID); + if (!trxFrom.save()) { + m_processMsg = "Transaction From not inserted (MA) [" + product.getValue() + "] - "; + return DocAction.STATUS_Invalid; + } + onHandDateMaterialPolicy = onhand.getDateMaterialPolicy(); + totalToMove = totalToMove.subtract(toMove); + if ((!reversal && totalToMove.signum() <= 0) || (reversal && totalToMove.signum() >= 0)) + break; + } + if (!MStorageOnHand.add(getCtx(), getM_Warehouse_ID(), M_Locator_ID, product.getM_Product_ID(), M_AttributeSetInstance_ID, qty, + (dateMaterialPolicy != null ? dateMaterialPolicy : onHandDateMaterialPolicy), trxName)) { + String lastError = CLogger.retrieveErrorString(""); + m_processMsg = "Cannot move Inventory OnHand to Shipment ASI [" + product.getValue() + "] - " + lastError; + return DocAction.STATUS_Invalid; + } + MTransaction trxTo = new MTransaction (Env.getCtx(), getAD_Org_ID(), getMovementType(), M_Locator_ID, product.getM_Product_ID(), M_AttributeSetInstance_ID, + qty, getMovementDate(), trxName); + trxTo.setM_InOutLine_ID(M_InOutLine_ID); + if (!trxTo.save()) { + m_processMsg = "Transaction To not inserted (MA) [" + product.getValue() + "] - "; + return DocAction.STATUS_Invalid; + } + } + return null; + } } // MInOut diff --git a/org.idempiere.test/src/org/idempiere/test/model/PaymentTest.java b/org.idempiere.test/src/org/idempiere/test/model/PaymentTest.java index 8552f332c7..6290910601 100644 --- a/org.idempiere.test/src/org/idempiere/test/model/PaymentTest.java +++ b/org.idempiere.test/src/org/idempiere/test/model/PaymentTest.java @@ -25,7 +25,6 @@ package org.idempiere.test.model; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import org.compiere.model.MPayment; 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 701071ef62..95bfd75aaa 100644 --- a/org.idempiere.test/src/org/idempiere/test/model/SalesOrderTest.java +++ b/org.idempiere.test/src/org/idempiere/test/model/SalesOrderTest.java @@ -41,6 +41,7 @@ import org.compiere.model.MBPartner; import org.compiere.model.MClient; import org.compiere.model.MInOut; import org.compiere.model.MInOutLine; +import org.compiere.model.MInOutLineMA; import org.compiere.model.MInvoice; import org.compiere.model.MOrder; import org.compiere.model.MOrderLine; @@ -1090,6 +1091,8 @@ public class SalesOrderTest extends AbstractTestCase { assertEquals(-1, asiTrxs.get(1).getMovementQty().intValue(), "Unexpected movement qty for second ASI MTransaction record"); //reverse the MR + Timestamp tomorrow = TimeUtil.addDays(today, 1); + Env.setContext(Env.getCtx(), Env.DATE, tomorrow); shipment.load(getTrxName()); info = MWorkflow.runDocumentActionWorkflow(shipment, DocAction.ACTION_Reverse_Accrual); assertFalse(info.isError(), info.getSummary()); @@ -1099,6 +1102,14 @@ public class SalesOrderTest extends AbstractTestCase { assertEquals(originalOnHand, newOnHand, "Unexpected on hand quantity no ASI"); asiOnHand = MStorageOnHand.getQtyOnHand(PRODUCT_PCHAIR, getM_Warehouse_ID(), asi.get_ID(), getTrxName()).intValue(); assertEquals(0, asiOnHand, "Unexpected on hand quantity for Serial ASI"); + storages = MStorageOnHand.getOfProduct(Env.getCtx(), PRODUCT_PCHAIR, getTrxName()); + for (MStorageOnHand storage : storages) { + if (storage.getM_Warehouse_ID() == getM_Warehouse_ID()) { + if (storage.getM_AttributeSetInstance_ID() == asi.get_ID()) { + assertEquals(0, storage.getQtyOnHand().intValue(), "Unexpected qty on hand for asi: " + storage.toString()); + } + } + } MInOut reversal = new MInOut(Env.getCtx(), shipment.getReversal_ID(), getTrxName()); MInOutLine[] reversalLines = reversal.getLines(); @@ -1107,7 +1118,7 @@ public class SalesOrderTest extends AbstractTestCase { .setOrderBy("M_Transaction_ID") .list(); assertEquals(1, noASITrxs.size(), "Unexpected number of records for reversal no ASI MTransaction"); - assertEquals(1, asiTrxs.get(0).getMovementQty().intValue(), "Unexpected reversal movement qty for no ASI MTransaction record"); + assertEquals(1, noASITrxs.get(0).getMovementQty().intValue(), "Unexpected reversal movement qty for no ASI MTransaction record"); query = new Query(Env.getCtx(), MTransaction.Table_Name, "M_InOutLine_ID=? AND M_Product_ID=? AND M_AttributeSetInstance_ID=?", getTrxName()); asiTrxs = query.setParameters(reversalLines[0].get_ID(), reversalLines[0].getM_Product_ID(), reversalLines[0].getM_AttributeSetInstance_ID()) @@ -1117,4 +1128,177 @@ public class SalesOrderTest extends AbstractTestCase { assertEquals(1, asiTrxs.get(0).getMovementQty().intValue(), "Unexpected reversal movement qty for first ASI MTransaction record"); assertEquals(-1, asiTrxs.get(1).getMovementQty().intValue(), "Unexpected reversal movement qty for second ASI MTransaction record"); } + + @Test + public void testSetASIWhenShipping2() { + MOrder order = new MOrder(Env.getCtx(), 0, getTrxName()); + order.setBPartner(MBPartner.get(Env.getCtx(), BP_JOE_BLOCK)); + 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); + line1.setProduct(MProduct.get(Env.getCtx(), PRODUCT_PCHAIR)); + line1.setQty(new BigDecimal("2")); + line1.setDatePromised(today); + line1.saveEx(); + + ProcessInfo info = MWorkflow.runDocumentActionWorkflow(order, DocAction.ACTION_Complete); + assertFalse(info.isError(), info.getSummary()); + order.load(getTrxName()); + assertEquals(DocAction.STATUS_Completed, order.getDocStatus(), "Unexpected Order document status"); + line1.load(getTrxName()); + assertEquals(2, line1.getQtyReserved().intValue(), "Unexpected order line qty reserved value"); + + int originalOnHand = MStorageOnHand.getQtyOnHandWithASIZero(PRODUCT_PCHAIR, getM_Warehouse_ID(), getTrxName()).intValue(); + + MInOut shipment = new MInOut(order, 120, order.getDateOrdered()); + shipment.setDocStatus(DocAction.STATUS_Drafted); + shipment.setDocAction(DocAction.ACTION_Complete); + shipment.saveEx(); + + MInOutLine shipmentLine = new MInOutLine(shipment); + shipmentLine.setOrderLine(line1, 0, new BigDecimal("2")); + shipmentLine.setQty(new BigDecimal("2")); + shipmentLine.saveEx(); + + MAttributeSetInstance asi1 = new MAttributeSetInstance(Env.getCtx(), 0, getTrxName()); + asi1.setM_AttributeSet_ID(MProduct.get(PRODUCT_PCHAIR).getM_AttributeSet_ID()); + asi1.setSerNo("PChair Serial #1000000"); + asi1.saveEx(); + MAttributeSetInstance asi2 = new MAttributeSetInstance(Env.getCtx(), 0, getTrxName()); + asi2.setM_AttributeSet_ID(MProduct.get(PRODUCT_PCHAIR).getM_AttributeSet_ID()); + asi2.setSerNo("PChair Serial #1000000"); + asi2.saveEx(); + MInOutLineMA ma1 = new MInOutLineMA(Env.getCtx(), 0, getTrxName()); + ma1.setM_AttributeSetInstance_ID(asi1.get_ID()); + ma1.setM_InOutLine_ID(shipmentLine.get_ID()); + ma1.setDateMaterialPolicy(shipment.getMovementDate()); + ma1.setMovementQty(new BigDecimal("1")); + ma1.setIsAutoGenerated(false); + ma1.saveEx(); + MInOutLineMA ma2 = new MInOutLineMA(Env.getCtx(), 0, getTrxName()); + ma2.setM_AttributeSetInstance_ID(asi2.get_ID()); + ma2.setM_InOutLine_ID(shipmentLine.get_ID()); + ma2.setDateMaterialPolicy(shipment.getMovementDate()); + ma2.setMovementQty(new BigDecimal("1")); + ma2.setIsAutoGenerated(false); + ma2.saveEx(); + + info = MWorkflow.runDocumentActionWorkflow(shipment, DocAction.ACTION_Complete); + assertFalse(info.isError(), info.getSummary()); + shipment.load(getTrxName()); + assertEquals(DocAction.STATUS_Completed, shipment.getDocStatus(), "Unexpected Shipment document status"); + + int newOnHand = MStorageOnHand.getQtyOnHandWithASIZero(PRODUCT_PCHAIR, getM_Warehouse_ID(), getTrxName()).intValue(); + assertEquals(originalOnHand-2, newOnHand, "Unexpected on hand quantity"); + + int asiOnHand = MStorageOnHand.getQtyOnHand(PRODUCT_PCHAIR, getM_Warehouse_ID(), asi1.get_ID(), getTrxName()).intValue(); + int asiRecords = 0; + MStorageOnHand[] storages = MStorageOnHand.getOfProduct(Env.getCtx(), PRODUCT_PCHAIR, getTrxName()); + for (MStorageOnHand storage : storages) { + if (storage.getM_Warehouse_ID()==getM_Warehouse_ID() && storage.getM_AttributeSetInstance_ID()==asi1.get_ID()) { + asiRecords++; + } + } + assertEquals(0, asiOnHand, "Unexpected on hand quantity for Serial ASI 1"); + assertEquals(1, asiRecords, "Unexpected number of Serial ASI 1 Storage records"); + + asiOnHand = MStorageOnHand.getQtyOnHand(PRODUCT_PCHAIR, getM_Warehouse_ID(), asi2.get_ID(), getTrxName()).intValue(); + asiRecords = 0; + storages = MStorageOnHand.getOfProduct(Env.getCtx(), PRODUCT_PCHAIR, getTrxName()); + for (MStorageOnHand storage : storages) { + if (storage.getM_Warehouse_ID()==getM_Warehouse_ID() && storage.getM_AttributeSetInstance_ID()==asi2.get_ID()) { + asiRecords++; + } + } + assertEquals(0, asiOnHand, "Unexpected on hand quantity for Serial ASI 2"); + assertEquals(1, asiRecords, "Unexpected number of Serial ASI 2 Storage records"); + + Query query = new Query(Env.getCtx(), MTransaction.Table_Name, "M_InOutLine_ID=? AND M_Product_ID=? AND M_AttributeSetInstance_ID=0", getTrxName()); + MTransaction trxFrom = query.setParameters(shipmentLine.get_ID(), shipmentLine.getM_Product_ID()).first(); + assertNotNull(trxFrom, "Can't find MTransaction record for no ASI MTransaction record"); + assertEquals(-1, trxFrom.getMovementQty().intValue(), "Unexpected movement qty for no ASI MTransaction record"); + + query = new Query(Env.getCtx(), MTransaction.Table_Name, "M_InOutLine_ID=? AND M_Product_ID=? AND M_AttributeSetInstance_ID=?", getTrxName()); + List asiTrxs = query.setParameters(shipmentLine.get_ID(), shipmentLine.getM_Product_ID(), ma1.getM_AttributeSetInstance_ID()) + .setOrderBy("M_Transaction_ID") + .list(); + assertEquals(2, asiTrxs.size(), "Unexpected number of records for ASI MTransaction"); + assertEquals(1, asiTrxs.get(0).getMovementQty().intValue(), "Unexpected movement qty for first ASI 1 MTransaction record"); + assertEquals(-1, asiTrxs.get(1).getMovementQty().intValue(), "Unexpected movement qty for second ASI 1 MTransaction record"); + + query = new Query(Env.getCtx(), MTransaction.Table_Name, "M_InOutLine_ID=? AND M_Product_ID=? AND M_AttributeSetInstance_ID=?", getTrxName()); + asiTrxs = query.setParameters(shipmentLine.get_ID(), shipmentLine.getM_Product_ID(), ma2.getM_AttributeSetInstance_ID()) + .setOrderBy("M_Transaction_ID") + .list(); + assertEquals(2, asiTrxs.size(), "Unexpected number of records for ASI MTransaction"); + assertEquals(1, asiTrxs.get(0).getMovementQty().intValue(), "Unexpected movement qty for first ASI 2 MTransaction record"); + assertEquals(-1, asiTrxs.get(1).getMovementQty().intValue(), "Unexpected movement qty for second ASI 2 MTransaction record"); + + //reverse the MR + Timestamp tomorrow = TimeUtil.addDays(today, 1); + Env.setContext(Env.getCtx(), Env.DATE, tomorrow); + shipment.load(getTrxName()); + info = MWorkflow.runDocumentActionWorkflow(shipment, DocAction.ACTION_Reverse_Accrual); + assertFalse(info.isError(), info.getSummary()); + shipment.load(getTrxName()); + assertEquals(DocAction.STATUS_Reversed, shipment.getDocStatus(), "Unexpected Shipment document status"); + newOnHand = MStorageOnHand.getQtyOnHandWithASIZero(PRODUCT_PCHAIR, getM_Warehouse_ID(), getTrxName()).intValue(); + assertEquals(originalOnHand, newOnHand, "Unexpected on hand quantity no ASI"); + + asiOnHand = MStorageOnHand.getQtyOnHand(PRODUCT_PCHAIR, getM_Warehouse_ID(), asi1.get_ID(), getTrxName()).intValue(); + assertEquals(0, asiOnHand, "Unexpected on hand quantity for Serial ASI 1"); + storages = MStorageOnHand.getOfProduct(Env.getCtx(), PRODUCT_PCHAIR, getTrxName()); + for (MStorageOnHand storage : storages) { + if (storage.getM_Warehouse_ID() == getM_Warehouse_ID()) { + if (storage.getM_AttributeSetInstance_ID() == asi1.get_ID()) { + assertEquals(0, storage.getQtyOnHand().intValue(), "Unexpected qty on hand for asi 1: " + storage.toString()); + } + } + } + + asiOnHand = MStorageOnHand.getQtyOnHand(PRODUCT_PCHAIR, getM_Warehouse_ID(), asi2.get_ID(), getTrxName()).intValue(); + assertEquals(0, asiOnHand, "Unexpected on hand quantity for Serial ASI 2"); + storages = MStorageOnHand.getOfProduct(Env.getCtx(), PRODUCT_PCHAIR, getTrxName()); + for (MStorageOnHand storage : storages) { + if (storage.getM_Warehouse_ID() == getM_Warehouse_ID()) { + if (storage.getM_AttributeSetInstance_ID() == asi2.get_ID()) { + assertEquals(0, storage.getQtyOnHand().intValue(), "Unexpected qty on hand for asi 2: " + storage.toString()); + } + } + } + + MInOut reversal = new MInOut(Env.getCtx(), shipment.getReversal_ID(), getTrxName()); + MInOutLine[] reversalLines = reversal.getLines(); + query = new Query(Env.getCtx(), MTransaction.Table_Name, "M_InOutLine_ID=? AND M_Product_ID=? AND M_AttributeSetInstance_ID=0", getTrxName()); + List noASITrxs = query.setParameters(reversalLines[0].get_ID(), reversalLines[0].getM_Product_ID()) + .setOrderBy("M_Transaction_ID") + .list(); + assertEquals(2, noASITrxs.size(), "Unexpected number of records for reversal no ASI MTransaction"); + assertEquals(1, noASITrxs.get(0).getMovementQty().intValue(), "Unexpected reversal movement qty for no ASI MTransaction record"); + assertEquals(1, noASITrxs.get(1).getMovementQty().intValue(), "Unexpected reversal movement qty for no ASI MTransaction record"); + + query = new Query(Env.getCtx(), MTransaction.Table_Name, "M_InOutLine_ID=? AND M_Product_ID=? AND M_AttributeSetInstance_ID=?", getTrxName()); + asiTrxs = query.setParameters(reversalLines[0].get_ID(), reversalLines[0].getM_Product_ID(), asi1.getM_AttributeSetInstance_ID()) + .setOrderBy("M_Transaction_ID") + .list(); + assertEquals(2, asiTrxs.size(), "Unexpected number of records for reversal ASI MTransaction"); + assertEquals(1, asiTrxs.get(0).getMovementQty().intValue(), "Unexpected reversal movement qty for first ASI 1 MTransaction record"); + assertEquals(-1, asiTrxs.get(1).getMovementQty().intValue(), "Unexpected reversal movement qty for second ASI 1 MTransaction record"); + + query = new Query(Env.getCtx(), MTransaction.Table_Name, "M_InOutLine_ID=? AND M_Product_ID=? AND M_AttributeSetInstance_ID=?", getTrxName()); + asiTrxs = query.setParameters(reversalLines[0].get_ID(), reversalLines[0].getM_Product_ID(), asi2.getM_AttributeSetInstance_ID()) + .setOrderBy("M_Transaction_ID") + .list(); + assertEquals(2, asiTrxs.size(), "Unexpected number of records for reversal ASI MTransaction"); + assertEquals(1, asiTrxs.get(0).getMovementQty().intValue(), "Unexpected reversal movement qty for first ASI 2 MTransaction record"); + assertEquals(-1, asiTrxs.get(1).getMovementQty().intValue(), "Unexpected reversal movement qty for second ASI 2 MTransaction record"); + } }