* refactoring
* eliminated recursive method calls
This commit is contained in:
teo_sarca 2008-09-15 13:53:46 +00:00
parent 786f6c1915
commit 377ff791cf
13 changed files with 853 additions and 872 deletions

View File

@ -17,9 +17,14 @@
package org.compiere.model; package org.compiere.model;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Properties; import java.util.Properties;
import org.adempiere.exceptions.AdempiereException;
import org.compiere.util.CCache; 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 * @author Teo Sarca, www.arhipac.ro
* <li>FR [ 2051056 ] MResource[Type] should be cached * <li>FR [ 2051056 ] MResource[Type] should be cached
* <li>added manufacturing related methods (getDayStart, getDayEnd etc)
*/ */
public class MResourceType extends X_S_ResourceType public class MResourceType extends X_S_ResourceType
{ {
@ -78,6 +84,19 @@ public class MResourceType extends X_S_ResourceType
super(ctx, rs, trxName); super(ctx, rs, trxName);
} // MResourceType } // MResourceType
@Override
protected boolean beforeSave(boolean newRecord)
{
if (isTimeSlot())
{
if (getTimeSlotStart().compareTo(getTimeSlotEnd()) >= 0)
{
throw new AdempiereException("@TimeSlotStart@ > @TimeSlotEnd@");
}
}
return true;
}
@Override @Override
protected boolean afterSave (boolean newRecord, boolean success) protected boolean afterSave (boolean newRecord, boolean success)
{ {
@ -102,4 +121,102 @@ public class MResourceType extends X_S_ResourceType
return success; return success;
} // afterSave } // 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 } // MResourceType

View File

@ -16,9 +16,12 @@
*****************************************************************************/ *****************************************************************************/
package org.compiere.model; package org.compiere.model;
import java.sql.*; import java.sql.ResultSet;
import java.util.*; import java.sql.Timestamp;
import org.compiere.util.*; 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 * @author Jorg Janke
* @version $Id: MResourceUnAvailable.java,v 1.2 2006/07/30 00:51:05 jjanke Exp $ * @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 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 * Standard Constructor
* @param ctx context * @param ctx context
@ -50,13 +75,8 @@ public class MResourceUnAvailable extends X_S_ResourceUnAvailable
{ {
super(ctx, rs, trxName); super(ctx, rs, trxName);
} // MResourceUnAvailable } // MResourceUnAvailable
@Override
/**
* Before Save
* @param newRecord new
* @return true
*/
protected boolean beforeSave (boolean newRecord) protected boolean beforeSave (boolean newRecord)
{ {
if (getDateTo() == null) if (getDateTo() == null)
@ -69,4 +89,24 @@ public class MResourceUnAvailable extends X_S_ResourceUnAvailable
return true; return true;
} // beforeSave } // 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 } // MResourceUnAvailable

View File

@ -417,8 +417,14 @@ public class TimeUtil
*/ */
static public Timestamp addDays (Timestamp day, int offset) static public Timestamp addDays (Timestamp day, int offset)
{ {
if (offset == 0)
{
return day;
}
if (day == null) if (day == null)
{
day = new Timestamp(System.currentTimeMillis()); day = new Timestamp(System.currentTimeMillis());
}
// //
GregorianCalendar cal = new GregorianCalendar(); GregorianCalendar cal = new GregorianCalendar();
cal.setTime(day); cal.setTime(day);
@ -655,6 +661,51 @@ public class TimeUtil
return new Timestamp (cal.getTimeInMillis()); return new Timestamp (cal.getTimeInMillis());
} // trunc } // 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 * Test
* @param args ignored * @param args ignored

View File

@ -38,7 +38,6 @@ import org.compiere.model.X_M_ForecastLine;
import org.compiere.process.DocAction; import org.compiere.process.DocAction;
import org.compiere.util.DB; import org.compiere.util.DB;
import org.compiere.util.Env; import org.compiere.util.Env;
import org.compiere.util.Util;
import org.compiere.util.TimeUtil; import org.compiere.util.TimeUtil;
import org.compiere.wf.MWorkflow; import org.compiere.wf.MWorkflow;

View File

@ -12,6 +12,7 @@
* For the text or an alternative of this public license, you may reach us * * For the text or an alternative of this public license, you may reach us *
* Copyright (C) 2003-2007 e-Evolution,SC. All Rights Reserved. * * Copyright (C) 2003-2007 e-Evolution,SC. All Rights Reserved. *
* Contributor(s): Victor Perez www.e-evolution.com * * Contributor(s): Victor Perez www.e-evolution.com *
* Teo Sarca, www.arhipac.ro *
*****************************************************************************/ *****************************************************************************/
package org.eevolution.model; 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) { public void setClientOrg(int AD_Client_ID, int AD_Org_ID) {
super.setClientOrg(AD_Client_ID, AD_Org_ID); super.setClientOrg(AD_Client_ID, AD_Org_ID);
} // setClientOrg } // setClientOrg
/**
* @return Open Qty
*/
public BigDecimal getQtyOpen()
{
return getQtyOrdered().subtract(getQtyDelivered()).subtract(getQtyScrap());
}
/************************************************************************** /**************************************************************************
* String Representation * String Representation
@ -282,11 +291,13 @@ public class MPPOrder extends X_PP_Order implements DocAction
@Override @Override
protected boolean beforeSave(boolean newRecord) protected boolean beforeSave(boolean newRecord)
{ {
if (getAD_Client_ID() == 0) { if (getAD_Client_ID() == 0)
{
m_processMsg = "AD_Client_ID = 0"; m_processMsg = "AD_Client_ID = 0";
return false; return false;
} }
if (getAD_Org_ID() == 0) { if (getAD_Org_ID() == 0)
{
int context_AD_Org_ID = Env.getAD_Org_ID(getCtx()); int context_AD_Org_ID = Env.getAD_Org_ID(getCtx());
if (context_AD_Org_ID == 0) { if (context_AD_Org_ID == 0) {
m_processMsg = "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); setAD_Org_ID(context_AD_Org_ID);
log.warning("beforeSave - Changed Org to Context=" + 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"); 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; return true;
} }

View File

@ -57,6 +57,14 @@ public class MPPOrderWorkflow extends X_PP_Order_Workflow
s_cache.put(key, retValue); s_cache.put(key, retValue);
return retValue; return retValue;
} // get } // 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 */ /** Single Cache */
private static CCache<Integer,MPPOrderWorkflow> s_cache = new CCache<Integer,MPPOrderWorkflow>("PP_Order_Workflow", 20); private static CCache<Integer,MPPOrderWorkflow> s_cache = new CCache<Integer,MPPOrderWorkflow>("PP_Order_Workflow", 20);
@ -154,9 +162,10 @@ public class MPPOrderWorkflow extends X_PP_Order_Workflow
*/ */
protected void loadNodes() 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()) 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(); .list();
log.fine("#" + m_nodes.size()); log.fine("#" + m_nodes.size());
} // loadNodes } // loadNodes
@ -352,7 +361,9 @@ public class MPPOrderWorkflow extends X_PP_Order_Workflow
{ {
MPPOrderNodeNext[] nexts = nodes[i].getTransitions(AD_Client_ID); MPPOrderNodeNext[] nexts = nodes[i].getTransitions(AD_Client_ID);
if (nexts.length > 0) if (nexts.length > 0)
{
return nexts[0].getPP_Order_Next_ID(); return nexts[0].getPP_Order_Next_ID();
}
return 0; return 0;
} }
} }
@ -401,15 +412,16 @@ public class MPPOrderWorkflow extends X_PP_Order_Workflow
/** /**
* Get very Last Node * Get very Last Node
* @param PP_Order_Node_ID ignored
* @param AD_Client_ID for client * @param AD_Client_ID for client
* @return next PP_Order_Node_ID or 0 * @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); MPPOrderNode[] nodes = getNodesInOrder(AD_Client_ID);
if (nodes.length > 0) if (nodes.length > 0)
{
return nodes[nodes.length-1].getPP_Order_Node_ID(); return nodes[nodes.length-1].getPP_Order_Node_ID();
}
return 0; return 0;
} // getLast } // getLast

View File

@ -12,260 +12,231 @@
* For the text or an alternative of this public license, you may reach us * * For the text or an alternative of this public license, you may reach us *
* Copyright (C) 2003-2007 e-Evolution,SC. All Rights Reserved. * * Copyright (C) 2003-2007 e-Evolution,SC. All Rights Reserved. *
* Contributor(s): Victor Perez www.e-evolution.com * * Contributor(s): Victor Perez www.e-evolution.com *
* Teo Sarca, www.arhipac.ro *
*****************************************************************************/ *****************************************************************************/
package org.eevolution.model.reasoner; package org.eevolution.model.reasoner;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.text.MessageFormat; import java.util.ArrayList;
import java.util.Calendar; import java.util.List;
import java.util.GregorianCalendar; import java.util.Properties;
import java.util.logging.Level;
import org.compiere.model.MResource; import org.compiere.model.MResource;
import org.compiere.model.MResourceType; import org.compiere.model.MResourceType;
import org.compiere.model.MResourceUnAvailable; import org.compiere.model.MResourceUnAvailable;
import org.compiere.model.PO; import org.compiere.model.POResultSet;
import org.compiere.util.CLogger; import org.compiere.model.Query;
import org.compiere.util.DB;
import org.compiere.util.Env; import org.compiere.util.Env;
import org.compiere.util.TimeUtil;
import org.eevolution.model.MPPOrder; import org.eevolution.model.MPPOrder;
import org.eevolution.model.MPPOrderNode; import org.eevolution.model.MPPOrderNode;
import org.eevolution.model.MPPOrderWorkflow;
import org.eevolution.tools.DateTimeUtil;
/** /**
* @author Gunther Hoppe, tranSIT GmbH Ilmenau/Germany * @author Gunther Hoppe, tranSIT GmbH Ilmenau/Germany
* @version 1.0, October 14th 2005 * @version 1.0, October 14th 2005
*
* @author Teo Sarca, http://www.arhipac.ro
*/ */
public class CRPReasoner { public class CRPReasoner
{
/** public Properties getCtx()
* All the below cases expect exactly two parameters: The (1) begin and the (2) end of a day {
*/ return Env.getCtx();
/**
* 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 MPPOrder[] getPPOrdersNotCompleted(MResource r) { private String getSQLDayRestriction(Timestamp dateTime, MResource r, List<Object> params)
{
Timestamp dayStart = r.getResourceType().getDayStart(dateTime);
Timestamp dayEnd = r.getResourceType().getDayEnd(dateTime);
String whereClause;
//
// Case 1: The time dependent process has already begun and ends at this day.
whereClause = "(DateStartSchedule<=? AND DateFinishSchedule>=? AND DateFinishSchedule<=?)";
params.add(dayStart);
params.add(dayStart);
params.add(dayEnd);
//
// Case 2: The time dependent process begins and ends at this day.
whereClause += " OR (DateStartSchedule>=? AND DateStartSchedule<=?"
+" AND DateFinishSchedule>=? AND DateFinishSchedule<=?)";
params.add(dayStart);
params.add(dayEnd);
params.add(dayStart);
params.add(dayEnd);
//String sql = "SELECT owf.PP_Order_Workflow_ID , o.DateStartSchedule , o.DateFinishSchedule ,o.QtyOrdered - o.QtyDelivered - o.QtyScrap AS QtyOpen FROM PP_Order o INNER JOIN PP_Order_Workflow owf ON (owf.PP_ORDER_ID = o.PP_Order_ID) WHERE o.DocStatus <> 'CL' AND o.AD_Client_ID = ? AND o.S_Resource_ID= ? ORDER BY DatePromised" ; //
String where = // Case 3: The time dependent process begins at this day and ends few days later.
// Checks the requested resource id directly on order node, not on resource id of the order whereClause += " OR (DateStartSchedule>=? AND DateStartSchedule<=? AND DateFinishSchedule>=?)";
//"PP_Order_ID IN (SELECT PP_Order_ID FROM PP_Order_Node on WHERE on.S_Resource_ID="+r.getID()+")" params.add(dayStart);
"S_Resource_ID="+r.get_ID() +" AND DocStatus <> 'CL' AND AD_Client_ID = " + r.getAD_Client_ID() ; //+ " AND PP_Order_ID = 1000031" ; params.add(dayEnd);
// ... and completed orders needn't to be observed params.add(dayEnd);
int[] orderIds = PO.getAllIDs("PP_Order", where, null); //
MPPOrder[] orders = new MPPOrder[orderIds.length]; // Case 4: The time dependent process has already begun and ends few days later.
for(int i = 0; i < orderIds.length; i++) { whereClause += " OR (DateStartSchedule<=? AND DateFinishSchedule>=?)";
params.add(dayStart);
params.add(dayEnd);
orders[i] = new MPPOrder(Env.getCtx(), orderIds[i], null); return "("+whereClause+")";
}
public Query getPPOrdersNotCompletedQuery(int S_Resource_ID, String trxName)
{
ArrayList<Object> params = new ArrayList<Object>();
StringBuffer whereClause = new StringBuffer();
// For current AD_Client_ID (security)
whereClause.append("AD_Client_ID=?");
params.add(Env.getAD_Client_ID(getCtx()));
// Skip voided, reversed and closed orders:
whereClause.append(" AND ").append(MPPOrder.COLUMNNAME_DocStatus).append(" NOT IN ('VO', 'RE', 'CL')");
// For given resource (if any)
if (S_Resource_ID > 0)
{
whereClause.append(" AND ").append(MPPOrder.COLUMNNAME_S_Resource_ID).append("=?");
params.add(S_Resource_ID);
} }
return orders; return new Query(getCtx(), MPPOrder.Table_Name, whereClause.toString(), trxName)
.setParameters(params)
.setOnlyActiveRecords(true)
.setOrderBy(MPPOrder.COLUMNNAME_DatePromised);
} }
public Timestamp getBorderDayMin(Timestamp dateTime, MResource r) { public MPPOrder[] getPPOrders(Timestamp dateTime, MResource r)
{
MResourceType t = MResourceType.get(Env.getCtx(), r.getS_ResourceType_ID()); if(!isAvailable(r, dateTime))
return (t.isTimeSlot()) ? {
DateTimeUtil.getDayBorder(dateTime, t.getTimeSlotStart(), false) :
DateTimeUtil.getDayBorder(dateTime, null, false);
}
public Timestamp getBorderDayMax(Timestamp dateTime, MResource r) {
MResourceType t = MResourceType.get(Env.getCtx(), r.getS_ResourceType_ID());
return (t.isTimeSlot()) ?
DateTimeUtil.getDayBorder(dateTime, t.getTimeSlotEnd(), true) :
DateTimeUtil.getDayBorder(dateTime, null, true);
}
public boolean isResourceAvailable(Timestamp dateTime, MResource r) {
MResourceType t = MResourceType.get(Env.getCtx(), r.getS_ResourceType_ID());
return ( checkResourceAvailability(dateTime, r) && checkResourceTypeAvailability(dateTime, t) );
}
public MPPOrder[] getPPOrders(Timestamp dateTime, MResource r) {
if(!isResourceAvailable(dateTime, r)) {
return new MPPOrder[0]; return new MPPOrder[0];
} }
String where = ArrayList<Object> params = new ArrayList<Object>();
params.add(r.get_ID());
final String whereClause =
// Checks the requested resource id directly on order node, not on resource id of the order // Checks the requested resource id directly on order node, not on resource id of the order
"PP_order_id in (select PP_order_id from PP_order_node where s_resource_id="+r.get_ID() "PP_Order_ID IN (SELECT PP_Order_ID FROM PP_Order_Node WHERE S_Resource_ID=?"
// ... and only the orders running on given day // ... and only the orders running on given day
+" AND ("+getDayRestriction(dateTime, r)+") ) AND AD_Client_ID =" + r.getAD_Client_ID(); +" AND "+getSQLDayRestriction(dateTime, r, params)
+")"
int[] orderIds = PO.getAllIDs("PP_Order", where, null); + " AND AD_Client_ID=?";
MPPOrder[] orders = new MPPOrder[orderIds.length]; params.add(r.getAD_Client_ID());
for(int i = 0; i < orderIds.length; i++) {
List<MPPOrder> list = new Query(r.getCtx(), MPPOrder.Table_Name, whereClause, null)
orders[i] = new MPPOrder(Env.getCtx(), orderIds[i], null); .setParameters(params)
} .list();
return list.toArray(new MPPOrder[list.size()]);
return orders;
} }
public MPPOrderNode[] getPPOrderNodes(Timestamp dateTime, MResource r) { public MPPOrderNode[] getPPOrderNodes(Timestamp dateTime, MResource r)
{
if(!isResourceAvailable(dateTime, r)) { if(!isAvailable(r, dateTime))
{
return new MPPOrderNode[0]; return new MPPOrderNode[0];
} }
String where = ArrayList<Object> params = new ArrayList<Object>();
"s_resource_id = "+r.get_ID() String whereClause = MPPOrderNode.COLUMNNAME_S_Resource_ID+"=? AND AD_Client_ID=?";
+" AND ("+getDayRestriction(dateTime, r)+") AND AD_Client_ID = " + r.getAD_Client_ID(); params.add(r.get_ID());
log.log(Level.FINE,"getPPOrderNodes --> Where:" + where); params.add(r.getAD_Client_ID());
int[] ids = PO.getAllIDs("PP_Order_Node", where, null);
whereClause += " AND "+getSQLDayRestriction(dateTime, r, params);
MPPOrderNode[] nodes = new MPPOrderNode[ids.length];
for(int i = 0; i < ids.length; i++) { List<MPPOrderNode> list = new Query(r.getCtx(), MPPOrderNode.Table_Name, whereClause, null)
.setParameters(params)
nodes[i] = new MPPOrderNode(Env.getCtx(), ids[i], null); .list();
} return list.toArray(new MPPOrderNode[list.size()]);
return nodes;
} }
public MPPOrderWorkflow getPPOrderWorkflow(MPPOrder o) { public boolean isAvailable(MResource r, Timestamp dateTime)
{
int[] ids = PO.getAllIDs("PP_Order_Workflow", "PP_Order_ID = "+o.get_ID() + " AND AD_Client_ID = " + o.getAD_Client_ID(), null); MResourceType t = MResourceType.get(Env.getCtx(), r.getS_ResourceType_ID());
return t.isDayAvailable(dateTime) && !MResourceUnAvailable.isUnAvailable(r, dateTime);
return (ids.length != 1) ? null : new MPPOrderWorkflow(Env.getCtx(), ids[0], null);
} }
public boolean checkResourceTypeAvailability(MResourceType t) { public boolean isAvailable(MResource r)
{
if(!t.isDateSlot()) { return r.getResourceType().isAvailable();
return true;
}
Timestamp dateTime = new Timestamp(System.currentTimeMillis());
for(int i = 0; i < 7; i++) {
if(checkResourceTypeAvailability(dateTime, t)) {
return true;
}
//dateTime = DateTimeUtil.incrementDay(dateTime);
dateTime = org.compiere.util.TimeUtil.addDays(dateTime, 1);
}
return false;
} }
public boolean checkResourceAvailability(Timestamp dateTime, MResource r) { private Timestamp getAvailableDate(MResourceType t, Timestamp dateTime, boolean isScheduleBackward)
{
int[] ids = PO.getAllIDs("S_ResourceUnAvailable", "S_Resource_ID = "+r.get_ID() + " AND AD_Client_ID = " + r.getAD_Client_ID(), null); Timestamp date = TimeUtil.trunc(dateTime, TimeUtil.TRUNC_DAY);
int direction = isScheduleBackward ? -1 : +1;
Timestamp dateFrom = null; for (int i = 0; i <= 7; i++)
Timestamp dateTo = null; {
Timestamp dateActual = null; date = TimeUtil.addDays(date, i * direction);
if (t.isDayAvailable(date))
MResourceUnAvailable rua = null; {
for(int i = 0; i < ids.length; i++) { break;
rua = new MResourceUnAvailable(Env.getCtx(), ids[i], null);
dateFrom = DateTimeUtil.getDayBorder(rua.getDateFrom(), null, false);
dateTo = DateTimeUtil.getDayBorder(rua.getDateTo(), null, true);
dateActual = DateTimeUtil.getDayBorder(dateTime, null, false);
if(dateFrom.compareTo(dateActual) <= 0 && dateTo.compareTo(dateActual) >= 0 ) {
return false;
} }
} }
return date;
return true;
} }
public boolean checkResourceTypeAvailability(Timestamp dateTime, MResourceType t) { /**
* @param r resource
if(!t.isDateSlot()) { * @param dateTime
* @return next available date
return true; */
public Timestamp getAvailableDate(MResource r, Timestamp dateTime, boolean isScheduleBackward)
{
MResourceType t = r.getResourceType();
Timestamp date = TimeUtil.trunc(dateTime, TimeUtil.TRUNC_DAY);
ArrayList<Object> params = new ArrayList<Object>();
String whereClause;
String orderByClause;
int direction;
if (isScheduleBackward)
{
whereClause = "TRUNC("+MResourceUnAvailable.COLUMNNAME_DateFrom+") < ?";
params.add(date);
orderByClause = MResourceUnAvailable.COLUMNNAME_DateFrom+" DESC";
direction = 1;
}
else
{
whereClause = "TRUNC("+MResourceUnAvailable.COLUMNNAME_DateTo+") > ?";
params.add(date);
orderByClause = MResourceUnAvailable.COLUMNNAME_DateTo;
direction = -1;
} }
GregorianCalendar gc = new GregorianCalendar(); whereClause += " AND "+MResourceUnAvailable.COLUMNNAME_S_Resource_ID+"=? AND AD_Client_ID=?";
gc.setTimeInMillis(dateTime.getTime()); params.add(r.get_ID());
params.add(r.getAD_Client_ID());
boolean retValue = false;
switch(gc.get(Calendar.DAY_OF_WEEK)) { POResultSet<MResourceUnAvailable> rs = new Query(r.getCtx(), MResourceUnAvailable.Table_Name, whereClause, null)
.setOrderBy(orderByClause)
case Calendar.SUNDAY: .setParameters(params)
retValue = t.isOnSunday(); .scroll();
break; try
{
case Calendar.MONDAY: while(rs.hasNext())
retValue = t.isOnMonday(); {
break; MResourceUnAvailable rua = rs.next();
if (rua.isUnAvailable(date))
case Calendar.TUESDAY: {
retValue = t.isOnTuesday(); date = TimeUtil.addDays(rua.getDateTo(), 1 * direction);
break; }
date = getAvailableDate(t, dateTime, isScheduleBackward);
case Calendar.WEDNESDAY: }
retValue = t.isOnWednesday(); }
break; finally
{
case Calendar.THURSDAY: DB.close(rs);
retValue = t.isOnThursday(); }
break; //
date = getAvailableDate(t, dateTime, isScheduleBackward);
case Calendar.FRIDAY: return date;
retValue = t.isOnFriday();
break;
case Calendar.SATURDAY:
retValue = t.isOnSaturday();
break;
}
return retValue;
} }
} }

