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());
+ }
+}