From 0b0c6de47edb22e865e7bd32db4b27409bf945ba Mon Sep 17 00:00:00 2001 From: teo_sarca Date: Sat, 31 Jan 2009 13:33:16 +0000 Subject: [PATCH] FR [ 2552432 ] Create JUnit MRP tests http://sourceforge.net/tracker/index.php?func=detail&aid=2552432&group_id=176962&atid=879335 --- .classpath | 2 + base/src/org/eevolution/model/I_PP_MRP.java | 53 +++++ base/src/org/eevolution/model/X_PP_MRP.java | 17 +- .../src/test/functional/mrp/CSVFactory.java | 211 ++++++++++++++++++ extend/src/test/functional/mrp/MRPNotice.java | 50 +++++ extend/src/test/functional/mrp/MRPTest.java | 207 +++++++++++++++++ extend/src/test/functional/mrp/MRPTests.csv | 16 ++ .../test/functional/mrp/MRPTests_README.txt | 22 ++ extend/src/test/functional/mrp/MRPUtil.java | 109 +++++++++ .../src/test/functional/mrp/TestableMRP.java | 195 ++++++++++++++++ 10 files changed, 869 insertions(+), 13 deletions(-) create mode 100644 extend/src/test/functional/mrp/CSVFactory.java create mode 100644 extend/src/test/functional/mrp/MRPNotice.java create mode 100644 extend/src/test/functional/mrp/MRPTest.java create mode 100644 extend/src/test/functional/mrp/MRPTests.csv create mode 100644 extend/src/test/functional/mrp/MRPTests_README.txt create mode 100644 extend/src/test/functional/mrp/MRPUtil.java create mode 100644 extend/src/test/functional/mrp/TestableMRP.java diff --git a/.classpath b/.classpath index 25f7a4cee1..a7d20c8a12 100644 --- a/.classpath +++ b/.classpath @@ -142,5 +142,7 @@ + + diff --git a/base/src/org/eevolution/model/I_PP_MRP.java b/base/src/org/eevolution/model/I_PP_MRP.java index 9a3d3862ec..9c02785da4 100644 --- a/base/src/org/eevolution/model/I_PP_MRP.java +++ b/base/src/org/eevolution/model/I_PP_MRP.java @@ -45,6 +45,14 @@ public interface I_PP_MRP /** Load Meta Data */ + /** Column name AD_Client_ID */ + public static final String COLUMNNAME_AD_Client_ID = "AD_Client_ID"; + + /** Get Client. + * Client/Tenant for this installation. + */ + public int getAD_Client_ID(); + /** Column name AD_Org_ID */ public static final String COLUMNNAME_AD_Org_ID = "AD_Org_ID"; @@ -103,6 +111,22 @@ public interface I_PP_MRP public I_C_Order getC_Order() throws RuntimeException; + /** Column name Created */ + public static final String COLUMNNAME_Created = "Created"; + + /** Get Created. + * Date this record was created + */ + public Timestamp getCreated(); + + /** Column name CreatedBy */ + public static final String COLUMNNAME_CreatedBy = "CreatedBy"; + + /** Get Created By. + * User who created this records + */ + public int getCreatedBy(); + /** Column name DD_OrderLine_ID */ public static final String COLUMNNAME_DD_OrderLine_ID = "DD_OrderLine_ID"; @@ -222,6 +246,19 @@ public interface I_PP_MRP */ public String getDocStatus(); + /** Column name IsActive */ + public static final String COLUMNNAME_IsActive = "IsActive"; + + /** Set Active. + * The record is active in the system + */ + public void setIsActive (boolean IsActive); + + /** Get Active. + * The record is active in the system + */ + public boolean isActive(); + /** Column name IsAvailable */ public static final String COLUMNNAME_IsAvailable = "IsAvailable"; @@ -437,6 +474,22 @@ public interface I_PP_MRP /** Get TypeMRP */ public String getTypeMRP(); + /** Column name Updated */ + public static final String COLUMNNAME_Updated = "Updated"; + + /** Get Updated. + * Date this record was updated + */ + public Timestamp getUpdated(); + + /** Column name UpdatedBy */ + public static final String COLUMNNAME_UpdatedBy = "UpdatedBy"; + + /** Get Updated By. + * User who updated this records + */ + public int getUpdatedBy(); + /** Column name Value */ public static final String COLUMNNAME_Value = "Value"; diff --git a/base/src/org/eevolution/model/X_PP_MRP.java b/base/src/org/eevolution/model/X_PP_MRP.java index 9bfb578676..2407e1affa 100644 --- a/base/src/org/eevolution/model/X_PP_MRP.java +++ b/base/src/org/eevolution/model/X_PP_MRP.java @@ -36,7 +36,7 @@ public class X_PP_MRP extends PO implements I_PP_MRP, I_Persistent /** * */ - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 20081221L; /** Standard Constructor */ public X_PP_MRP (Properties ctx, int PP_MRP_ID, String trxName) @@ -427,10 +427,7 @@ public class X_PP_MRP extends PO implements I_PP_MRP, I_Persistent public void setDocStatus (String DocStatus) { - if (DocStatus == null || DocStatus.equals("DR") || DocStatus.equals("CO") || DocStatus.equals("AP") || DocStatus.equals("NA") || DocStatus.equals("VO") || DocStatus.equals("IN") || DocStatus.equals("RE") || DocStatus.equals("CL") || DocStatus.equals("??") || DocStatus.equals("IP") || DocStatus.equals("WP") || DocStatus.equals("WC")); - else throw new IllegalArgumentException ("DocStatus Invalid value - " + DocStatus + " - Reference_ID=131 - DR - CO - AP - NA - VO - IN - RE - CL - ?? - IP - WP - WC"); - - set_Value (COLUMNNAME_DocStatus, DocStatus); + if (DocStatus == null || DocStatus.equals("DR") || DocStatus.equals("CO") || DocStatus.equals("AP") || DocStatus.equals("NA") || DocStatus.equals("VO") || DocStatus.equals("IN") || DocStatus.equals("RE") || DocStatus.equals("CL") || DocStatus.equals("??") || DocStatus.equals("IP") || DocStatus.equals("WP") || DocStatus.equals("WC")); else throw new IllegalArgumentException ("DocStatus Invalid value - " + DocStatus + " - Reference_ID=131 - DR - CO - AP - NA - VO - IN - RE - CL - ?? - IP - WP - WC"); set_Value (COLUMNNAME_DocStatus, DocStatus); } /** Get Document Status. @@ -742,10 +739,7 @@ public class X_PP_MRP extends PO implements I_PP_MRP, I_Persistent public void setOrderType (String OrderType) { - if (OrderType == null || OrderType.equals("FCT") || OrderType.equals("MOP") || OrderType.equals("POO") || OrderType.equals("POR") || OrderType.equals("SOO") || OrderType.equals("DOO")); - else throw new IllegalArgumentException ("OrderType Invalid value - " + OrderType + " - Reference_ID=53229 - FCT - MOP - POO - POR - SOO - DOO"); - - set_Value (COLUMNNAME_OrderType, OrderType); + if (OrderType == null || OrderType.equals("FCT") || OrderType.equals("MOP") || OrderType.equals("POO") || OrderType.equals("POR") || OrderType.equals("SOO") || OrderType.equals("DOO")); else throw new IllegalArgumentException ("OrderType Invalid value - " + OrderType + " - Reference_ID=53229 - FCT - MOP - POO - POR - SOO - DOO"); set_Value (COLUMNNAME_OrderType, OrderType); } /** Get OrderType. @@ -953,10 +947,7 @@ public class X_PP_MRP extends PO implements I_PP_MRP, I_Persistent public void setTypeMRP (String TypeMRP) { - if (TypeMRP == null || TypeMRP.equals("D") || TypeMRP.equals("S")); - else throw new IllegalArgumentException ("TypeMRP Invalid value - " + TypeMRP + " - Reference_ID=53230 - D - S"); - - set_Value (COLUMNNAME_TypeMRP, TypeMRP); + if (TypeMRP == null || TypeMRP.equals("D") || TypeMRP.equals("S")); else throw new IllegalArgumentException ("TypeMRP Invalid value - " + TypeMRP + " - Reference_ID=53230 - D - S"); set_Value (COLUMNNAME_TypeMRP, TypeMRP); } /** Get TypeMRP. diff --git a/extend/src/test/functional/mrp/CSVFactory.java b/extend/src/test/functional/mrp/CSVFactory.java new file mode 100644 index 0000000000..50173b45d8 --- /dev/null +++ b/extend/src/test/functional/mrp/CSVFactory.java @@ -0,0 +1,211 @@ +/****************************************************************************** + * Product: Adempiere ERP & CRM Smart Business Solution * + * Copyright (C) 2008 SC ARHIPAC SERVICE SRL. All Rights Reserved. * + * This program is free software; you can redistribute it and/or modify it * + * under the terms version 2 of the GNU General Public License as published * + * by the Free Software Foundation. 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., * + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * + *****************************************************************************/ +package test.functional.mrp; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.math.BigDecimal; +import java.sql.Timestamp; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.List; + +import org.eevolution.model.I_PP_MRP; +import org.supercsv.io.CsvListReader; +import org.supercsv.io.ICsvListReader; +import org.supercsv.prefs.CsvPreference; + +/** + * Read a CSV file and produce {@link TestableMRP} objects, ready to be run. + * @author Teo Sarca, www.arhipac.ro + */ +public class CSVFactory +{ + public static final DateFormat s_dateFormat = new SimpleDateFormat("dd.MM.yyyy"); + + private ICsvListReader reader; + + public Collection read(InputStream in) throws Exception + { + ArrayList tests = new ArrayList(); + // + reader = new CsvListReader(new InputStreamReader(in), CsvPreference.STANDARD_PREFERENCE); + String[] header = reader.getCSVHeader(true); + System.out.println("HEADER: "+MRPUtil.toString(header)); + // + List line; + int last_lineNo = -1; + boolean isPlanningLine = true; + TestableMRP mrpTest = null; + try + { + while ( (line = reader.read()) != null) + { + if (last_lineNo == -1 || last_lineNo + 1 < reader.getLineNumber()) + { + isPlanningLine = true; + if (mrpTest != null) + { + tests.add(mrpTest); + } + mrpTest = new TestableMRP(); + } + if (isPlanningLine) + { + readProductPlanning(mrpTest, header, line); + isPlanningLine = false; + } + else + { + readMRPLine(mrpTest, header, line); + } + // + last_lineNo = reader.getLineNumber(); + } + } + catch (Exception e) + { + throw new RuntimeException("Error on line "+reader.getLineNumber()+": "+e.getLocalizedMessage(), e); + } + // + return tests; + } + + private void readProductPlanning(TestableMRP mrpTest, String[] header, List line) + { + mrpTest.name = "junit-test-line_"+reader.getLineNumber(); + mrpTest.description = "Test starts in CSV at line "+reader.getLineNumber(); + mrpTest.qtyOnHand = getValue("QtyOnHand", BigDecimal.class, header, line); + mrpTest.today = getValue("Today", Timestamp.class, header, line); + // + int LeadTime = getValue("LeadTime", Integer.class, header, line); + String Order_Policy = getValue("Order_Policy", String.class, header, line); + int Order_Min = getValue("Order_Min", Integer.class, header, line); + int Order_Pack = getValue("Order_Min", Integer.class, header, line); + int Order_Max = getValue("Order_Max", Integer.class, header, line); + int SafetyStock = getValue("SafetyStock", Integer.class, header, line); + int Order_Period = 0; + mrpTest.planning = MRPTest.getPlanning(mrpTest.productValue, + Order_Policy, Order_Min, Order_Max, Order_Pack, SafetyStock, Order_Period, LeadTime); + } + + private void readMRPLine(TestableMRP mrpTest, String[] header, List line) + { + boolean isGenerated = getValue("Generated", Boolean.class, header, line); + Timestamp DatePromised = getValue("DatePromised", Timestamp.class, header, line); + String TypeMRP = getValue("TypeMRP", String.class, header, line); + String DocStatus = getValue("DocStatus", String.class, header, line); + BigDecimal Qty = getValue("Qty", BigDecimal.class, header, line); + String MRP_Notice = getValue("MRP_Notice", String.class, header, line); + // + if (MRP_Notice != null && MRP_Notice.trim().length() > 0) + { + mrpTest.expectedNotices.add(new MRPNotice(MRP_Notice)); + } + // + if (TypeMRP == null || TypeMRP.trim().length() == 0) + { + ; + } + else + { + I_PP_MRP mrp = MRPTest.createMRP(mrpTest.planning, TypeMRP, DocStatus, Qty, DatePromised); + mrp.setDescription("CSV Line "+reader.getLineNumber()); + if (isGenerated) + { + mrpTest.expectedMRP.add(mrp); + } + else + { + mrpTest.initialMRP.add(mrp); + } + } + } + + @SuppressWarnings("unchecked") + public static T getValue(String name, Class clazz, String[] headers, List values) + { + String value = null; + for (int i = 0; i < headers.length; i++) + { + if (name.equalsIgnoreCase(headers[i])) + { + if (values.size() > i) + { + value = values.get(i); + } + break; + } + } + if (value != null && value.trim().length() == 0) + { + value = null; + } + // + if (String.class == clazz) + { + return (T)value; + } + else if (BigDecimal.class == clazz) + { + if (value == null) + return (T)BigDecimal.ZERO; + else + return (T)new BigDecimal(value); + } + else if (Integer.class == clazz) + { + if (value == null) + return (T)Integer.valueOf(0); + else + return (T)((Integer)Integer.parseInt(value)); + } + else if (Timestamp.class == clazz) + { + if (value == null) + return null; + else + { + try + { + Date date = s_dateFormat.parse(value); + return (T)new Timestamp(date.getTime()); + } + catch(ParseException e) + { + throw new RuntimeException(e); + } + } + } + else if (Boolean.class == clazz) + { + if (value == null) + return (T)Boolean.FALSE; + else if ("Y".equals(value)) + return (T)Boolean.TRUE; + else if ("N".equals(value)) + return (T)Boolean.FALSE; + else + throw new IllegalStateException("Invalid boolean value '"+value+"'"); + } + else + { + throw new IllegalArgumentException("clazz not supported - "+clazz); + } + } +} diff --git a/extend/src/test/functional/mrp/MRPNotice.java b/extend/src/test/functional/mrp/MRPNotice.java new file mode 100644 index 0000000000..2fb2571549 --- /dev/null +++ b/extend/src/test/functional/mrp/MRPNotice.java @@ -0,0 +1,50 @@ +/****************************************************************************** + * Product: Adempiere ERP & CRM Smart Business Solution * + * Copyright (C) 2008 SC ARHIPAC SERVICE SRL. All Rights Reserved. * + * This program is free software; you can redistribute it and/or modify it * + * under the terms version 2 of the GNU General Public License as published * + * by the Free Software Foundation. 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., * + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * + *****************************************************************************/ +package test.functional.mrp; + +import java.math.BigDecimal; + +import org.compiere.model.MProduct; + +/** + * MRP Notice Value Object + * @author Teo Sarca, www.arhipac.ro + */ +public class MRPNotice +{ + public String code; + public int AD_Org_ID; + public int PP_MRP_ID; + public MProduct product; + public String documentNo; + public BigDecimal qty; + public String comment; + + public MRPNotice(String code) + { + this.code = code; + } + + public String toString() + { + return this.code + "[" + +"AD_Org_ID="+this.AD_Org_ID + +", PP_MRP_ID="+this.PP_MRP_ID + +", Product="+(this.product != null ? this.product.getValue() : "null") + +", DocumentNo="+this.documentNo + +", Qty="+this.qty + +", Comment="+this.comment + +"]"; + } +} diff --git a/extend/src/test/functional/mrp/MRPTest.java b/extend/src/test/functional/mrp/MRPTest.java new file mode 100644 index 0000000000..4eefa914e3 --- /dev/null +++ b/extend/src/test/functional/mrp/MRPTest.java @@ -0,0 +1,207 @@ +/****************************************************************************** + * Product: Adempiere ERP & CRM Smart Business Solution * + * Copyright (C) 2008 SC ARHIPAC SERVICE SRL. All Rights Reserved. * + * This program is free software; you can redistribute it and/or modify it * + * under the terms version 2 of the GNU General Public License as published * + * by the Free Software Foundation. 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., * + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * + *****************************************************************************/ +package test.functional.mrp; + +import java.io.InputStream; +import java.math.BigDecimal; +import java.sql.Timestamp; +import java.util.Collection; +import java.util.Properties; + +import org.compiere.model.MProduct; +import org.compiere.model.MResource; +import org.compiere.model.MWarehouse; +import org.compiere.util.Env; +import org.eevolution.model.I_PP_MRP; +import org.eevolution.model.I_PP_Product_Planning; +import org.eevolution.model.MPPMRP; +import org.eevolution.model.MPPProductPlanning; + +import test.AdempiereTestCase; + +/** + * MRP Engine Test Case + * @author Teo Sarca, www.arhipac.ro + */ +public class MRPTest extends AdempiereTestCase +{ + @Override + protected void setUp() throws Exception + { + super.setUp(); + } + + public void test01() throws Exception + { +// InputStream in = new FileInputStream("D:\\Kituri\\fm"); + InputStream in = getClass().getClassLoader().getResourceAsStream("test/functional/mrp/MRPTests.csv"); + CSVFactory factory = new CSVFactory(); + Collection tests = factory.read(in); + // + for (TestableMRP test : tests) + { + _testMRP(test); + rollback(); + } + } + private void _testMRP(TestableMRP test) throws Exception + { + boolean ok = false; + test.trxName = getTrxName(); + try + { + test.doIt(); +// test.dumpStatus(); + // + assertEquals(test.name+": MRP Records# not match", test.expectedMRP.size(), test.actualMRP.size()); + for (int i = 0; i < test.expectedMRP.size(); i++) + { + assertEquals(test.name+": MRP Record not match", + test.expectedMRP.get(i), + test.actualMRP.get(i)); + } + // + assertEquals(test.name+": MRP Notices# not match", test.expectedNotices.size(), test.actualNotices.size()); + for (int i = 0; i < test.expectedNotices.size(); i++) + { + assertEquals(test.name+": MRP Record not match", + test.expectedNotices.get(i).code, + test.actualNotices.get(i).code); + } + // + ok = true; + } + finally + { + if (!ok) + { + System.err.println("ERRROR_______________________________________"); + test.dumpStatus(); + } + } + } + + + /** + * Helper Method : Create Product Planning + */ + public static I_PP_Product_Planning getPlanning(String productValue, + String Order_Policy, + int Order_Min, int Order_Max, int Order_Pack, int SafetyStock, + int Order_Period, + int LeadTime) + { + boolean isPurchased = true; + int PlanningHorizon = 365; + // + Properties ctx = Env.getCtx(); +// int AD_Client_ID = Env.getAD_Client_ID(ctx); + int AD_Org_ID = MRPUtil.getFirst_Org_ID(); + MWarehouse wh = MRPUtil.getCreateWarehouse(AD_Org_ID, productValue); + MResource plant = MRPUtil.getCreatePlant(productValue, wh.get_ID(), PlanningHorizon); + MProduct product = getCreateProduct(ctx, productValue, isPurchased); + // + MPPProductPlanning pp = new MPPProductPlanning(ctx, 0, null); + pp.setIsCreatePlan(true); + pp.setIsRequiredMRP(true); + pp.setIsRequiredDRP(false); + pp.setM_Product_ID(product.get_ID()); + pp.setAD_Org_ID(AD_Org_ID); + pp.setM_Warehouse_ID(wh.get_ID()); + pp.setS_Resource_ID(plant.get_ID()); + // + pp.setOrder_Policy(Order_Policy); + pp.setOrder_Min(BigDecimal.valueOf(Order_Min)); + pp.setOrder_Max(BigDecimal.valueOf(Order_Max)); + pp.setOrder_Pack(BigDecimal.valueOf(Order_Pack)); + pp.setSafetyStock(BigDecimal.valueOf(SafetyStock)); + pp.setOrder_Period(BigDecimal.valueOf(Order_Period)); + pp.setDeliveryTime_Promised(BigDecimal.valueOf(LeadTime)); + // + return pp; + } + + public static I_PP_MRP createMRP(I_PP_Product_Planning planning, + String TypeMRP, String DocStatus, BigDecimal Qty, Timestamp DatePromised) + { + Properties ctx = Env.getCtx(); + // + MPPMRP mrp = new MPPMRP(ctx, 0, null); + mrp.setAD_Org_ID(planning.getAD_Org_ID()); + mrp.setName("MRP"); + mrp.setTypeMRP(TypeMRP); + mrp.setDocStatus(DocStatus); + mrp.setQty(Qty); + mrp.setDatePromised(DatePromised); + mrp.setDateStartSchedule(DatePromised); + mrp.setDateFinishSchedule(DatePromised); + mrp.setDateOrdered(DatePromised); + mrp.setM_Product_ID(planning.getM_Product_ID()); + mrp.setM_Warehouse_ID(planning.getM_Warehouse_ID()); + return mrp; + } + + /** + * Helper Method : Create Product + */ + public static MProduct getCreateProduct(Properties ctx, String value, boolean isPurchased) + { + MProduct[] arr = MProduct.get(ctx, "Value='"+value+"'", null); + if (arr.length > 0) + { + return arr[0]; + } + MProduct p = new MProduct(ctx, 0, null); + p.setValue(value); + p.setName(value); + p.setAD_Org_ID(0); + p.setProductType (MProduct.PRODUCTTYPE_Item); // I + p.setIsBOM (false); // N + p.setIsInvoicePrintDetails (false); + p.setIsPickListPrintDetails (false); + p.setIsPurchased (isPurchased); + p.setIsSold (true); // Y + p.setIsStocked (true); // Y + p.setIsSummary (false); + p.setIsVerified (false); // N + p.setIsWebStoreFeatured (false); + p.setIsSelfService(true); + p.setIsExcludeAutoDelivery(false); + p.setProcessing (false); // N + p.setC_UOM_ID(100); // Each + p.saveEx(); + return p; + } + + public void assertEquals(String message, I_PP_MRP expected, I_PP_MRP actual) throws Exception + { + boolean equals = expected.getAD_Client_ID() == actual.getAD_Client_ID() + && expected.getAD_Org_ID() == actual.getAD_Org_ID() + && expected.getM_Warehouse_ID() == actual.getM_Warehouse_ID() + && expected.getM_Product_ID() == actual.getM_Product_ID() + && expected.getQty().equals(actual.getQty()) + && expected.getTypeMRP().equals(actual.getTypeMRP()) + && expected.getDocStatus().equals(actual.getDocStatus()) + && expected.getDatePromised().equals(actual.getDatePromised()) + && expected.getDateStartSchedule().equals(actual.getDateStartSchedule()) + && expected.getDateFinishSchedule().equals(actual.getDateFinishSchedule()) + && expected.getDateOrdered().equals(actual.getDateOrdered()); + // + StringBuffer sb = new StringBuffer(message) + .append(": expected="+expected) + .append(", actual="+actual); + + assertTrue(sb.toString(), equals); + } +} diff --git a/extend/src/test/functional/mrp/MRPTests.csv b/extend/src/test/functional/mrp/MRPTests.csv new file mode 100644 index 0000000000..2e5546e629 --- /dev/null +++ b/extend/src/test/functional/mrp/MRPTests.csv @@ -0,0 +1,16 @@ +Generated,DatePromised,TypeMRP,DocStatus,Qty,MRP_Notice,QtyOnHand,LeadTime,Order_Policy,Order_Min,Order_Pack,Today,Order_Max,SafetyStock +N,,,,,,4,3,LFL,0,0,30.01.2009,, +N,28.02.2009,D,CO,10,,,,,,,30.01.2009,, +Y,28.02.2009,S,DR,6,,,,,,,30.01.2009,, + +N,,,,,,0,0,LFL,,,29.01.2009,, +N,01.02.2009,D,CO,21,,,,,,,29.01.2009,, +Y,01.02.2009,S,DR,21,,,,,0,0,29.01.2009,0,0 + +N,,,,,,0,0,LFL,,,29.01.2009,, +N,06.02.2009,D,CO,10,,,,,,,29.01.2009,, +Y,06.02.2009,S,DR,10,,,,,0,0,29.01.2009,0,0 + +N,,,,,,0,0,LFL,15,,29.01.2009,, +N,06.02.2009,D,CO,10,MRP-080,,,,,,29.01.2009,, +Y,06.02.2009,S,DR,15,,,,,,,29.01.2009,, diff --git a/extend/src/test/functional/mrp/MRPTests_README.txt b/extend/src/test/functional/mrp/MRPTests_README.txt new file mode 100644 index 0000000000..2b18cd4765 --- /dev/null +++ b/extend/src/test/functional/mrp/MRPTests_README.txt @@ -0,0 +1,22 @@ +MRPTests Format/Rules: + +* Tests are separated by a completelly empty line +* First line from each test is containing the product data planning parameters; + The CSV column names are identical with those from PP_Product_Planning table. +* Next lines are the MRP records; The CSV column names are identical with those from PP_MRP table. +* The "Generated" column (first column from CSV file) is applicable just for MRP record lines and means: + N = This record is not generated and it will be created before running the MRP engine. + Y = This record IS generated. We expect this as a resulting MRP record after MRP engine runs. +* The "MRP_Notice" column specify that we expect that MRP notice to be throwed by MRP engine. + For more informations regarding MRP notices please run following SQL query: + SELECT Value, MsgText, MsgTip FROM AD_Message WHERE value LIKE 'MRP-%' + ORDER BY Value +* The "Today" column specify which is the "Today" date for MRP engine. In a normal environment (i.e. running Adempiere client), + MRP engine assumes that Today is system date +* The "LeadTime" column is PP_ProductPlanning.DeliveryTime_Promised + + +For any other questions, please ask in ADempiere forums ;) + +Best regards, +Teo Sarca - www.arhipac.ro diff --git a/extend/src/test/functional/mrp/MRPUtil.java b/extend/src/test/functional/mrp/MRPUtil.java new file mode 100644 index 0000000000..8fcca66cd8 --- /dev/null +++ b/extend/src/test/functional/mrp/MRPUtil.java @@ -0,0 +1,109 @@ +/****************************************************************************** + * Product: Adempiere ERP & CRM Smart Business Solution * + * Copyright (C) 2008 SC ARHIPAC SERVICE SRL. All Rights Reserved. * + * This program is free software; you can redistribute it and/or modify it * + * under the terms version 2 of the GNU General Public License as published * + * by the Free Software Foundation. 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., * + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * + *****************************************************************************/ +package test.functional.mrp; + +import java.util.Properties; + +import org.compiere.model.MLocation; +import org.compiere.model.MResource; +import org.compiere.model.MWarehouse; +import org.compiere.model.Query; +import org.compiere.util.DB; +import org.compiere.util.Env; + +/** + * Many helper methods for producing different entities + * @author Teo Sarca, www.arhipac.ro + */ +public class MRPUtil +{ + + public static int getFirst_Org_ID() + { + String sql = "SELECT MIN(AD_Org_ID) FROM AD_Org WHERE AD_Client_ID=?"; + return DB.getSQLValueEx(null, sql, Env.getAD_Client_ID(Env.getCtx())); + } + + /** + * Helper Method : Create Warehouse + */ + public static MWarehouse getCreateWarehouse(int AD_Org_ID, String value) + { + Properties ctx = Env.getCtx(); + int AD_Client_ID = Env.getAD_Client_ID(ctx); + String whereClause = "AD_Client_ID=? AND AD_Org_ID=? AND Value=?"; + MWarehouse wh = new Query(ctx, MWarehouse.Table_Name, whereClause, null) + .setParameters(new Object[]{AD_Client_ID, AD_Org_ID, value}) + .firstOnly(); + if (wh != null) + return wh; + wh = new MWarehouse(ctx, 0, null); + wh.setAD_Org_ID(AD_Org_ID); + wh.setValue(value); + wh.setName(value); + + MLocation loc = new MLocation(ctx, 0, null); + loc.saveEx(); + wh.setC_Location_ID(loc.get_ID()); + wh.saveEx(); + return wh; + } + + /** + * Helper Method : Create Plant (S_Resource_ID) + */ + public static MResource getCreatePlant(String value, int M_Warehouse_ID, int PlanningHorizon) + { + Properties ctx = Env.getCtx(); + int AD_Client_ID = Env.getAD_Client_ID(ctx); + String whereClause = MResource.COLUMNNAME_Value+"=? AND AD_Client_ID=?"; + MResource r = new Query(ctx, MResource.Table_Name, whereClause, null) + .setParameters(new Object[]{value, AD_Client_ID}) + .firstOnly(); + if (r == null) + { + r = new MResource(ctx, 0, null); + int S_ResourceType_ID = DB.getSQLValueEx(null, + "SELECT MIN(S_ResourceType_ID) FROM S_Resource WHERE AD_Client_ID=? AND IsAvailable=?", + AD_Client_ID, true); + r.setS_ResourceType_ID(S_ResourceType_ID); + } + r.setValue(value); + r.setName(value); + r.setIsManufacturingResource(true); + r.setManufacturingResourceType(MResource.MANUFACTURINGRESOURCETYPE_Plant); + r.setIsAvailable(true); + r.setM_Warehouse_ID(M_Warehouse_ID); + r.setPlanningHorizon(PlanningHorizon); + r.setPercentUtilization(Env.ONEHUNDRED); + r.saveEx(); + return r; + } + + public static String toString(Object[] arr) + { + if (arr == null) + return "null"; + // + StringBuffer sb = new StringBuffer(); + int i = 1; + sb.append("(size="+arr.length+")"); + for (Object o : arr) + { + sb.append("["+i+":"+o+"]"); + i++; + } + return sb.toString(); + } +} diff --git a/extend/src/test/functional/mrp/TestableMRP.java b/extend/src/test/functional/mrp/TestableMRP.java new file mode 100644 index 0000000000..6a66a9091f --- /dev/null +++ b/extend/src/test/functional/mrp/TestableMRP.java @@ -0,0 +1,195 @@ +/****************************************************************************** + * Product: Adempiere ERP & CRM Smart Business Solution * + * Copyright (C) 2008 SC ARHIPAC SERVICE SRL. All Rights Reserved. * + * This program is free software; you can redistribute it and/or modify it * + * under the terms version 2 of the GNU General Public License as published * + * by the Free Software Foundation. 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., * + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * + *****************************************************************************/ +package test.functional.mrp; + +import java.math.BigDecimal; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +import org.compiere.model.MProduct; +import org.compiere.model.PO; +import org.compiere.util.DB; +import org.compiere.util.Env; +import org.eevolution.model.I_PP_MRP; +import org.eevolution.model.I_PP_Product_Planning; +import org.eevolution.model.X_PP_MRP; +import org.eevolution.process.MRP; + +/** + * Extends {@link MRP} engine process and simulates initial context + * (product data planning, existing MRP records). + * + * @author Teo Sarca, www.arhipac.ro + */ +class TestableMRP extends org.eevolution.process.MRP +{ + public String name = "junit-test"; + public String description = ""; + public String trxName = null; + public String productValue = "junit-test"; + public I_PP_Product_Planning planning; + public Timestamp today; + public BigDecimal qtyOnHand; + // + public List initialMRP = new ArrayList(); + public List expectedMRP = new ArrayList(); + public List actualMRP = new ArrayList(); + // + public List expectedNotices = new ArrayList(); + public List actualNotices = new ArrayList(); + + public TestableMRP() + { + } + @Override + public Properties getCtx() + { + return Env.getCtx(); + } + @Override + protected String get_TrxName() + { + return this.trxName; + } + @Override + protected int getAD_Client_ID() + { + return this.planning.getAD_Client_ID(); + } + @Override + public int getAD_Org_ID() + { + return this.planning.getAD_Org_ID(); + } + @Override + public int getM_Warehouse_ID() + { + return this.planning.getM_Warehouse_ID(); + } + @Override + public int getPlant_ID() + { + return this.planning.getS_Resource_ID(); + } + @Override + public boolean isRequiredDRP() + { + return this.planning.isRequiredDRP(); + } + @Override + protected I_PP_Product_Planning getProductPlanning(int AD_Client_ID, int AD_Org_ID, + int S_Resource_ID, int M_Warehouse_ID, MProduct product) + { + return this.planning; + } + @Override + protected BigDecimal getQtyOnHand(I_PP_Product_Planning pp) + { + return this.qtyOnHand; + } + @Override + protected Timestamp getToday() + { + return this.today; + } + @Override + protected void createMRPNote(String code, int AD_Org_ID, int PP_MRP_ID, MProduct product, String documentNo, BigDecimal qty, String comment) + { + MRPNotice note = new MRPNotice(code); + note.AD_Org_ID = AD_Org_ID; + note.PP_MRP_ID = PP_MRP_ID; + note.product = product; + note.documentNo = documentNo; + note.qty = qty; + note.comment = comment; + this.actualNotices.add(note); + } + @Override + protected void createDDOrder(int AD_Org_ID, int PP_MRP_ID, MProduct product, BigDecimal QtyPlanned, Timestamp DemandDateStartSchedule) + { + createMRPSupply(AD_Org_ID, PP_MRP_ID, product, QtyPlanned, DemandDateStartSchedule); + } + @Override + protected void createPPOrder(int AD_Org_ID, int PP_MRP_ID, MProduct product, BigDecimal QtyPlanned, Timestamp DemandDateStartSchedule) + { + createMRPSupply(AD_Org_ID, PP_MRP_ID, product, QtyPlanned, DemandDateStartSchedule); + } + @Override + protected void createRequisition(int AD_Org_ID, int PP_MRP_ID, MProduct product, BigDecimal QtyPlanned, Timestamp DemandDateStartSchedule) + { + createMRPSupply(AD_Org_ID, PP_MRP_ID, product, QtyPlanned, DemandDateStartSchedule); + } + private void createMRPSupply(int AD_Org_ID, int PP_MRP_ID, MProduct product, BigDecimal QtyPlanned, Timestamp DemandDateStartSchedule) + { + I_PP_MRP mrp = MRPTest.createMRP(this.planning, X_PP_MRP.TYPEMRP_Supply, X_PP_MRP.DOCSTATUS_Drafted, + QtyPlanned, DemandDateStartSchedule); + ((PO)mrp).saveEx(get_TrxName()); + this.actualMRP.add(mrp); + } + @Override + public String doIt() throws Exception + { + this.p_M_Product_ID = this.planning.getM_Product_ID(); + // Create MRP lines: + for (I_PP_MRP mrp : this.initialMRP) + ((PO)mrp).saveEx(get_TrxName()); + // + return super.doIt(); + } + @Override + protected void deleteMRP(int AD_Client_ID, int AD_Org_ID, int S_Resource_ID, int M_Warehouse_ID) + { + // Delete all MRP records for our testing product + String sql = "DELETE FROM PP_MRP" + +" WHERE AD_Client_ID=? AND AD_Org_ID=?" + +" AND M_Warehouse_ID=? AND S_Resource_ID=?" + +" AND M_Product_ID=?"; + int no = DB.executeUpdateEx(sql, + new Object[]{AD_Client_ID, AD_Org_ID, + M_Warehouse_ID, S_Resource_ID, this.p_M_Product_ID}, + get_TrxName()); + log.info("[DEBUG] clean up MRP #"+no); + // + super.deleteMRP(AD_Client_ID, AD_Org_ID, S_Resource_ID, M_Warehouse_ID); + } + + public void dumpStatus() + { + log.info("------------ MRP TEST --------------"); + log.info(" Name : "+this.name); + log.info(" Description : "+this.description); + log.info(" Product : "+this.productValue); + log.info(" Today : "+this.today); + log.info(" QtyOnHand : "+this.qtyOnHand); + ((PO)this.planning).dump(); + // + log.info("------------ Initial MRP --------------"); + for (I_PP_MRP mrp : this.initialMRP) + log.info(" "+((PO)mrp).toString()); + log.info("------------ Expected MRP --------------"); + for (I_PP_MRP mrp : this.expectedMRP) + log.info(" "+((PO)mrp).toString()); + log.info("------------ Actual MRP --------------"); + for (I_PP_MRP mrp : this.actualMRP) + log.info((" "+(PO)mrp).toString()); + log.info("------------ Expected NOTICES --------------"); + for (MRPNotice notice : this.expectedNotices) + log.info(" "+notice.toString()); + log.info("------------ Actual NOTICES --------------"); + for (MRPNotice notice : this.actualNotices) + log.info(" "+notice.toString()); + } +}