View File

@ -12,33 +12,35 @@
* For the text or an alternative of this public license, you may reach us * * For the text or an alternative of this public license, you may reach us *
* Copyright (C) 2003-2007 e-Evolution,SC. All Rights Reserved. * * Copyright (C) 2003-2007 e-Evolution,SC. All Rights Reserved. *
* Contributor(s): Victor Perez www.e-evolution.com * * Contributor(s): Victor Perez www.e-evolution.com *
* Teo Sarca, www.arhipac.ro *
*****************************************************************************/ *****************************************************************************/
package org.eevolution.process; package org.eevolution.process;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.logging.Level;
import org.adempiere.exceptions.AdempiereException;
import org.compiere.model.MResource;
import org.compiere.model.MResourceType;
import org.compiere.model.POResultSet;
import org.compiere.process.ProcessInfoParameter; import org.compiere.process.ProcessInfoParameter;
import org.compiere.process.SvrProcess; import org.compiere.process.SvrProcess;
import org.compiere.util.Env; import org.compiere.util.DB;
import org.compiere.util.Msg; import org.compiere.util.TimeUtil;
import org.eevolution.model.MPPOrder; import org.eevolution.model.MPPOrder;
import org.eevolution.model.MPPOrderNode; import org.eevolution.model.MPPOrderNode;
import org.eevolution.model.MPPOrderWorkflow; import org.eevolution.model.MPPOrderWorkflow;
import org.compiere.model.*;
import org.eevolution.model.reasoner.CRPReasoner; import org.eevolution.model.reasoner.CRPReasoner;
import org.eevolution.tools.DateTimeUtil;
import java.math.BigDecimal;
import java.util.logging.*;
import java.sql.Timestamp;
/** /**
* Capacity Requirement Planning * Capacity Requirement Planning
* *
* @author Gunther Hoppe, tranSIT GmbH Ilmenau/Germany (Original by Victor Perez, e-Evolution, S.C.) * @author Gunther Hoppe, tranSIT GmbH Ilmenau/Germany (Original by Victor Perez, e-Evolution, S.C.)
* @version 1.0, October 14th 2005 * @version 1.0, October 14th 2005
*
* @author Teo Sarca, www.arhipac.ro
*/ */
public class CRP extends SvrProcess { public class CRP extends SvrProcess {
@ -55,35 +57,22 @@ public class CRP extends SvrProcess {
reasoner = new CRPReasoner(); reasoner = new CRPReasoner();
} }
protected void prepare() { protected void prepare()
{
ProcessInfoParameter[] para = getParameter(); ProcessInfoParameter[] para = getParameter();
for (int i = 0; i < para.length; i++)
if(para == null) { {
return;
}
for (int i = 0; i < para.length; i++) {
if(para[i] == null) {
continue;
}
String name = para[i].getParameterName(); String name = para[i].getParameterName();
if (para[i].getParameter() == null)
;
if (name.equals("S_Resource_ID")) { if (name.equals("S_Resource_ID")) {
p_S_Resource_ID = ((BigDecimal)para[i].getParameter()).intValue(); p_S_Resource_ID = ((BigDecimal)para[i].getParameter()).intValue();
} }
else if (name.equals("ScheduleType")) { else if (name.equals("ScheduleType")) {
p_ScheduleType = ((String)para[i].getParameter()); p_ScheduleType = ((String)para[i].getParameter());
} }
else { else {
log.log(Level.SEVERE, "prepare - Unknown Parameter: " + name);
log.log(Level.SEVERE,"prepare - Unknown Parameter: " + name);
} }
} }
} }
@ -93,299 +82,221 @@ public class CRP extends SvrProcess {
return runCRP(); return runCRP();
} }
private String runCRP() { private String runCRP()
{
MPPOrderWorkflow owf = null; POResultSet<MPPOrder> rs = reasoner.getPPOrdersNotCompletedQuery(p_S_Resource_ID, get_TrxName())
MPPOrderNode node = null; .scroll();
MResource resource = null; try
MResourceType resourceType = null; {
while(rs.hasNext())
BigDecimal qtyOpen = null; {
runCRP(rs.next());
Timestamp date = null;
Timestamp dateStart = null;
Timestamp dateFinish = null;
long nodeMillis = 0;
int nodeId = -1;
resource = MResource.get(getCtx(), p_S_Resource_ID);
MPPOrder[] orders = reasoner.getPPOrdersNotCompleted(resource);
log.log(Level.INFO,"MPP_Order[] : " + orders.length);
for(int i = 0; i < orders.length; i++) {
qtyOpen = orders[i].getQtyOrdered().subtract(orders[i].getQtyDelivered()).subtract(orders[i].getQtyScrap());
owf = reasoner.getPPOrderWorkflow(orders[i]);
if(owf == null) {
return Msg.translate(Env.getCtx(), "Error");
} }
}
// Schedule Fordward finally
if (p_ScheduleType.equals(FORWARD_SCHEDULING)) { {
log.log(Level.FINE,"MPP_Order DocumentNo:" + orders[i].getDocumentNo()); DB.close(rs);
log.log(Level.FINE,"MPP_Order Workflow:" + owf.getName()); rs = null;
date = orders[i].getDateStartSchedule();
nodeId = owf.getPP_Order_Node_ID();
while(nodeId != 0) {
node = new MPPOrderNode(getCtx(),nodeId , get_TrxName());
log.log(Level.FINE,"MPP_Order Node:" + node.getName() + " Description:" + node.getDescription());
resource = MResource.get(getCtx(), node.getS_Resource_ID());
resourceType = MResourceType.get(getCtx(), resource.getS_ResourceType_ID());
// Checks, whether the resource type is principal available on one day a week.
// If not, process breaks with a Info message about.
if(!reasoner.checkResourceTypeAvailability(resourceType)) {
return Msg.getMsg(Env.getCtx(), "ResourceNotInSlotDay");
}
nodeMillis = calculateMillisFor(node, resourceType, qtyOpen, owf.getDurationBaseSec());
dateFinish = scheduleForward(date, nodeMillis ,resource, resourceType);
node.setDateStartSchedule(date);
node.setDateFinishSchedule(dateFinish);
node.save(get_TrxName());
date = node.getDateFinishSchedule();
nodeId = owf.getNext(nodeId,getAD_Client_ID());
if (nodeId == 0)
log.log(Level.FINE,"---------------MPP_Order Node Next not exist:" );
}
if (node!=null)
orders[i].setDateFinishSchedule(node.getDateFinishSchedule());
}
// Schedule backward
else if (p_ScheduleType.equals(BACKWARD_SCHEDULING)) {
log.log(Level.FINE,"MPP_Order DocumentNo:" + orders[i].getDocumentNo());
log.log(Level.FINE,"MPP_Order Workflow:" + owf.getName());
date = orders[i].getDateFinishSchedule();
nodeId = owf.getLast(0, getAD_Client_ID());
while(nodeId != 0) {
node = new MPPOrderNode(getCtx(),nodeId , get_TrxName());
log.log(Level.FINE,"MPP_Order Node:" + node.getName() + " Description:" + node.getDescription());
resource = MResource.get(getCtx(), node.getS_Resource_ID());
resourceType = MResourceType.get(getCtx(), resource.getS_ResourceType_ID());
// Checks, whether the resource type is principal available on one day a week.
// If not, process breaks with a Info message about.
if(!reasoner.checkResourceTypeAvailability(resourceType)) {
return Msg.getMsg(Env.getCtx(), "ResourceNotInSlotDay");
}
nodeMillis = calculateMillisFor(node, resourceType, qtyOpen, owf.getDurationBaseSec());
dateStart = scheduleBackward(date, nodeMillis ,resource, resourceType);
node.setDateStartSchedule(dateStart);
node.setDateFinishSchedule(date);
node.save(get_TrxName());
date = node.getDateStartSchedule();
nodeId = owf.getPrevious(nodeId,getAD_Client_ID());
if (nodeId == 0)
log.log(Level.FINE,"MPP_Order Node Previos not exist:" );
}
if (node != null)
orders[i].setDateStartSchedule(node.getDateStartSchedule()) ;
}
orders[i].save(get_TrxName());
} }
return "OK"; return "OK";
} }
private void runCRP(MPPOrder order)
{
log.fine("PP_Order DocumentNo:" + order.getDocumentNo());
BigDecimal qtyOpen = order.getQtyOpen();
private long calculateMillisFor(MPPOrderNode node, MResourceType type, BigDecimal qty, long commonBase) { MPPOrderWorkflow owf = MPPOrderWorkflow.forPP_Order_ID(order.getCtx(), order.getPP_Order_ID(), order.get_TrxName());
log.fine("PP_Order Workflow:" + owf.getName());
// A day of 24 hours in milliseconds // Schedule Fordward
double aDay24 = 24*60*60*1000; if (p_ScheduleType.equals(FORWARD_SCHEDULING))
{
Timestamp date = order.getDateStartSchedule();
int nodeId = owf.getPP_Order_Node_ID();
MPPOrderNode node = null;
// Initializing available time as complete day in milliseconds. while(nodeId != 0)
double actualDay = aDay24; {
node = owf.getNode(nodeId);
log.fine("PP_Order Node:" + node.getName() + " Description:" + node.getDescription());
MResource resource = MResource.get(getCtx(), node.getS_Resource_ID());
MResourceType resourceType = resource.getResourceType();
// If resource type is timeslot, updating to available time of the resource. if(!reasoner.isAvailable(resource))
if (type.isTimeSlot()) { {
throw new AdempiereException("@ResourceNotInSlotDay@");
}
actualDay = (double)DateTimeUtil.getTimeDifference(type.getTimeSlotStart(), type.getTimeSlotEnd()); long nodeMillis = calculateMillisFor(node, resourceType, qtyOpen, owf.getDurationBaseSec());
Timestamp dateFinish = scheduleForward(date, nodeMillis ,resource, resourceType);
node.setDateStartSchedule(date);
node.setDateFinishSchedule(dateFinish);
node.saveEx(get_TrxName());
date = node.getDateFinishSchedule();
nodeId = owf.getNext(nodeId, getAD_Client_ID());
}
if (node != null)
{
order.setDateFinishSchedule(node.getDateFinishSchedule());
}
}
// Schedule backward
else if (p_ScheduleType.equals(BACKWARD_SCHEDULING))
{
Timestamp date = order.getDateFinishSchedule();
int nodeId = owf.getLast(getAD_Client_ID());
MPPOrderNode node = null;
while(nodeId != 0)
{
node = owf.getNode(nodeId);
log.fine("PP_Order Node:" + node.getName() + " Description:" + node.getDescription());
MResource resource = MResource.get(getCtx(), node.getS_Resource_ID());
MResourceType resourceType = resource.getResourceType();
if(!reasoner.isAvailable(resource))
{
throw new AdempiereException("@ResourceNotInSlotDay@");
}
long nodeMillis = calculateMillisFor(node, resourceType, qtyOpen, owf.getDurationBaseSec());
Timestamp dateStart = scheduleBackward(date, nodeMillis ,resource, resourceType);
node.setDateStartSchedule(dateStart);
node.setDateFinishSchedule(date);
node.saveEx();
date = node.getDateStartSchedule();
nodeId = owf.getPrevious(nodeId, getAD_Client_ID());
}
if (node != null)
{
order.setDateStartSchedule(node.getDateStartSchedule()) ;
}
}
else
{
throw new AdempiereException("@Unknown scheduling method - "+p_ScheduleType);
} }
// Available time factor of the resource of the workflow node order.saveEx(get_TrxName());
BigDecimal factorAvailablility = new BigDecimal((actualDay / aDay24)); }
private long calculateMillisFor(MPPOrderNode node, MResourceType type, BigDecimal qty, long commonBase)
{
// // Available time factor of the resource of the workflow node
// double actualDay = type.getDayDurationMillis();
// final double aDay24 = 24*60*60*1000; // A day of 24 hours in milliseconds
// BigDecimal factorAvailablility = new BigDecimal((actualDay / aDay24));
// Total duration of workflow node (seconds) ... // Total duration of workflow node (seconds) ...
// ... its static single parts ... // ... its static single parts ...
BigDecimal totalDuration = new BigDecimal( long totalDuration =
//node.getQueuingTime() //node.getQueuingTime()
node.getSetupTimeRequiered() // Use the present required setup time to notice later changes node.getSetupTimeRequiered() // Use the present required setup time to notice later changes
+ node.getMovingTime() + node.getMovingTime()
+ node.getWaitingTime() + node.getWaitingTime()
); ;
// ... and its qty dependend working time ... (Use the present required duration time to notice later changes) // ... and its qty dependend working time ... (Use the present required duration time to notice later changes)
//totalDuration = totalDuration.add(qty.multiply(new BigDecimal(node.getDurationRequiered()))); //totalDuration = totalDuration.add(qty.multiply(new BigDecimal(node.getDurationRequiered())));
totalDuration = totalDuration.add(qty.multiply(new BigDecimal(node.getDuration()))); totalDuration += qty.doubleValue() * node.getDuration();
// ... converted to common base.
totalDuration = totalDuration.multiply(new BigDecimal(commonBase));
// Returns the total duration of a node in milliseconds. // Returns the total duration of a node in milliseconds.
return totalDuration.multiply(new BigDecimal(1000)).longValue(); return (long)(totalDuration * commonBase * 1000);
} }
private Timestamp scheduleForward(Timestamp start, long nodeDuration, MResource r, MResourceType t) { private Timestamp scheduleForward(Timestamp start, long nodeDuration, MResource r, MResourceType t)
{
// Checks, whether the resource is available at this day and recall with Timestamp end = null;
// next day, if not. int iteration = 0; // statistical interation count
if(!reasoner.checkResourceAvailability(start, r)) { do
{
//return scheduleForward(Util.incrementDay(start), nodeDuration, r, t); start = reasoner.getAvailableDate(r, start, false);
return scheduleForward(org.compiere.util.TimeUtil.addDays(start, 1) , nodeDuration, r, t); Timestamp dayStart = t.getDayStart(start);
Timestamp dayEnd = t.getDayEnd(start);
} // If working has already began at this day and the value is in the range of the
// Checks, whether the resource type (only if date slot) is available at // resource's availability, switch start time to the given again
// this day and recall with next day, if not. if(start.after(dayStart) && start.before(dayEnd))
else if(t.isDateSlot()) { {
dayStart = start;
if(!reasoner.checkResourceTypeAvailability(start, t)) {
//return scheduleForward(DateTimeUtil.incrementDay(start), nodeDuration, r, t);
return scheduleForward(org.compiere.util.TimeUtil.addDays(start, 1), nodeDuration, r, t);
} }
}
// The available time at this day in milliseconds
long availableDayDuration = dayEnd.getTime() - dayStart.getTime();
// The work can be finish on this day.
if(availableDayDuration >= nodeDuration)
{
end = new Timestamp(dayStart.getTime() + nodeDuration);
nodeDuration = 0;
break;
}
// Otherwise recall with next day and the remained node duration.
else
{
start = TimeUtil.addDays(TimeUtil.getDayBorder(start, null, false), 1);
nodeDuration -= availableDayDuration;
}
iteration++;
} while (nodeDuration > 0);
Timestamp dayStart = null; return end;
// Retrieve the principal days start time, dependent on timeslot or not
if(t.isTimeSlot()) {
dayStart = DateTimeUtil.getDayBorder(start, t.getTimeSlotStart(), false);
}
else {
dayStart = DateTimeUtil.getDayBorder(start, null, false);
}
Timestamp dayEnd = null;
// Retrieve the days end time, dependent on timeslot or not
if(t.isTimeSlot()) {
dayEnd = DateTimeUtil.getDayBorder(start, t.getTimeSlotEnd(), true);
}
else {
dayEnd = DateTimeUtil.getDayBorder(start, null, true);
}
// If working has already begon at this day and the value is in the range of the
// resource's availability, switch start time to the given again
if(start.after(dayStart) && start.before(dayEnd)) {
dayStart = start;
}
// The available time at this day in milliseconds
long availableDayDuration = DateTimeUtil.getTimeDifference(dayStart, dayEnd);
Timestamp retValue = null;
// The work can be finish on this day.
if(availableDayDuration >= nodeDuration) {
retValue = new Timestamp(dayStart.getTime()+nodeDuration);
}
// Otherwise recall with next day and the remained node duration.
else {
//retValue = scheduleForward(DateTimeUtil.incrementDay(DateTimeUtil.getDayBorder(start, null, false)), nodeDuration-availableDayDuration, r, t);
retValue = scheduleForward(org.compiere.util.TimeUtil.addDays(DateTimeUtil.getDayBorder(start, null, false),1), nodeDuration-availableDayDuration, r, t);
}
return retValue;
} }
private Timestamp scheduleBackward(Timestamp end, long nodeDuration, MResource r, MResourceType t) { private Timestamp scheduleBackward(Timestamp end, long nodeDuration, MResource r, MResourceType t)
{
log.log(Level.FINE,"scheduleBackward --> end " +end); log.fine("--> ResourceType " + t);
log.log(Level.FINE,"scheduleBackward --> nodeDuration " +nodeDuration); Timestamp start = null;
log.log(Level.FINE,"scheduleBackward --> ResourceType " + t); int iteration = 0; // statistical interation count
do
// Checks, whether the resource is available at this day and recall with {
// next day, if not. log.fine("--> end " +end);
if(!reasoner.checkResourceAvailability(end, r)) { log.fine("--> nodeDuration=" +nodeDuration);
//return scheduleBackward(DateTimeUtil.decrementDay(end), nodeDuration, r, t); end = reasoner.getAvailableDate(r, end, true);
return scheduleBackward(org.compiere.util.TimeUtil.addDays(end , -1), nodeDuration, r, t); Timestamp dayEnd = t.getDayEnd(end);
Timestamp dayStart = t.getDayStart(end);
} log.fine("--> dayEnd=" + dayEnd + ", dayStart=" + dayStart);
// If working has already began at this day and the value is in the range of the
// Checks, whether the resource type (only if date slot) is available on // resource's availability, switch end time to the given again
// this day and recall with next day, if not. if(end.before(dayEnd) && end.after(dayStart))
if(t.isDateSlot()) { {
dayEnd = end;
if(!reasoner.checkResourceTypeAvailability(end, t)) {
//return scheduleBackward(DateTimeUtil.decrementDay(end), nodeDuration, r, t);
return scheduleBackward(org.compiere.util.TimeUtil.addDays(end , -1), nodeDuration, r, t);
} }
// The available time at this day in milliseconds
long availableDayDuration = dayEnd.getTime() - dayStart.getTime();
log.fine("--> availableDayDuration " + availableDayDuration);
// The work can be finish on this day.
if(availableDayDuration >= nodeDuration)
{
log.fine("--> availableDayDuration >= nodeDuration true " + availableDayDuration + "|" + nodeDuration );
start = new Timestamp(dayEnd.getTime() - nodeDuration);
nodeDuration = 0;
break;
}
// Otherwise recall with previous day and the remained node duration.
else
{
log.fine("--> availableDayDuration >= nodeDuration false " + availableDayDuration + "|" + nodeDuration );
log.fine("--> nodeDuration-availableDayDuration " + (nodeDuration-availableDayDuration) );
end = TimeUtil.addDays(TimeUtil.getDayBorder(end, null, true), -1);
nodeDuration -= availableDayDuration;
}
//
iteration++;
} }
while(nodeDuration > 0);
Timestamp dayEnd = null;
// Retrieve the principal days end time, dependent on timeslot or not log.fine(" --> start=" + start + " <---------------------------------------- ");
if(t.isTimeSlot()) { return start;
dayEnd = DateTimeUtil.getDayBorder(end, t.getTimeSlotEnd(), true);
}
else {
dayEnd = DateTimeUtil.getDayBorder(end, null, true);
}
log.log(Level.FINE,"scheduleBackward --> dayEnd " + dayEnd);
Timestamp dayStart = null;
// Retrieve the start end time, dependent on timeslot or not
if(t.isTimeSlot()) {
dayStart = DateTimeUtil.getDayBorder(end, t.getTimeSlotStart(), false);
}
else {
dayStart = DateTimeUtil.getDayBorder(end, null, false);
}
log.log(Level.FINE,"scheduleBackward --> dayStart " + dayStart);
// If working has already begon at this day and the value is in the range of the
// resource's availability, switch end time to the given again
if(end.before(dayEnd) && end.after(dayStart)) {
dayEnd = end;
}
// The available time at this day in milliseconds
long availableDayDuration = DateTimeUtil.getTimeDifference(dayStart, dayEnd);
log.log(Level.FINE,"scheduleBackward --> availableDayDuration " + availableDayDuration );
Timestamp retValue = null;
// The work can be finish on this day.
if(availableDayDuration >= nodeDuration) {
log.log(Level.FINE,"scheduleBackward --> availableDayDuration >= nodeDuration true " + availableDayDuration + "|" + nodeDuration );
retValue = new Timestamp(dayEnd.getTime()-nodeDuration);
}
// Otherwise recall with previous day and the remained node duration.
else {
//retValue = scheduleBackward(DateTimeUtil.getDayBorder(end, null, true)), nodeDuration-availableDayDuration, r, t);
log.log(Level.FINE,"scheduleBackward --> availableDayDuration >= nodeDuration false " + availableDayDuration + "|" + nodeDuration );
log.log(Level.FINE,"scheduleBackward --> nodeDuration-availableDayDuration " + (nodeDuration-availableDayDuration) );
retValue = scheduleBackward(org.compiere.util.TimeUtil.addDays(DateTimeUtil.getDayBorder(end, null, true), -1), nodeDuration-availableDayDuration, r, t);
}
log.log(Level.FINE,"scheduleBackward --> retValue " + retValue);
return retValue;
} }
} }

