diff --git a/base/src/org/compiere/model/MResourceType.java b/base/src/org/compiere/model/MResourceType.java
index 3ae2bd2165..96ba7000df 100644
--- a/base/src/org/compiere/model/MResourceType.java
+++ b/base/src/org/compiere/model/MResourceType.java
@@ -17,9 +17,14 @@
package org.compiere.model;
import java.sql.ResultSet;
+import java.sql.Timestamp;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
import java.util.Properties;
+import org.adempiere.exceptions.AdempiereException;
import org.compiere.util.CCache;
+import org.compiere.util.TimeUtil;
/**
@@ -30,6 +35,7 @@ import org.compiere.util.CCache;
*
* @author Teo Sarca, www.arhipac.ro
*
FR [ 2051056 ] MResource[Type] should be cached
+ * added manufacturing related methods (getDayStart, getDayEnd etc)
*/
public class MResourceType extends X_S_ResourceType
{
@@ -78,6 +84,19 @@ public class MResourceType extends X_S_ResourceType
super(ctx, rs, trxName);
} // MResourceType
+ @Override
+ protected boolean beforeSave(boolean newRecord)
+ {
+ if (isTimeSlot())
+ {
+ if (getTimeSlotStart().compareTo(getTimeSlotEnd()) >= 0)
+ {
+ throw new AdempiereException("@TimeSlotStart@ > @TimeSlotEnd@");
+ }
+ }
+ return true;
+ }
+
@Override
protected boolean afterSave (boolean newRecord, boolean success)
{
@@ -102,4 +121,102 @@ public class MResourceType extends X_S_ResourceType
return success;
} // afterSave
+
+ public Timestamp getDayStart(Timestamp date)
+ {
+ if(isTimeSlot())
+ {
+ return TimeUtil.getDayBorder(date, getTimeSlotStart(), false);
+ }
+ else
+ {
+ return TimeUtil.getDayBorder(date, null, false);
+ }
+ }
+
+ public Timestamp getDayEnd(Timestamp date)
+ {
+ if(isTimeSlot())
+ {
+ return TimeUtil.getDayBorder(date, getTimeSlotEnd(), true);
+ }
+ else
+ {
+ return TimeUtil.getDayBorder(date, null, true);
+ }
+ }
+
+ public long getDayDurationMillis()
+ {
+ if (isTimeSlot())
+ {
+ return getTimeSlotEnd().getTime() - getTimeSlotStart().getTime();
+ }
+ else
+ {
+ return 24*60*60*1000; // 24 hours
+ }
+ }
+
+ public boolean isDayAvailable(Timestamp dateTime)
+ {
+ if (!isActive())
+ {
+ return false;
+ }
+ if(isDateSlot())
+ {
+ return true;
+ }
+
+ GregorianCalendar gc = new GregorianCalendar();
+ gc.setTimeInMillis(dateTime.getTime());
+
+ boolean retValue = false;
+ switch(gc.get(Calendar.DAY_OF_WEEK)) {
+ case Calendar.SUNDAY:
+ retValue = isOnSunday();
+ break;
+
+ case Calendar.MONDAY:
+ retValue = isOnMonday();
+ break;
+
+ case Calendar.TUESDAY:
+ retValue = isOnTuesday();
+ break;
+
+ case Calendar.WEDNESDAY:
+ retValue = isOnWednesday();
+ break;
+
+ case Calendar.THURSDAY:
+ retValue = isOnThursday();
+ break;
+
+ case Calendar.FRIDAY:
+ retValue = isOnFriday();
+ break;
+
+ case Calendar.SATURDAY:
+ retValue = isOnSaturday();
+ break;
+ }
+
+ return retValue;
+ }
+
+ public boolean isAvailable()
+ {
+ if (!isActive())
+ {
+ return false;
+ }
+ if(!isDateSlot())
+ {
+ return true;
+ }
+ return isOnMonday() || isOnTuesday() || isOnWednesday() || isOnThursday() || isOnFriday()
+ || isOnSaturday() || isOnSunday();
+ }
} // MResourceType
diff --git a/base/src/org/compiere/model/MResourceUnAvailable.java b/base/src/org/compiere/model/MResourceUnAvailable.java
index b0d625e700..7820ca6ecc 100644
--- a/base/src/org/compiere/model/MResourceUnAvailable.java
+++ b/base/src/org/compiere/model/MResourceUnAvailable.java
@@ -16,9 +16,12 @@
*****************************************************************************/
package org.compiere.model;
-import java.sql.*;
-import java.util.*;
-import org.compiere.util.*;
+import java.sql.ResultSet;
+import java.sql.Timestamp;
+import java.util.Properties;
+
+import org.compiere.util.Msg;
+import org.compiere.util.TimeUtil;
/**
@@ -26,10 +29,32 @@ import org.compiere.util.*;
*
* @author Jorg Janke
* @version $Id: MResourceUnAvailable.java,v 1.2 2006/07/30 00:51:05 jjanke Exp $
+ *
+ * @author Teo Sarca, www.arhipac.ro
*/
public class MResourceUnAvailable extends X_S_ResourceUnAvailable
{
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Check if a resource is not available
+ * @param r resource
+ * @param dateTime date (date is truncated to day)
+ * @return true if resource is unavailable
+ */
+ public static boolean isUnAvailable(MResource r, Timestamp dateTime)
+ {
+ Timestamp date = TimeUtil.trunc(dateTime, TimeUtil.TRUNC_DAY);
+ final String whereClause = COLUMNNAME_S_Resource_ID+"=? AND AD_Client_ID=?"
+ +" AND TRUNC("+COLUMNNAME_DateFrom+") <= ?"
+ +" AND TRUNC("+COLUMNNAME_DateTo+") >= ?";
+ return new Query(r.getCtx(), MResourceUnAvailable.Table_Name, whereClause, null)
+ .setParameters(new Object[]{r.get_ID(), r.getAD_Client_ID(), date, date})
+ .match();
+
+ }
+
/**
* Standard Constructor
* @param ctx context
@@ -50,13 +75,8 @@ public class MResourceUnAvailable extends X_S_ResourceUnAvailable
{
super(ctx, rs, trxName);
} // MResourceUnAvailable
-
-
- /**
- * Before Save
- * @param newRecord new
- * @return true
- */
+
+ @Override
protected boolean beforeSave (boolean newRecord)
{
if (getDateTo() == null)
@@ -69,4 +89,24 @@ public class MResourceUnAvailable extends X_S_ResourceUnAvailable
return true;
} // beforeSave
+
+ /**
+ * Check if the resource is unavailable for date
+ * @param date
+ * @return true if valid
+ */
+ public boolean isUnAvailable(Timestamp dateTime)
+ {
+ Timestamp date = TimeUtil.trunc(dateTime, TimeUtil.TRUNC_DAY);
+ Timestamp dateFrom = getDateFrom();
+ Timestamp dateTo = getDateTo();
+
+ if (dateFrom != null && date.before(dateFrom))
+ return false;
+ if (dateTo != null && date.after(dateTo))
+ return false;
+ return true;
+ }
+
+
} // MResourceUnAvailable
diff --git a/base/src/org/compiere/util/TimeUtil.java b/base/src/org/compiere/util/TimeUtil.java
index b0888d2e4e..5d024570d6 100644
--- a/base/src/org/compiere/util/TimeUtil.java
+++ b/base/src/org/compiere/util/TimeUtil.java
@@ -417,8 +417,14 @@ public class TimeUtil
*/
static public Timestamp addDays (Timestamp day, int offset)
{
+ if (offset == 0)
+ {
+ return day;
+ }
if (day == null)
+ {
day = new Timestamp(System.currentTimeMillis());
+ }
//
GregorianCalendar cal = new GregorianCalendar();
cal.setTime(day);
@@ -655,6 +661,51 @@ public class TimeUtil
return new Timestamp (cal.getTimeInMillis());
} // trunc
+ /**
+ * Returns the day border by combining the date part from dateTime and time part form timeSlot.
+ * If timeSlot is null, then first milli of the day will be used (if end == false)
+ * or last milli of the day (if end == true).
+ *
+ * @param dateTime
+ * @param timeSlot
+ * @param end
+ * @return
+ */
+ public static Timestamp getDayBorder(Timestamp dateTime, Timestamp timeSlot, boolean end)
+ {
+ GregorianCalendar gc = new GregorianCalendar();
+ gc.setTimeInMillis(dateTime.getTime());
+ dateTime.setNanos(0);
+
+ if(timeSlot != null)
+ {
+ timeSlot.setNanos(0);
+ GregorianCalendar gcTS = new GregorianCalendar();
+ gcTS.setTimeInMillis(timeSlot.getTime());
+
+ gc.set(Calendar.HOUR_OF_DAY, gcTS.get(Calendar.HOUR_OF_DAY));
+ gc.set(Calendar.MINUTE, gcTS.get(Calendar.MINUTE));
+ gc.set(Calendar.SECOND, gcTS.get(Calendar.SECOND));
+ gc.set(Calendar.MILLISECOND, gcTS.get(Calendar.MILLISECOND));
+ }
+ else if(end)
+ {
+ gc.set(Calendar.HOUR_OF_DAY, 23);
+ gc.set(Calendar.MINUTE, 59);
+ gc.set(Calendar.SECOND, 59);
+ gc.set(Calendar.MILLISECOND, 999);
+ }
+ else
+ {
+ gc.set(Calendar.MILLISECOND, 0);
+ gc.set(Calendar.SECOND, 0);
+ gc.set(Calendar.MINUTE, 0);
+ gc.set(Calendar.HOUR_OF_DAY, 0);
+ }
+ return new Timestamp(gc.getTimeInMillis());
+ }
+
+
/**
* Test
* @param args ignored
diff --git a/base/src/org/eevolution/model/MPPMRP.java b/base/src/org/eevolution/model/MPPMRP.java
index c8f4742792..675fad80ed 100644
--- a/base/src/org/eevolution/model/MPPMRP.java
+++ b/base/src/org/eevolution/model/MPPMRP.java
@@ -38,7 +38,6 @@ import org.compiere.model.X_M_ForecastLine;
import org.compiere.process.DocAction;
import org.compiere.util.DB;
import org.compiere.util.Env;
-import org.compiere.util.Util;
import org.compiere.util.TimeUtil;
import org.compiere.wf.MWorkflow;
diff --git a/base/src/org/eevolution/model/MPPOrder.java b/base/src/org/eevolution/model/MPPOrder.java
index 47cceb2436..5be34f2cbb 100644
--- a/base/src/org/eevolution/model/MPPOrder.java
+++ b/base/src/org/eevolution/model/MPPOrder.java
@@ -12,6 +12,7 @@
* For the text or an alternative of this public license, you may reach us *
* Copyright (C) 2003-2007 e-Evolution,SC. All Rights Reserved. *
* Contributor(s): Victor Perez www.e-evolution.com *
+ * Teo Sarca, www.arhipac.ro *
*****************************************************************************/
package org.eevolution.model;
@@ -224,6 +225,14 @@ public class MPPOrder extends X_PP_Order implements DocAction
public void setClientOrg(int AD_Client_ID, int AD_Org_ID) {
super.setClientOrg(AD_Client_ID, AD_Org_ID);
} // setClientOrg
+
+ /**
+ * @return Open Qty
+ */
+ public BigDecimal getQtyOpen()
+ {
+ return getQtyOrdered().subtract(getQtyDelivered()).subtract(getQtyScrap());
+ }
/**************************************************************************
* String Representation
@@ -282,11 +291,13 @@ public class MPPOrder extends X_PP_Order implements DocAction
@Override
protected boolean beforeSave(boolean newRecord)
{
- if (getAD_Client_ID() == 0) {
+ if (getAD_Client_ID() == 0)
+ {
m_processMsg = "AD_Client_ID = 0";
return false;
}
- if (getAD_Org_ID() == 0) {
+ if (getAD_Org_ID() == 0)
+ {
int context_AD_Org_ID = Env.getAD_Org_ID(getCtx());
if (context_AD_Org_ID == 0) {
m_processMsg = "AD_Org_ID = 0";
@@ -295,11 +306,20 @@ public class MPPOrder extends X_PP_Order implements DocAction
setAD_Org_ID(context_AD_Org_ID);
log.warning("beforeSave - Changed Org to Context=" + context_AD_Org_ID);
}
-
- if (getM_Warehouse_ID() == 0) {
+ if (getM_Warehouse_ID() == 0)
+ {
int ii = Env.getContextAsInt(getCtx(), "#M_Warehouse_ID");
- if (ii != 0) setM_Warehouse_ID(ii);
+ if (ii != 0)
+ {
+ setM_Warehouse_ID(ii);
+ }
}
+ // If DateFinishSchedule is not filled, use DatePromised
+ if (getDateFinishSchedule() == null)
+ {
+ setDateFinishSchedule(getDatePromised());
+ }
+
return true;
}
diff --git a/base/src/org/eevolution/model/MPPOrderWorkflow.java b/base/src/org/eevolution/model/MPPOrderWorkflow.java
index 7912373a83..94aa34b7fe 100644
--- a/base/src/org/eevolution/model/MPPOrderWorkflow.java
+++ b/base/src/org/eevolution/model/MPPOrderWorkflow.java
@@ -57,6 +57,14 @@ public class MPPOrderWorkflow extends X_PP_Order_Workflow
s_cache.put(key, retValue);
return retValue;
} // get
+
+ public static MPPOrderWorkflow forPP_Order_ID(Properties ctx, int PP_Order_ID, String trxName)
+ {
+ final String whereClause = MPPOrderWorkflow.COLUMNNAME_PP_Order_ID+"=?";
+ return new Query(ctx, MPPOrderWorkflow.Table_Name, whereClause, trxName)
+ .setParameters(new Object[]{PP_Order_ID})
+ .first();
+ }
/** Single Cache */
private static CCache s_cache = new CCache("PP_Order_Workflow", 20);
@@ -154,9 +162,10 @@ public class MPPOrderWorkflow extends X_PP_Order_Workflow
*/
protected void loadNodes()
{
- final String whereClause = MPPOrderNode.COLUMNNAME_PP_Order_Workflow_ID+"=? AND IsActive=?";
+ final String whereClause = MPPOrderNode.COLUMNNAME_PP_Order_Workflow_ID+"=?";
m_nodes = new Query(getCtx(), MPPOrderNode.Table_Name, whereClause, get_TrxName())
- .setParameters(new Object[]{get_ID(), "Y"})
+ .setParameters(new Object[]{get_ID()})
+ .setOnlyActiveRecords(true)
.list();
log.fine("#" + m_nodes.size());
} // loadNodes
@@ -352,7 +361,9 @@ public class MPPOrderWorkflow extends X_PP_Order_Workflow
{
MPPOrderNodeNext[] nexts = nodes[i].getTransitions(AD_Client_ID);
if (nexts.length > 0)
+ {
return nexts[0].getPP_Order_Next_ID();
+ }
return 0;
}
}
@@ -401,15 +412,16 @@ public class MPPOrderWorkflow extends X_PP_Order_Workflow
/**
* Get very Last Node
- * @param PP_Order_Node_ID ignored
* @param AD_Client_ID for client
* @return next PP_Order_Node_ID or 0
*/
- public int getLast (int PP_Order_Node_ID, int AD_Client_ID)
+ public int getLast (int AD_Client_ID)
{
MPPOrderNode[] nodes = getNodesInOrder(AD_Client_ID);
if (nodes.length > 0)
+ {
return nodes[nodes.length-1].getPP_Order_Node_ID();
+ }
return 0;
} // getLast
diff --git a/base/src/org/eevolution/model/reasoner/CRPReasoner.java b/base/src/org/eevolution/model/reasoner/CRPReasoner.java
index d201ac5e68..2a2d6a4099 100644
--- a/base/src/org/eevolution/model/reasoner/CRPReasoner.java
+++ b/base/src/org/eevolution/model/reasoner/CRPReasoner.java
@@ -12,260 +12,231 @@
* For the text or an alternative of this public license, you may reach us *
* Copyright (C) 2003-2007 e-Evolution,SC. All Rights Reserved. *
* Contributor(s): Victor Perez www.e-evolution.com *
+ * Teo Sarca, www.arhipac.ro *
*****************************************************************************/
package org.eevolution.model.reasoner;
import java.sql.Timestamp;
-import java.text.MessageFormat;
-import java.util.Calendar;
-import java.util.GregorianCalendar;
-import java.util.logging.Level;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
import org.compiere.model.MResource;
import org.compiere.model.MResourceType;
import org.compiere.model.MResourceUnAvailable;
-import org.compiere.model.PO;
-import org.compiere.util.CLogger;
+import org.compiere.model.POResultSet;
+import org.compiere.model.Query;
+import org.compiere.util.DB;
import org.compiere.util.Env;
+import org.compiere.util.TimeUtil;
import org.eevolution.model.MPPOrder;
import org.eevolution.model.MPPOrderNode;
-import org.eevolution.model.MPPOrderWorkflow;
-import org.eevolution.tools.DateTimeUtil;
/**
* @author Gunther Hoppe, tranSIT GmbH Ilmenau/Germany
* @version 1.0, October 14th 2005
+ *
+ * @author Teo Sarca, http://www.arhipac.ro
*/
-public class CRPReasoner {
-
- /**
- * All the below cases expect exactly two parameters: The (1) begin and the (2) end of a day
- */
-
- /**
- * Case 1: The time dependent process has already begun and ends at this day.
- */
- public static final String RESTRICTION_DAY_CASE_1 =
- "(datestartschedule<=''{0}'' AND datefinishschedule>=''{0}'' AND datefinishschedule<=''{1}'')";
-
- /**
- * Case 2: The time dependent process begins and ends at this day.
- */
- public static final String RESTRICTION_DAY_CASE_2 =
- "(datestartschedule>=''{0}'' AND datestartschedule<=''{1}'' AND datefinishschedule>=''{0}'' AND datefinishschedule<=''{1}'')";
-
- /**
- * Case 3: The time dependent process begins at this day and ends few days later.
- */
- public static final String RESTRICTION_DAY_CASE_3 =
- "(datestartschedule>=''{0}'' AND datestartschedule<=''{1}'' AND datefinishschedule>=''{1}'')";
-
- /**
- * Case 4: The time dependent process has already begun and ends few days later.
- */
- public static final String RESTRICTION_DAY_CASE_4 =
- "(datestartschedule<=''{0}'' AND datefinishschedule>=''{1}'')";
-
- private static CLogger log = CLogger.getCLogger (CRPReasoner.class);
-
-
- private String getDayRestriction(Timestamp dateTime, MResource r) {
-
- Object[] params = { getBorderDayMin(dateTime, r).toString(), getBorderDayMax(dateTime, r).toString() };
-
- return
- MessageFormat.format(RESTRICTION_DAY_CASE_1, params)+
- " OR "+MessageFormat.format(RESTRICTION_DAY_CASE_2, params)+
- " OR "+MessageFormat.format(RESTRICTION_DAY_CASE_3, params)+
- " OR "+MessageFormat.format(RESTRICTION_DAY_CASE_4, params);
+public class CRPReasoner
+{
+ public Properties getCtx()
+ {
+ return Env.getCtx();
}
- public MPPOrder[] getPPOrdersNotCompleted(MResource r) {
+ private String getSQLDayRestriction(Timestamp dateTime, MResource r, List