/*********************************************************************** * This file is part of iDempiere ERP Open Source * * http://www.idempiere.org * * * * Copyright (C) Contributors * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * * MA 02110-1301, USA. * * * * Contributors: * * - hengsin * **********************************************************************/ package org.idempiere.test.model; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import java.math.BigDecimal; import java.sql.Timestamp; import java.util.List; import org.compiere.model.MAttributeSetInstance; import org.compiere.model.MPInstance; import org.compiere.model.MPInstancePara; import org.compiere.model.MProcess; import org.compiere.model.MProduct; import org.compiere.model.MStorageOnHand; import org.compiere.model.Query; import org.compiere.model.SystemIDs; import org.compiere.process.ProcessInfo; import org.compiere.process.ServerProcessCtl; import org.compiere.util.DB; import org.compiere.util.Env; import org.compiere.util.TimeUtil; import org.idempiere.test.AbstractTestCase; import org.idempiere.test.DictionaryIDs; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.parallel.Isolated; /** * * @author hengsin * */ @Isolated public class MStorageOnHandTestIsolated extends AbstractTestCase { public MStorageOnHandTestIsolated() { } @Test public void testStorageCleanUp() { MProduct product = new MProduct(Env.getCtx(), 0, getTrxName()); product.setName("testStorageCleanUp"); product.setM_AttributeSet_ID(DictionaryIDs.M_AttributeSet.FERTILIZER_LOT.id); product.setIsStocked(true); product.setProductType(MProduct.PRODUCTTYPE_Item); product.setC_UOM_ID(DictionaryIDs.C_UOM.EACH.id); product.setM_Product_Category_ID(DictionaryIDs.M_Product_Category.CHEMICALS.id); product.setC_TaxCategory_ID(DictionaryIDs.C_TaxCategory.STANDARD.id); product.saveEx(); Timestamp today = TimeUtil.getDay(null); MStorageOnHand.add(Env.getCtx(), DictionaryIDs.M_Locator.HQ.id, product.get_ID(), 0, new BigDecimal("2"), today, getTrxName()); Query query = new Query(Env.getCtx(), MStorageOnHand.Table_Name, "M_Product_ID=?", getTrxName()); int count = query.setParameters(product.get_ID()).count(); assertEquals(1, count); MStorageOnHand.add(Env.getCtx(), DictionaryIDs.M_Locator.HQ.id, product.get_ID(), 0, new BigDecimal("-2"), today, getTrxName()); DB.executeUpdateEx("UPDATE M_StorageOnHand SET Created=? WHERE M_Product_ID=?", new Object[] {TimeUtil.addDays(today, -7), product.get_ID()}, getTrxName()); query = new Query(Env.getCtx(), MStorageOnHand.Table_Name, "M_Product_ID=?", getTrxName()); count = query.setParameters(product.get_ID()).count(); assertEquals(1, count); //movement get product from cache MProduct product1 = new MProduct(Env.getCtx(), 0, null); product1.setName("testStorageCleanUp#1"); product1.setValue(product1.getName()); product1.setM_AttributeSet_ID(DictionaryIDs.M_AttributeSet.FERTILIZER_LOT.id); product1.setIsStocked(true); product1.setProductType(MProduct.PRODUCTTYPE_Item); product1.setC_UOM_ID(DictionaryIDs.C_UOM.EACH.id); product1.setM_Product_Category_ID(DictionaryIDs.M_Product_Category.CHEMICALS.id); product1.setC_TaxCategory_ID(DictionaryIDs.C_TaxCategory.STANDARD.id); product1.saveEx(); try { MAttributeSetInstance asi1 = new MAttributeSetInstance(Env.getCtx(), 0, getTrxName()); asi1.setM_AttributeSet_ID(DictionaryIDs.M_AttributeSet.FERTILIZER_LOT.id); asi1.setLot("Lot1"); asi1.saveEx(); MStorageOnHand.add(Env.getCtx(), DictionaryIDs.M_Locator.HQ.id, product1.get_ID(), asi1.get_ID(), new BigDecimal("-1"), today, getTrxName()); MStorageOnHand.add(Env.getCtx(), DictionaryIDs.M_Locator.HQ.id, product1.get_ID(), 0, new BigDecimal("1"), today, getTrxName()); query = new Query(Env.getCtx(), MStorageOnHand.Table_Name, "M_Product_ID=? AND M_AttributeSetInstance_ID=?", getTrxName()); MStorageOnHand onhand = query.setParameters(product1.get_ID(), asi1.get_ID()).first(); assertNotNull(onhand); assertEquals(-1, onhand.getQtyOnHand().intValue()); query = new Query(Env.getCtx(), MStorageOnHand.Table_Name, "M_Product_ID=? AND M_AttributeSetInstance_ID=?", getTrxName()); onhand = query.setParameters(product1.get_ID(), 0).first(); assertNotNull(onhand); assertEquals(1, onhand.getQtyOnHand().intValue()); MProduct product2 = new MProduct(Env.getCtx(), 0, getTrxName()); product2.setName("testStorageCleanUp#2"); product2.setValue(product2.getName()); product2.setM_AttributeSet_ID(DictionaryIDs.M_AttributeSet.FERTILIZER_LOT.id); product2.setIsStocked(true); product2.setProductType(MProduct.PRODUCTTYPE_Item); product2.setC_UOM_ID(DictionaryIDs.C_UOM.EACH.id); product2.setM_Product_Category_ID(DictionaryIDs.M_Product_Category.CHEMICALS.id); product2.setC_TaxCategory_ID(DictionaryIDs.C_TaxCategory.STANDARD.id); product2.saveEx(); MAttributeSetInstance asi2 = new MAttributeSetInstance(Env.getCtx(), 0, getTrxName()); asi2.setM_AttributeSet_ID(DictionaryIDs.M_AttributeSet.FERTILIZER_LOT.id); asi2.setLot("LotX"); asi2.saveEx(); MStorageOnHand.add(Env.getCtx(), DictionaryIDs.M_Locator.HQ.id, product2.get_ID(), asi2.get_ID(), new BigDecimal("-1"), today, getTrxName()); MAttributeSetInstance asi3 = new MAttributeSetInstance(Env.getCtx(), 0, getTrxName()); asi3.setM_AttributeSet_ID(DictionaryIDs.M_AttributeSet.FERTILIZER_LOT.id); asi3.setLot("LotY"); asi3.saveEx(); MStorageOnHand.add(Env.getCtx(), DictionaryIDs.M_Locator.HQ.id, product2.get_ID(), asi3.get_ID(), new BigDecimal("1"), today, getTrxName()); query = new Query(Env.getCtx(), MStorageOnHand.Table_Name, "M_Product_ID=? AND M_AttributeSetInstance_ID=?", getTrxName()); onhand = query.setParameters(product2.get_ID(), asi2.get_ID()).first(); assertNotNull(onhand); assertEquals(-1, onhand.getQtyOnHand().intValue()); query = new Query(Env.getCtx(), MStorageOnHand.Table_Name, "M_Product_ID=? AND M_AttributeSetInstance_ID=?", getTrxName()); onhand = query.setParameters(product2.get_ID(), asi3.get_ID()).first(); assertNotNull(onhand); assertEquals(1, onhand.getQtyOnHand().intValue()); MProduct product3 = new MProduct(Env.getCtx(), 0, getTrxName()); product3.setName("testStorageCleanUp#3"); product3.setM_AttributeSet_ID(DictionaryIDs.M_AttributeSet.FERTILIZER_LOT.id); product3.setIsStocked(true); product3.setProductType(MProduct.PRODUCTTYPE_Item); product3.setC_UOM_ID(DictionaryIDs.C_UOM.EACH.id); product3.setM_Product_Category_ID(DictionaryIDs.M_Product_Category.CHEMICALS.id); product3.setC_TaxCategory_ID(DictionaryIDs.C_TaxCategory.STANDARD.id); product3.saveEx(); MAttributeSetInstance asi4 = new MAttributeSetInstance(Env.getCtx(), 0, getTrxName()); asi4.setM_AttributeSet_ID(DictionaryIDs.M_AttributeSet.FERTILIZER_LOT.id); asi4.setSerNo(product3.getName()+"SerialNo#1"); asi4.saveEx(); MStorageOnHand.add(Env.getCtx(), DictionaryIDs.M_Locator.HQ.id, product3.get_ID(), asi4.get_ID(), new BigDecimal("1"), today, getTrxName()); query = new Query(Env.getCtx(), MStorageOnHand.Table_Name, "M_Product_ID=?", getTrxName()); count = query.setParameters(product3.get_ID()).count(); assertEquals(1, count); MStorageOnHand.add(Env.getCtx(), DictionaryIDs.M_Locator.HQ.id, product3.get_ID(), asi4.get_ID(), new BigDecimal("-1"), today, getTrxName()); DB.executeUpdateEx("UPDATE M_StorageOnHand SET Created=? WHERE M_Product_ID=?", new Object[] {TimeUtil.addDays(today, -7), product3.get_ID()}, getTrxName()); query = new Query(Env.getCtx(), MStorageOnHand.Table_Name, "M_Product_ID=?", getTrxName()); count = query.setParameters(product3.get_ID()).count(); assertEquals(1, count); MPInstance instance = new MPInstance(Env.getCtx(), SystemIDs.PROCESS_M_StorageCleanup, 0, 0, null); instance.saveEx(); MPInstancePara para = new MPInstancePara(instance, 10); para.setParameterName("C_DocType_ID"); para.setP_Number(DictionaryIDs.C_DocType.MATERIAL_MOVEMENT.id); para.saveEx(); MProcess process = MProcess.get(Env.getCtx(), SystemIDs.PROCESS_M_StorageCleanup); ProcessInfo pi = new ProcessInfo(process.getName(), process.get_ID()); pi.setAD_PInstance_ID(instance.get_ID()); pi.setAD_Client_ID(getAD_Client_ID()); pi.setAD_User_ID(getAD_User_ID()); pi.setTransactionName(getTrxName()); ServerProcessCtl.process(pi, getTrx(), false); assertFalse(pi.isError(), pi.getSummary()); //check 0 stock removed query = new Query(Env.getCtx(), MStorageOnHand.Table_Name, "M_Product_ID=?", getTrxName()); count = query.setParameters(product.get_ID()).count(); assertEquals(0, count); //check 0 stock with serno not removed query = new Query(Env.getCtx(), MStorageOnHand.Table_Name, "M_Product_ID=?", getTrxName()); List onhands = query.setParameters(product3.get_ID()).list(); assertEquals(1, onhands.size()); assertEquals(0, onhands.get(0).getQtyOnHand().intValue()); assertEquals(asi4.get_ID(), onhands.get(0).getM_AttributeSetInstance_ID()); //check -1 and 1 consolidated query = new Query(Env.getCtx(), MStorageOnHand.Table_Name, "M_Product_ID=? AND M_AttributeSetInstance_ID=?", getTrxName()); onhand = query.setParameters(product1.get_ID(), asi1.get_ID()).first(); assertNotNull(onhand); assertEquals(0, onhand.getQtyOnHand().intValue()); query = new Query(Env.getCtx(), MStorageOnHand.Table_Name, "M_Product_ID=? AND M_AttributeSetInstance_ID=?", getTrxName()); onhand = query.setParameters(product1.get_ID(), 0).first(); assertNotNull(onhand); assertEquals(0, onhand.getQtyOnHand().intValue()); //check -1 and 1 not consolidated due to different lot query = new Query(Env.getCtx(), MStorageOnHand.Table_Name, "M_Product_ID=? AND M_AttributeSetInstance_ID=?", getTrxName()); onhand = query.setParameters(product2.get_ID(), asi2.get_ID()).first(); assertNotNull(onhand); assertEquals(-1, onhand.getQtyOnHand().intValue()); query = new Query(Env.getCtx(), MStorageOnHand.Table_Name, "M_Product_ID=? AND M_AttributeSetInstance_ID=?", getTrxName()); onhand = query.setParameters(product2.get_ID(), asi3.get_ID()).first(); assertNotNull(onhand); assertEquals(1, onhand.getQtyOnHand().intValue()); } finally { getTrx().rollback(); product1.deleteEx(true); } } }