diff --git a/migration/i8.2z/oracle/202112050910_IDEMPIERE-5073.sql b/migration/i8.2z/oracle/202112050910_IDEMPIERE-5073.sql new file mode 100644 index 0000000000..3a5f6f1538 --- /dev/null +++ b/migration/i8.2z/oracle/202112050910_IDEMPIERE-5073.sql @@ -0,0 +1,12 @@ +SET SQLBLANKLINES ON +SET DEFINE OFF + +-- IDEMPIERE-5073 M_InOutLineMA.DateMaterialPolicy should comes from MStorageOnHand or Shipment instead of through user entry +-- Dec 5, 2021, 5:06:51 PM MYT +UPDATE AD_Field SET IsReadOnly='Y', AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, IsToolbarButton=NULL,Updated=TO_DATE('2021-12-05 17:06:51','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=201618 +; + + +SELECT register_migration_script('202112050910_IDEMPIERE-5073.sql') FROM dual +; + diff --git a/migration/i8.2z/postgresql/202112050910_IDEMPIERE-5073.sql b/migration/i8.2z/postgresql/202112050910_IDEMPIERE-5073.sql new file mode 100644 index 0000000000..08a0de70fa --- /dev/null +++ b/migration/i8.2z/postgresql/202112050910_IDEMPIERE-5073.sql @@ -0,0 +1,8 @@ +-- IDEMPIERE-5073 M_InOutLineMA.DateMaterialPolicy should comes from MStorageOnHand or Shipment instead of through user entry +-- Dec 5, 2021, 5:06:51 PM MYT +UPDATE AD_Field SET IsReadOnly='Y', AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, IsToolbarButton=NULL,Updated=TO_TIMESTAMP('2021-12-05 17:06:51','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=201618 +; + +SELECT register_migration_script('202112050910_IDEMPIERE-5073.sql') FROM dual +; + diff --git a/org.adempiere.base/src/org/compiere/model/MInOutLineMA.java b/org.adempiere.base/src/org/compiere/model/MInOutLineMA.java index 3ed7ebca24..870ed1a74f 100644 --- a/org.adempiere.base/src/org/compiere/model/MInOutLineMA.java +++ b/org.adempiere.base/src/org/compiere/model/MInOutLineMA.java @@ -248,6 +248,11 @@ public class MInOutLineMA extends X_M_InOutLineMA return retValue; } // getNonReturned + @Override + public MInOutLine getM_InOutLine() throws RuntimeException { + return new MInOutLine(getCtx(), getM_InOutLine_ID(), get_TrxName()); + } + /************************************************************************** * Before Save * @param newRecord new @@ -255,25 +260,24 @@ public class MInOutLineMA extends X_M_InOutLineMA */ protected boolean beforeSave (boolean newRecord) { - MInOutLine parentline = new MInOutLine(getCtx(), getM_InOutLine_ID(), get_TrxName()); + MInOutLine parentline = getM_InOutLine(); if (newRecord && parentline.getParent().isProcessed()) { log.saveError("ParentComplete", Msg.translate(getCtx(), "M_InOut_ID")); return false; } //Set DateMaterialPolicy - if(!newRecord && is_ValueChanged(COLUMNNAME_M_AttributeSetInstance_ID)){ - //TODO Require testing for all scenario - I_M_InOutLine line = getM_InOutLine(); + if ((!newRecord && is_ValueChanged(COLUMNNAME_M_AttributeSetInstance_ID)) || + (newRecord && getM_AttributeSetInstance_ID() > 0 && getDateMaterialPolicy() == null)) { Timestamp dateMPolicy = null; if(getM_AttributeSetInstance_ID()>0) { - dateMPolicy = MStorageOnHand.getDateMaterialPolicy(line.getM_Product_ID(), getM_AttributeSetInstance_ID(), get_TrxName()); + dateMPolicy = MStorageOnHand.getDateMaterialPolicy(parentline.getM_Product_ID(), getM_AttributeSetInstance_ID(), get_TrxName()); } if(dateMPolicy == null) { - I_M_InOut inout = line.getM_InOut(); + I_M_InOut inout = parentline.getParent(); dateMPolicy = inout.getMovementDate(); } 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 95bfd75aaa..d43e8cfaf3 100644 --- a/org.idempiere.test/src/org/idempiere/test/model/SalesOrderTest.java +++ b/org.idempiere.test/src/org/idempiere/test/model/SalesOrderTest.java @@ -34,6 +34,7 @@ import java.math.BigDecimal; import java.sql.Timestamp; import java.util.List; import java.util.Properties; +import java.util.UUID; import org.compiere.model.MAllocationHdr; import org.compiere.model.MAttributeSetInstance; @@ -76,6 +77,9 @@ public class SalesOrderTest extends AbstractTestCase { public SalesOrderTest() { } + private static final int BP_PATIO = 121; + private static final int DOCTYPE_PO = 126; + private static final int DOCTYPE_RECEIPT = 122; private final static int BP_JOE_BLOCK = 118; private static final int PRODUCT_OAK_TREE = 123; private static final int PRODUCT_AZALEA = 128; @@ -88,6 +92,7 @@ public class SalesOrderTest extends AbstractTestCase { private static final int WAREHOUSE_HQ = 103; private static final int LOCATOR_FERTILIZER = 50001; private static final int UOM_HOUR = 101; + private static final int USER_GARDENADMIN = 101; @Test /** @@ -1301,4 +1306,192 @@ public class SalesOrderTest extends AbstractTestCase { 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"); } + + @Test + public void testShipmentDateMaterialPolicy() { + Timestamp today = TimeUtil.getDay(System.currentTimeMillis()); + Timestamp tomorrow = TimeUtil.addDays(today, 1); + MOrder order = new MOrder(Env.getCtx(), 0, getTrxName()); + order.setBPartner(MBPartner.get(Env.getCtx(), 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); + order.setDateOrdered(today); + order.setDatePromised(today); + order.saveEx(); + + MProduct fert = MProduct.get(Env.getCtx(), PRODUCT_FERT50); + MOrderLine line1 = new MOrderLine(order); + line1.setLine(10); + line1.setProduct(fert); + 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(getTrxName()); + assertEquals(DocAction.STATUS_Completed, order.getDocStatus(), "Order not completed"); + + MInOut receipt = new MInOut(order, DOCTYPE_RECEIPT, order.getDateOrdered()); + receipt.setDocStatus(DocAction.STATUS_Drafted); + receipt.setDocAction(DocAction.ACTION_Complete); + receipt.saveEx(); + + // receipt + MInOutLine receiptLine = new MInOutLine(receipt); + receiptLine.setOrderLine(line1, 0, new BigDecimal("1")); + receiptLine.setQty(new BigDecimal("1")); + receiptLine.saveEx(); + + info = MWorkflow.runDocumentActionWorkflow(receipt, DocAction.ACTION_Prepare); + assertFalse(info.isError(), info.getSummary()); + receipt.load(getTrxName()); + assertEquals(DocAction.STATUS_InProgress, receipt.getDocStatus()); + receiptLine.load(getTrxName()); + MInOutLineMA ma = new MInOutLineMA(Env.getCtx(), 0, getTrxName()); + ma.setM_InOutLine_ID(receiptLine.get_ID()); + ma.setIsAutoGenerated(false); + MAttributeSetInstance asi1 = new MAttributeSetInstance(Env.getCtx(), 0, getTrxName()); + asi1.setM_AttributeSet_ID(fert.getM_AttributeSet_ID()); + String lot1 = UUID.randomUUID().toString(); + asi1.setLot(lot1); + asi1.saveEx(); + ma.setM_AttributeSetInstance_ID(asi1.get_ID()); + ma.setMovementQty(new BigDecimal("1")); + ma.saveEx(); + assertEquals(receipt.getMovementDate(), ma.getDateMaterialPolicy()); + info = MWorkflow.runDocumentActionWorkflow(receipt, DocAction.ACTION_Complete); + assertFalse(info.isError(), info.getSummary()); + receipt.load(getTrxName()); + assertEquals(DocAction.STATUS_Completed, receipt.getDocStatus()); + + order = new MOrder(Env.getCtx(), 0, getTrxName()); + order.setBPartner(MBPartner.get(Env.getCtx(), 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); + order.setDateOrdered(tomorrow); + order.setDatePromised(tomorrow); + order.saveEx(); + + line1 = new MOrderLine(order); + line1.setLine(10); + line1.setProduct(fert); + line1.setQty(new BigDecimal("1")); + line1.setDatePromised(tomorrow); + line1.saveEx(); + + info = MWorkflow.runDocumentActionWorkflow(order, DocAction.ACTION_Complete); + assertFalse(info.isError(), info.getSummary()); + order.load(getTrxName()); + assertEquals(DocAction.STATUS_Completed, order.getDocStatus(), "Order not completed"); + + receipt = new MInOut(order, DOCTYPE_RECEIPT, order.getDateOrdered()); + receipt.setDocStatus(DocAction.STATUS_Drafted); + receipt.setDocAction(DocAction.ACTION_Complete); + receipt.saveEx(); + + // receipt + receiptLine = new MInOutLine(receipt); + receiptLine.setOrderLine(line1, 0, new BigDecimal("1")); + receiptLine.setQty(new BigDecimal("1")); + receiptLine.saveEx(); + + info = MWorkflow.runDocumentActionWorkflow(receipt, DocAction.ACTION_Prepare); + assertFalse(info.isError(), info.getSummary()); + receipt.load(getTrxName()); + assertEquals(DocAction.STATUS_InProgress, receipt.getDocStatus()); + receiptLine.load(getTrxName()); + ma = new MInOutLineMA(Env.getCtx(), 0, getTrxName()); + ma.setM_InOutLine_ID(receiptLine.get_ID()); + ma.setIsAutoGenerated(false); + MAttributeSetInstance asi2 = new MAttributeSetInstance(Env.getCtx(), 0, getTrxName()); + asi2.setM_AttributeSet_ID(fert.getM_AttributeSet_ID()); + String lot2 = UUID.randomUUID().toString(); + asi2.setLot(lot2); + asi2.saveEx(); + ma.setM_AttributeSetInstance_ID(asi2.get_ID()); + ma.setMovementQty(new BigDecimal("1")); + ma.saveEx(); + assertEquals(receipt.getMovementDate(), ma.getDateMaterialPolicy()); + info = MWorkflow.runDocumentActionWorkflow(receipt, DocAction.ACTION_Complete); + assertFalse(info.isError(), info.getSummary()); + receipt.load(getTrxName()); + assertEquals(DocAction.STATUS_Completed, receipt.getDocStatus()); + + int onHand1 = MStorageOnHand.getQtyOnHand(fert.get_ID(), getM_Warehouse_ID(), asi1.get_ID(), getTrxName()).intValue(); + int onHand2 = MStorageOnHand.getQtyOnHand(fert.get_ID(), getM_Warehouse_ID(), asi2.get_ID(), getTrxName()).intValue(); + assertEquals(onHand1, onHand2); + assertEquals(1, onHand1); + + //sales and shipment + 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); + order.setDateOrdered(today); + order.setDatePromised(today); + order.saveEx(); + + line1 = new MOrderLine(order); + line1.setLine(10); + line1.setProduct(fert); + line1.setQty(new BigDecimal("2")); + line1.setDatePromised(today); + line1.saveEx(); + + info = MWorkflow.runDocumentActionWorkflow(order, DocAction.ACTION_Complete); + assertFalse(info.isError(), info.getSummary()); + order.load(getTrxName()); + assertEquals(DocAction.STATUS_Completed, order.getDocStatus()); + line1.load(getTrxName()); + assertEquals(2, line1.getQtyReserved().intValue()); + + MInOut shipment = new MInOut(order, 120, order.getDateOrdered()); + shipment.setDocStatus(DocAction.STATUS_Drafted); + shipment.setDocAction(DocAction.ACTION_Prepare); + shipment.saveEx(); + + 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_Prepare); + assertFalse(info.isError(), info.getSummary()); + shipment.load(getTrxName()); + assertEquals(DocAction.STATUS_InProgress, shipment.getDocStatus()); + shipmentLine.load(getTrxName()); + ma = new MInOutLineMA(Env.getCtx(), 0, getTrxName()); + ma.setM_InOutLine_ID(shipmentLine.get_ID()); + ma.setIsAutoGenerated(false); + ma.setM_AttributeSetInstance_ID(asi1.get_ID()); + ma.setMovementQty(new BigDecimal("1")); + ma.saveEx(); + assertEquals(today, ma.getDateMaterialPolicy()); + ma = new MInOutLineMA(Env.getCtx(), 0, getTrxName()); + ma.setM_InOutLine_ID(shipmentLine.get_ID()); + ma.setIsAutoGenerated(false); + ma.setM_AttributeSetInstance_ID(asi2.get_ID()); + ma.setMovementQty(new BigDecimal("1")); + ma.saveEx(); + assertEquals(tomorrow, ma.getDateMaterialPolicy()); + + info = MWorkflow.runDocumentActionWorkflow(shipment, DocAction.ACTION_Complete); + assertFalse(info.isError(), info.getSummary()); + shipment.load(getTrxName()); + assertEquals(DocAction.STATUS_Completed, shipment.getDocStatus()); + + onHand1 = MStorageOnHand.getQtyOnHand(fert.get_ID(), getM_Warehouse_ID(), asi1.get_ID(), getTrxName()).intValue(); + onHand2 = MStorageOnHand.getQtyOnHand(fert.get_ID(), getM_Warehouse_ID(), asi2.get_ID(), getTrxName()).intValue(); + assertEquals(onHand1, onHand2); + assertEquals(0, onHand1); + } }