View File

@ -1,90 +0,0 @@
/******************************************************************************
* Product: Adempiere ERP & CRM Smart Business Solution *
* 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. *
* 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 *
*****************************************************************************/
package org.eevolution.tools;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.GregorianCalendar;
/**
* @author Gunther Hoppe, tranSIT GmbH Ilmenau/Germany
* @version 1.0, October 14th 2005
*/
public class DateTimeUtil {
/**
* @param time1
* @param time2
* @return time difference (time2 - time1) in millis
*/
public static long getTimeDifference(Timestamp time1 , Timestamp time2)
{
return time2.getTime() - time1.getTime();
}
public static Timestamp[] getDayBorders(Timestamp dateTime, Timestamp timeSlotStart, Timestamp timeSlotFinish) {
return new Timestamp[] {
getDayBorder(dateTime, timeSlotStart, false),
getDayBorder(dateTime, timeSlotFinish, true),
};
}
public static Timestamp[] getDayBorders(Timestamp dateTime) {
return getDayBorders(dateTime, null, null);
}
/**
* 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());
}
}

View File

@ -17,80 +17,48 @@
package org.eevolution.form; package org.eevolution.form;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Hashtable;
import java.util.Properties;
import java.util.logging.Level;
import org.compiere.apps.ConfirmPanel;
import org.compiere.apps.form.FormFrame;
import org.compiere.apps.form.FormPanel;
import org.compiere.grid.ed.VDate;
import org.compiere.grid.ed.VLookup;
import org.compiere.model.MColumn;
import org.compiere.model.MLookup;
import org.compiere.model.MLookupFactory;
import org.compiere.model.MProduct;
import org.compiere.model.MResource;
import org.compiere.model.MResourceType;
import org.compiere.model.MUOM;
import org.compiere.swing.CLabel;
import org.compiere.swing.CPanel;
import org.compiere.util.CLogger;
import org.compiere.util.DB;
import org.compiere.util.DisplayType;
import org.compiere.util.Env;
import org.compiere.util.Msg;
import org.eevolution.form.crp.CRPDatasetFactory; import org.eevolution.form.crp.CRPDatasetFactory;
import org.eevolution.form.crp.CRPModel; import org.eevolution.form.crp.CRPModel;
import org.eevolution.model.MPPMRP; import org.eevolution.model.MPPMRP;
import org.jfree.chart.ChartFactory; import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel; import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart; import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.CategoryLabelPositions;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation; import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.BarRenderer;
import org.jfree.chart.resources.JFreeChartResources;
import org.jfree.data.category.CategoryDataset; import org.jfree.data.category.CategoryDataset;
import org.jfree.data.category.DefaultCategoryDataset; import org.jfree.data.category.DefaultCategoryDataset;
//import org.jfree.ui.ApplicationFrame;
//import org.jfree.ui.RefineryUtilities;
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Cursor;
import java.awt.GridBagConstraints;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GradientPaint;
import java.text.DateFormat;
import java.io.File;
import java.math.BigDecimal;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Hashtable;
import java.util.Properties;
import java.util.logging.Level;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import java.math.BigDecimal;
import org.compiere.apps.*;
import org.compiere.impexp.*;
import org.compiere.swing.*;
import org.compiere.util.*;
import org.compiere.model.*;
import org.compiere.minigrid.*;
import org.compiere.print.*;
import org.compiere.db.*;
import org.compiere.apps.form.FormFrame;
import org.compiere.apps.form.FormPanel;
import org.compiere.grid.ed.VDate;
import org.compiere.model.MTable;
import org.compiere.swing.CLabel;
import org.compiere.swing.CPanel;
import org.compiere.grid.ed.*;
@ -366,9 +334,8 @@ implements FormPanel, ActionListener
DefaultCategoryDataset dataset = new DefaultCategoryDataset(); DefaultCategoryDataset dataset = new DefaultCategoryDataset();
double currentweight = DB.getSQLValue(null, "Select SUM( (mo.qtyordered-mo.qtydelivered)*(Select mp.weight From m_product mp Where mo.m_product_id=mp.m_product_id ) )From PP_order mo Where ad_client_id=?", r.getAD_Client_ID()); double currentweight = DB.getSQLValue(null, "Select SUM( (mo.qtyordered-mo.qtydelivered)*(Select mp.weight From m_product mp Where mo.m_product_id=mp.m_product_id ) )From PP_order mo Where ad_client_id=?", r.getAD_Client_ID());
double dailyCapacity = DB.getSQLValue(null,"Select dailycapacity From s_resource Where s_resource_id=?",r.getS_Resource_ID()); double dailyCapacity = r.getDailyCapacity().doubleValue();
double utilization = DB.getSQLValue(null, "Select percentutilization From s_resource Where s_resource_id=?", r.getS_Resource_ID()); double utilization = r.getPercentUtilization().doubleValue();
double summary = 0; double summary = 0;
int day = 0; int day = 0;

View File

@ -1,5 +1,5 @@
/****************************************************************************** /******************************************************************************
* Product: Adempiere ERP & CRM Smart Business Solution * * Product: Adempiere ERP & CRM Smart Business Solution *
* This program is free software; you can redistribute it and/or modify it * * 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 * * 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 * * by the Free Software Foundation. This program is distributed in the hope *
@ -12,11 +12,13 @@
* For the text or an alternative of this public license, you may reach us * * For the text or an alternative of this public license, you may reach us *
* Copyright (C) 2003-2007 e-Evolution,SC. All Rights Reserved. * * Copyright (C) 2003-2007 e-Evolution,SC. All Rights Reserved. *
* Contributor(s): Victor Perez www.e-evolution.com * * Contributor(s): Victor Perez www.e-evolution.com *
* Teo Sarca, www.arhipac.ro *
*****************************************************************************/ *****************************************************************************/
package org.eevolution.form.crp; package org.eevolution.form.crp;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
@ -30,31 +32,34 @@ import org.compiere.model.MResource;
import org.compiere.model.MResourceType; import org.compiere.model.MResourceType;
import org.compiere.model.MUOM; import org.compiere.model.MUOM;
import org.compiere.model.MUOMConversion; import org.compiere.model.MUOMConversion;
import org.eevolution.model.reasoner.CRPReasoner; import org.compiere.util.DisplayType;
import org.compiere.util.Env; import org.compiere.util.Env;
import org.compiere.util.Msg; import org.compiere.util.Msg;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.category.DefaultCategoryDataset;
import org.eevolution.tools.DateTimeUtil;
import org.eevolution.model.MPPOrder; import org.eevolution.model.MPPOrder;
import org.eevolution.model.MPPOrderNode; import org.eevolution.model.MPPOrderNode;
import org.eevolution.model.MPPOrderWorkflow; import org.eevolution.model.MPPOrderWorkflow;
import org.eevolution.model.reasoner.CRPReasoner;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.category.DefaultCategoryDataset;
/** /**
* @author Gunther Hoppe, tranSIT GmbH Ilmenau/Germany * @author Gunther Hoppe, tranSIT GmbH Ilmenau/Germany
* @version 1.0, October 14th 2005 * @version 1.0, October 14th 2005
*
* @author Teo Sarca, http://www.arhipac.ro
*/ */
public abstract class CRPDatasetFactory extends CRPReasoner implements CRPModel { public abstract class CRPDatasetFactory extends CRPReasoner implements CRPModel
{
protected JTree tree; protected JTree tree;
protected DefaultCategoryDataset dataset; protected DefaultCategoryDataset dataset;
protected abstract BigDecimal convert(BigDecimal value); /**
* Convert from minutes to base UOM
*/
protected abstract BigDecimal convert(BigDecimal minutes);
public static CRPModel get(Timestamp start, Timestamp end, MResource r) { public static CRPModel get(Timestamp start, Timestamp end, MResource r)
{
MResourceType t = MResourceType.get(Env.getCtx(), r.getS_ResourceType_ID()); MResourceType t = MResourceType.get(Env.getCtx(), r.getS_ResourceType_ID());
// UOM ID - 'Minutes' is base unit // UOM ID - 'Minutes' is base unit
final MUOM uom1 = MUOM.get(Env.getCtx(), MUOM.getMinute_UOM_ID(Env.getCtx())); final MUOM uom1 = MUOM.get(Env.getCtx(), MUOM.getMinute_UOM_ID(Env.getCtx()));
@ -62,202 +67,180 @@ public abstract class CRPDatasetFactory extends CRPReasoner implements CRPModel
final MUOM uom2 = MUOM.get(Env.getCtx(), t.getC_UOM_ID()); final MUOM uom2 = MUOM.get(Env.getCtx(), t.getC_UOM_ID());
CRPDatasetFactory factory = new CRPDatasetFactory() { CRPDatasetFactory factory = new CRPDatasetFactory() {
protected BigDecimal convert(BigDecimal minutes)
protected BigDecimal convert(BigDecimal value) { {
return MUOMConversion.convert(Env.getCtx(), uom1.get_ID(), uom2.get_ID(), minutes);
return MUOMConversion.convert(Env.getCtx(), uom1.get_ID(), uom2.get_ID(), value);
} }
}; };
factory.generate(start, end, r); factory.generate(start, end, r);
return factory; return factory;
} }
protected boolean generate(Timestamp start, Timestamp end, MResource r) { private void generate(Timestamp start, Timestamp end, MResource r)
{
if(start == null || end == null || r == null) { if(start == null || end == null || r == null)
{
return false; return ;
} }
String labelActCap = Msg.translate(Env.getCtx(), "DailyCapacity"); String labelActCap = Msg.translate(Env.getCtx(), "DailyCapacity");
String labelLoadAct = Msg.translate(Env.getCtx(), "ActualLoad"); String labelLoadAct = Msg.translate(Env.getCtx(), "ActualLoad");
DateFormat formatter = DisplayType.getDateFormat(DisplayType.DateTime, Env.getLanguage(Env.getCtx()));
MResourceType t = MResourceType.get(Env.getCtx(), r.getS_ResourceType_ID()); BigDecimal dailyCapacity = getMaxRange(r);
BigDecimal utilization = r.getPercentUtilization();
BigDecimal dailyCapacity = null;
if(BigDecimal.ZERO.compareTo(utilization) < 0) {
dailyCapacity = r.getDailyCapacity().divide(utilization.divide(new BigDecimal(100)), 8, BigDecimal.ROUND_HALF_DOWN);
}
else {
dailyCapacity = BigDecimal.ZERO;
}
BigDecimal load = null;
String label = null; dataset = new DefaultCategoryDataset();
DateFormat formatter = DateFormat.getDateInstance(); HashMap<DefaultMutableTreeNode, String> names = new HashMap<DefaultMutableTreeNode, String>();
DefaultMutableTreeNode root = new DefaultMutableTreeNode(r);
names.put(root, getTreeNodeRepresentation(null, root, r));
dataset = new DefaultCategoryDataset(); Timestamp dateTime = start;
HashMap names = new HashMap(); while(end.after(dateTime))
DefaultMutableTreeNode root = new DefaultMutableTreeNode(r); {
names.put(root, getTreeNodeRepresentation(null, root, r)); String label = formatter.format(dateTime);
names.putAll(addTreeNodes(dateTime, root, r));
Timestamp dateTime = start;
while(end.after(dateTime)) {
label = formatter.format(dateTime); boolean available = isAvailable(r, dateTime);
names.putAll(addTreeNodes(dateTime, root, r)); dataset.addValue(available ? dailyCapacity : BigDecimal.ZERO, labelActCap, label);
dataset.addValue(available ? calculateLoad(dateTime, r, null) : BigDecimal.ZERO, labelLoadAct, label);
load = isResourceAvailable(dateTime, r) ? calculateLoad(dateTime, r, null) : BigDecimal.ZERO; dateTime = org.compiere.util.TimeUtil.addDays(dateTime, 1); // TODO: teo_sarca: increment should be more general, not only days
dataset.addValue(isResourceAvailable(dateTime, r) ? dailyCapacity : BigDecimal.ZERO ,labelActCap, label); }
dataset.addValue(isResourceAvailable(dateTime, r) ? load : BigDecimal.ZERO ,labelLoadAct, label);
//dateTime = DateTimeUtil.incrementDay(dateTime); tree = new JTree(root);
dateTime = org.compiere.util.TimeUtil.addDays(dateTime,1); tree.setCellRenderer(new DiagramTreeCellRenderer(names));
}
tree = new JTree(root);
tree.setCellRenderer(new DiagramTreeCellRenderer(names));
return true;
} }
public BigDecimal calculateLoad(Timestamp dateTime, MResource r, String docStatus) { public BigDecimal calculateLoad(Timestamp dateTime, MResource r, String docStatus)
{
MResourceType t = MResourceType.get(Env.getCtx(), r.getS_ResourceType_ID()); MResourceType t = MResourceType.get(Env.getCtx(), r.getS_ResourceType_ID());
MPPOrderNode[] nodes = getPPOrderNodes(dateTime, r);
MUOM uom = MUOM.get(Env.getCtx(), t.getC_UOM_ID()); MUOM uom = MUOM.get(Env.getCtx(), t.getC_UOM_ID());
MPPOrder o = null;
BigDecimal qtyOpen; BigDecimal qtyOpen;
long millis = 0l; long millis = 0l;
for(int i = 0; i < nodes.length; i++) { for(MPPOrderNode node : getPPOrderNodes(dateTime, r))
o = new MPPOrder(Env.getCtx(), nodes[i].getPP_Order_ID(), null); {
if(docStatus != null && !o.getDocStatus().equals(docStatus)) { if (docStatus != null)
{
continue; MPPOrder o = new MPPOrder(node.getCtx(), node.getPP_Order_ID(), node.get_TrxName());
if(!o.getDocStatus().equals(docStatus))
{
continue;
}
} }
millis += calculateMillisForDay(dateTime, node, t);
millis += calculateMillisForDay(dateTime, nodes[i], t);
} }
// Pre-converts to minutes, because its the lowest time unit of compiere // Pre-converts to minutes, because its the lowest time unit of compiere
BigDecimal scale = new BigDecimal(1000*60); BigDecimal scale = new BigDecimal(1000*60);
BigDecimal minutes = new BigDecimal(millis).divide(scale, 2, BigDecimal.ROUND_HALF_UP); BigDecimal minutes = new BigDecimal(millis).divide(scale, 2, BigDecimal.ROUND_HALF_UP);
return convert(minutes); return convert(minutes);
} }
protected Timestamp[] getDayBorders(Timestamp dateTime, MPPOrderNode node, MResourceType t) { /**
* Gets {StartDate, EndDate} times for given dateTime.
Timestamp endDayTime = null; * For calculating this, following factors are considered:
* <li> resource type time slot
* <li> node DateStartSchedule and DateEndSchedule
* @param dateTime
* @param node
* @param t resouce type
* @return array of 2 elements, {StartDate, EndDate}
*/
private Timestamp[] getDayBorders(Timestamp dateTime, MPPOrderNode node, MResourceType t)
{
// The theoretical latest time on a day, where the work ends, dependent on // The theoretical latest time on a day, where the work ends, dependent on
// the resource type's time slot value // the resource type's time slot value
if(t.isTimeSlot()) { Timestamp endDayTime = t.getDayEnd(dateTime);
// Initialize the end time to the present, if the work ends at this day.
endDayTime = DateTimeUtil.getDayBorder(dateTime, t.getTimeSlotEnd(), true); // Otherwise the earliest possible start time for a day is set.
}
else {
endDayTime = DateTimeUtil.getDayBorder(dateTime, null, true);
}
// Initialize the end time to the present, if the work ends at this day. Otherwise
// the earliest possible start time for a day is set.
endDayTime = (endDayTime.before(node.getDateFinishSchedule())) ? endDayTime : node.getDateFinishSchedule(); endDayTime = (endDayTime.before(node.getDateFinishSchedule())) ? endDayTime : node.getDateFinishSchedule();
Timestamp startDayTime = null;
// The theoretical earliest time on a day, where the work begins, dependent on // The theoretical earliest time on a day, where the work begins, dependent on
// the resource type's time slot value // the resource type's time slot value
if(t.isTimeSlot()) { Timestamp startDayTime = t.getDayStart(dateTime);
// Initialize the start time to the present, if the work begins at this day.
startDayTime = DateTimeUtil.getDayBorder(dateTime, t.getTimeSlotStart(), false); // Otherwise the latest possible start time for a day is set.
}
else {
startDayTime = DateTimeUtil.getDayBorder(dateTime, null, false);
}
// Initialize the end time to the present, if the work begins at this day. Otherwise
// the earliest possible start time for a day is set.
startDayTime = (startDayTime.after(node.getDateStartSchedule())) ? startDayTime : node.getDateStartSchedule(); startDayTime = (startDayTime.after(node.getDateStartSchedule())) ? startDayTime : node.getDateStartSchedule();
return new Timestamp[] {startDayTime, endDayTime}; return new Timestamp[] {startDayTime, endDayTime};
} }
protected long calculateMillisForDay(Timestamp dateTime, MPPOrderNode node, MResourceType t) { private long calculateMillisForDay(Timestamp dateTime, MPPOrderNode node, MResourceType t)
{
Timestamp[] borders = getDayBorders(dateTime, node, t); Timestamp[] borders = getDayBorders(dateTime, node, t);
return DateTimeUtil.getTimeDifference(borders[0], borders[1]); return borders[1].getTime() - borders[0].getTime();
} }
protected HashMap addTreeNodes(Timestamp dateTime, DefaultMutableTreeNode root, MResource r) {
HashMap names = new HashMap(); /**
* Generates following tree:
* <pre>
* (dateTime)
* \-------(root)
* \-------(PP Order)
* \---------(PP Order Node)
* </pre>
* @param dateTime
* @param root
* @param r
* @return
*/
private HashMap<DefaultMutableTreeNode, String> addTreeNodes(Timestamp dateTime, DefaultMutableTreeNode root, MResource r)
{
HashMap<DefaultMutableTreeNode, String> names = new HashMap<DefaultMutableTreeNode, String>();
MPPOrder[] orders = getPPOrders(dateTime, r);
MPPOrderNode[] nodes = null;
DefaultMutableTreeNode parent = new DefaultMutableTreeNode(dateTime); DefaultMutableTreeNode parent = new DefaultMutableTreeNode(dateTime);
names.put(parent, getTreeNodeRepresentation(null, parent, r)); names.put(parent, getTreeNodeRepresentation(null, parent, r));
DefaultMutableTreeNode child1 = null;
DefaultMutableTreeNode child2 = null;
root.add(parent); root.add(parent);
for(int i = 0; i < orders.length; i++) { for(MPPOrder order : getPPOrders(dateTime, r))
{
DefaultMutableTreeNode childOrder = new DefaultMutableTreeNode(order);
parent.add(childOrder);
names.put(childOrder, getTreeNodeRepresentation(dateTime, childOrder, r));
child1 = new DefaultMutableTreeNode(orders[i]); for(MPPOrderNode node : getPPOrderNodes(dateTime, r))
parent.add(child1); {
DefaultMutableTreeNode childNode = new DefaultMutableTreeNode(node);
names.put(child1, getTreeNodeRepresentation(dateTime, child1, r)); childOrder.add(childNode);
names.put(childNode, getTreeNodeRepresentation(dateTime, childNode, r));
nodes = getPPOrderNodes(dateTime, r);
for(int j = 0; j < nodes.length; j++) {
child2 = new DefaultMutableTreeNode(nodes[j]);
child1.add(child2);
names.put(child2, getTreeNodeRepresentation(dateTime, child2, r));
} }
} }
return names; return names;
} }
protected String getTreeNodeRepresentation(Timestamp dateTime, DefaultMutableTreeNode node, MResource r) { private String getTreeNodeRepresentation(Timestamp dateTime, DefaultMutableTreeNode node, MResource r)
{
String name = null; String name = null;
if(node.getUserObject() instanceof MResource) { if(node.getUserObject() instanceof MResource)
{
MResource res = (MResource) node.getUserObject(); MResource res = (MResource) node.getUserObject();
name = res.getName(); name = res.getName();
} }
else if(node.getUserObject() instanceof Timestamp) { else if(node.getUserObject() instanceof Timestamp)
{
Timestamp d = (Timestamp)node.getUserObject(); Timestamp d = (Timestamp)node.getUserObject();
SimpleDateFormat df = Env.getLanguage(Env.getCtx()).getDateFormat(); SimpleDateFormat df = Env.getLanguage(Env.getCtx()).getDateFormat();
name = df.format(d); name = df.format(d);
if(!isResourceAvailable(d, r)) { if(!isAvailable(r, d))
{
name = "{"+name+"}"; name = "{"+name+"}";
} }
} }
else if(node.getUserObject() instanceof MPPOrder) { else if(node.getUserObject() instanceof MPPOrder)
{
MPPOrder o = (MPPOrder)node.getUserObject(); MPPOrder o = (MPPOrder)node.getUserObject();
MProduct p = new MProduct(Env.getCtx(), o.getM_Product_ID(), null); MProduct p = MProduct.get(Env.getCtx(), o.getM_Product_ID());
name = o.getDocumentNo()+" ("+p.getName()+")"; name = o.getDocumentNo()+" ("+p.getName()+")";
} }
else if(node.getUserObject() instanceof MPPOrderNode) { else if(node.getUserObject() instanceof MPPOrderNode)
{
MPPOrderNode on = (MPPOrderNode)node.getUserObject(); MPPOrderNode on = (MPPOrderNode)node.getUserObject();
MPPOrderWorkflow owf = new MPPOrderWorkflow(Env.getCtx(), on.getPP_Order_Workflow_ID(), null); MPPOrderWorkflow owf = on.getWorkflow();
MResourceType rt = MResourceType.get(Env.getCtx(), r.getS_ResourceType_ID()); MResourceType rt = MResourceType.get(Env.getCtx(), r.getS_ResourceType_ID());
// no function // no function
@ -270,19 +253,23 @@ public abstract class CRPDatasetFactory extends CRPReasoner implements CRPModel
return name; return name;
} }
protected BigDecimal getMaxRange(MResource r) { /**
* @return Daily Capacity * Utilization / 100
return r.getDailyCapacity().divide(r.getPercentUtilization().divide(new BigDecimal(100))); */
private BigDecimal getMaxRange(MResource r)
} {
BigDecimal utilizationDec = r.getPercentUtilization().divide(Env.ONEHUNDRED, 2, RoundingMode.HALF_UP);
int precision = 2; // TODO: hardcoded
return r.getDailyCapacity().divide(utilizationDec, precision, RoundingMode.HALF_UP);
}
public CategoryDataset getDataset() { public CategoryDataset getDataset()
{
return dataset; return dataset;
} }
public JTree getTree() { public JTree getTree()
{
return tree; return tree;
} }
} }

View File

@ -28,12 +28,10 @@ import org.jfree.data.category.CategoryDataset;
* @author Gunther Hoppe, tranSIT GmbH Ilmenau/Germany * @author Gunther Hoppe, tranSIT GmbH Ilmenau/Germany
* @version 1.0, October 14th 2005 * @version 1.0, October 14th 2005
*/ */
public interface CRPModel { public interface CRPModel
{
public JTree getTree(); public JTree getTree();
public CategoryDataset getDataset(); public CategoryDataset getDataset();
public BigDecimal calculateLoad(Timestamp dateTime, MResource r, String docStatus); public BigDecimal calculateLoad(Timestamp dateTime, MResource r, String docStatus);
} }

View File

@ -28,9 +28,7 @@ import javax.swing.tree.DefaultMutableTreeNode;
import org.compiere.model.MResource; import org.compiere.model.MResource;
import org.compiere.util.Env; import org.compiere.util.Env;
import org.eevolution.form.tree.MapTreeCellRenderer; import org.eevolution.form.tree.MapTreeCellRenderer;
import org.eevolution.model.MPPOrder; import org.eevolution.model.MPPOrder;
import org.eevolution.model.MPPOrderNode; import org.eevolution.model.MPPOrderNode;
@ -38,60 +36,60 @@ import org.eevolution.model.MPPOrderNode;
* @author Gunther Hoppe, tranSIT GmbH Ilmenau/Germany * @author Gunther Hoppe, tranSIT GmbH Ilmenau/Germany
* @version 1.0, October 14th 2005 * @version 1.0, October 14th 2005
*/ */
public class DiagramTreeCellRenderer extends MapTreeCellRenderer { public class DiagramTreeCellRenderer extends MapTreeCellRenderer
{
public DiagramTreeCellRenderer(HashMap map) { private static final long serialVersionUID = 1L;
public DiagramTreeCellRenderer(HashMap<?, ?> map)
{
super(map); super(map);
} }
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
String name = (String)getMapping(value);
ImageIcon icon = getIcon(value);
if(isNotAvailable(name)) {
final int x1 = getFontMetrics(getFont()).stringWidth(name)+icon.getIconWidth();
JLabel l = new JLabel(name.substring(1, name.length()-1), icon, JLabel.LEFT) {
public void paint(Graphics g) {
super.paint(g); @Override
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus)
int y = getFont().getSize()/2; {
Component c = super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
g.drawLine(0, y, x1, y);
} String name = (String)getMapping(value);
}; ImageIcon icon = getIcon(value);
l.setFont(getFont()); if(isNotAvailable(name))
return l; {
} final int x1 = getFontMetrics(getFont()).stringWidth(name) + icon.getIconWidth();
return this; JLabel l = new JLabel(name.substring(1, name.length()-1), icon, JLabel.LEFT) {
} private static final long serialVersionUID = 1L;
public void paint(Graphics g) {
super.paint(g);
int y = getFont().getSize()/2;
g.drawLine(0, y, x1, y);
}
};
l.setFont(getFont());
return l;
}
return c;
}
private boolean isNotAvailable(String value) { private boolean isNotAvailable(String value)
{
return value.startsWith("{") && value.endsWith("}"); return value.startsWith("{") && value.endsWith("}");
} }
protected ImageIcon getIcon(Object value) { protected ImageIcon getIcon(Object value)
{
ImageIcon icon = null; ImageIcon icon = null;
DefaultMutableTreeNode node = (DefaultMutableTreeNode)value; DefaultMutableTreeNode node = (DefaultMutableTreeNode)value;
if(node.getUserObject() instanceof MResource) { if(node.getUserObject() instanceof MResource)
{
} }
else if(node.getUserObject() instanceof Date) { else if(node.getUserObject() instanceof Date)
{
icon = Env.getImageIcon("Calendar10.gif"); icon = Env.getImageIcon("Calendar10.gif");
} }
else if(node.getUserObject() instanceof MPPOrder) { else if(node.getUserObject() instanceof MPPOrder)
{
} }
else if(node.getUserObject() instanceof MPPOrderNode) { else if(node.getUserObject() instanceof MPPOrderNode)
{
} }
return icon; return icon;