* 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;
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
* <li>FR [ 2051056 ] MResource[Type] should be cached
* <li>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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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<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()
{
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

View File

@ -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<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 =
// 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 on WHERE on.S_Resource_ID="+r.getID()+")"
"S_Resource_ID="+r.get_ID() +" AND DocStatus <> 'CL' AND AD_Client_ID = " + r.getAD_Client_ID() ; //+ " AND PP_Order_ID = 1000031" ;
// ... and completed orders needn't to be observed
//
// Case 3: The time dependent process begins at this day and ends few days later.
whereClause += " OR (DateStartSchedule>=? AND DateStartSchedule<=? AND DateFinishSchedule>=?)";
params.add(dayStart);
params.add(dayEnd);
params.add(dayEnd);
int[] orderIds = PO.getAllIDs("PP_Order", where, null);
MPPOrder[] orders = new MPPOrder[orderIds.length];
for(int i = 0; i < orderIds.length; i++) {
//
// Case 4: The time dependent process has already begun and ends few days later.
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) {
MResourceType t = MResourceType.get(Env.getCtx(), r.getS_ResourceType_ID());
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)) {
public MPPOrder[] getPPOrders(Timestamp dateTime, MResource r)
{
if(!isAvailable(r, dateTime))
{
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
"PP_order_id in (select PP_order_id from PP_order_node where s_resource_id="+r.get_ID()
// ... and only the orders running on given day
+" AND ("+getDayRestriction(dateTime, r)+") ) AND AD_Client_ID =" + r.getAD_Client_ID();
int[] orderIds = PO.getAllIDs("PP_Order", where, null);
MPPOrder[] orders = new MPPOrder[orderIds.length];
for(int i = 0; i < orderIds.length; i++) {
orders[i] = new MPPOrder(Env.getCtx(), orderIds[i], null);
}
return orders;
"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 "+getSQLDayRestriction(dateTime, r, params)
+")"
+ " AND AD_Client_ID=?";
params.add(r.getAD_Client_ID());
List<MPPOrder> list = new Query(r.getCtx(), MPPOrder.Table_Name, whereClause, null)
.setParameters(params)
.list();
return list.toArray(new MPPOrder[list.size()]);
}
public MPPOrderNode[] getPPOrderNodes(Timestamp dateTime, MResource r) {
if(!isResourceAvailable(dateTime, r)) {
public MPPOrderNode[] getPPOrderNodes(Timestamp dateTime, MResource r)
{
if(!isAvailable(r, dateTime))
{
return new MPPOrderNode[0];
}
String where =
"s_resource_id = "+r.get_ID()
+" AND ("+getDayRestriction(dateTime, r)+") AND AD_Client_ID = " + r.getAD_Client_ID();
log.log(Level.FINE,"getPPOrderNodes --> Where:" + where);
int[] ids = PO.getAllIDs("PP_Order_Node", where, null);
MPPOrderNode[] nodes = new MPPOrderNode[ids.length];
for(int i = 0; i < ids.length; i++) {
nodes[i] = new MPPOrderNode(Env.getCtx(), ids[i], null);
}
return nodes;
ArrayList<Object> params = new ArrayList<Object>();
String whereClause = MPPOrderNode.COLUMNNAME_S_Resource_ID+"=? AND AD_Client_ID=?";
params.add(r.get_ID());
params.add(r.getAD_Client_ID());
whereClause += " AND "+getSQLDayRestriction(dateTime, r, params);
List<MPPOrderNode> list = new Query(r.getCtx(), MPPOrderNode.Table_Name, whereClause, null)
.setParameters(params)
.list();
return list.toArray(new MPPOrderNode[list.size()]);
}
public MPPOrderWorkflow getPPOrderWorkflow(MPPOrder o) {
int[] ids = PO.getAllIDs("PP_Order_Workflow", "PP_Order_ID = "+o.get_ID() + " AND AD_Client_ID = " + o.getAD_Client_ID(), null);
return (ids.length != 1) ? null : new MPPOrderWorkflow(Env.getCtx(), ids[0], null);
public boolean isAvailable(MResource r, Timestamp dateTime)
{
MResourceType t = MResourceType.get(Env.getCtx(), r.getS_ResourceType_ID());
return t.isDayAvailable(dateTime) && !MResourceUnAvailable.isUnAvailable(r, dateTime);
}
public boolean checkResourceTypeAvailability(MResourceType t) {
if(!t.isDateSlot()) {
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 isAvailable(MResource r)
{
return r.getResourceType().isAvailable();
}
public boolean checkResourceAvailability(Timestamp dateTime, MResource r) {
int[] ids = PO.getAllIDs("S_ResourceUnAvailable", "S_Resource_ID = "+r.get_ID() + " AND AD_Client_ID = " + r.getAD_Client_ID(), null);
Timestamp dateFrom = null;
Timestamp dateTo = null;
Timestamp dateActual = null;
MResourceUnAvailable rua = null;
for(int i = 0; i < ids.length; i++) {
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;
private Timestamp getAvailableDate(MResourceType t, Timestamp dateTime, boolean isScheduleBackward)
{
Timestamp date = TimeUtil.trunc(dateTime, TimeUtil.TRUNC_DAY);
int direction = isScheduleBackward ? -1 : +1;
for (int i = 0; i <= 7; i++)
{
date = TimeUtil.addDays(date, i * direction);
if (t.isDayAvailable(date))
{
break;
}
}
return true;
return date;
}
public boolean checkResourceTypeAvailability(Timestamp dateTime, MResourceType t) {
if(!t.isDateSlot()) {
return true;
/**
* @param r resource
* @param dateTime
* @return next available date
*/
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();
gc.setTimeInMillis(dateTime.getTime());
boolean retValue = false;
switch(gc.get(Calendar.DAY_OF_WEEK)) {
case Calendar.SUNDAY:
retValue = t.isOnSunday();
break;
case Calendar.MONDAY:
retValue = t.isOnMonday();
break;
case Calendar.TUESDAY:
retValue = t.isOnTuesday();
break;
case Calendar.WEDNESDAY:
retValue = t.isOnWednesday();
break;
case Calendar.THURSDAY:
retValue = t.isOnThursday();
break;
case Calendar.FRIDAY:
retValue = t.isOnFriday();
break;
case Calendar.SATURDAY:
retValue = t.isOnSaturday();
break;
}
return retValue;
whereClause += " AND "+MResourceUnAvailable.COLUMNNAME_S_Resource_ID+"=? AND AD_Client_ID=?";
params.add(r.get_ID());
params.add(r.getAD_Client_ID());
POResultSet<MResourceUnAvailable> rs = new Query(r.getCtx(), MResourceUnAvailable.Table_Name, whereClause, null)
.setOrderBy(orderByClause)
.setParameters(params)
.scroll();
try
{
while(rs.hasNext())
{
MResourceUnAvailable rua = rs.next();
if (rua.isUnAvailable(date))
{
date = TimeUtil.addDays(rua.getDateTo(), 1 * direction);
}
date = getAvailableDate(t, dateTime, isScheduleBackward);
}
}
finally
{
DB.close(rs);
}
//
date = getAvailableDate(t, dateTime, isScheduleBackward);
return date;
}
}

View File

@ -12,33 +12,35 @@
* 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.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.SvrProcess;
import org.compiere.util.Env;
import org.compiere.util.Msg;
import org.compiere.util.DB;
import org.compiere.util.TimeUtil;
import org.eevolution.model.MPPOrder;
import org.eevolution.model.MPPOrderNode;
import org.eevolution.model.MPPOrderWorkflow;
import org.compiere.model.*;
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
*
* @author Gunther Hoppe, tranSIT GmbH Ilmenau/Germany (Original by Victor Perez, e-Evolution, S.C.)
* @version 1.0, October 14th 2005
*
* @author Teo Sarca, www.arhipac.ro
*/
public class CRP extends SvrProcess {
@ -55,35 +57,22 @@ public class CRP extends SvrProcess {
reasoner = new CRPReasoner();
}
protected void prepare() {
protected void prepare()
{
ProcessInfoParameter[] para = getParameter();
if(para == null) {
return;
}
for (int i = 0; i < para.length; i++) {
if(para[i] == null) {
continue;
}
for (int i = 0; i < para.length; i++)
{
String name = para[i].getParameterName();
if (para[i].getParameter() == null)
;
if (name.equals("S_Resource_ID")) {
p_S_Resource_ID = ((BigDecimal)para[i].getParameter()).intValue();
}
else if (name.equals("ScheduleType")) {
p_ScheduleType = ((String)para[i].getParameter());
}
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();
}
private String runCRP() {
MPPOrderWorkflow owf = null;
MPPOrderNode node = null;
MResource resource = null;
MResourceType resourceType = null;
BigDecimal qtyOpen = null;
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");
private String runCRP()
{
POResultSet<MPPOrder> rs = reasoner.getPPOrdersNotCompletedQuery(p_S_Resource_ID, get_TrxName())
.scroll();
try
{
while(rs.hasNext())
{
runCRP(rs.next());
}
// Schedule Fordward
if (p_ScheduleType.equals(FORWARD_SCHEDULING)) {
log.log(Level.FINE,"MPP_Order DocumentNo:" + orders[i].getDocumentNo());
log.log(Level.FINE,"MPP_Order Workflow:" + owf.getName());
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());
}
finally
{
DB.close(rs);
rs = null;
}
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
double aDay24 = 24*60*60*1000;
// Schedule Fordward
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.
double actualDay = aDay24;
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 resource type is timeslot, updating to available time of the resource.
if (type.isTimeSlot()) {
if(!reasoner.isAvailable(resource))
{
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
BigDecimal factorAvailablility = new BigDecimal((actualDay / aDay24));
order.saveEx(get_TrxName());
}
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) ...
// ... its static single parts ...
BigDecimal totalDuration = new BigDecimal(
long totalDuration =
//node.getQueuingTime()
node.getSetupTimeRequiered() // Use the present required setup time to notice later changes
+ node.getMovingTime()
+ node.getWaitingTime()
);
;
// ... 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.getDuration())));
// ... converted to common base.
totalDuration = totalDuration.multiply(new BigDecimal(commonBase));
totalDuration += qty.doubleValue() * node.getDuration();
// 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) {
// Checks, whether the resource is available at this day and recall with
// next day, if not.
if(!reasoner.checkResourceAvailability(start, r)) {
//return scheduleForward(Util.incrementDay(start), nodeDuration, r, t);
return scheduleForward(org.compiere.util.TimeUtil.addDays(start, 1) , nodeDuration, r, t);
}
// Checks, whether the resource type (only if date slot) is available at
// this day and recall with next day, if not.
else if(t.isDateSlot()) {
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);
private Timestamp scheduleForward(Timestamp start, long nodeDuration, MResource r, MResourceType t)
{
Timestamp end = null;
int iteration = 0; // statistical interation count
do
{
start = reasoner.getAvailableDate(r, start, false);
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
// 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 = 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;
// 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;
return end;
}
private Timestamp scheduleBackward(Timestamp end, long nodeDuration, MResource r, MResourceType t) {
log.log(Level.FINE,"scheduleBackward --> end " +end);
log.log(Level.FINE,"scheduleBackward --> nodeDuration " +nodeDuration);
log.log(Level.FINE,"scheduleBackward --> ResourceType " + t);
// Checks, whether the resource is available at this day and recall with
// next day, if not.
if(!reasoner.checkResourceAvailability(end, r)) {
//return scheduleBackward(DateTimeUtil.decrementDay(end), nodeDuration, r, t);
return scheduleBackward(org.compiere.util.TimeUtil.addDays(end , -1), nodeDuration, r, t);
}
// Checks, whether the resource type (only if date slot) is available on
// this day and recall with next day, if not.
if(t.isDateSlot()) {
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);
private Timestamp scheduleBackward(Timestamp end, long nodeDuration, MResource r, MResourceType t)
{
log.fine("--> ResourceType " + t);
Timestamp start = null;
int iteration = 0; // statistical interation count
do
{
log.fine("--> end " +end);
log.fine("--> nodeDuration=" +nodeDuration);
end = reasoner.getAvailableDate(r, end, true);
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
// 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 = 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++;
}
Timestamp dayEnd = null;
// Retrieve the principal days end time, dependent on timeslot or not
if(t.isTimeSlot()) {
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;
while(nodeDuration > 0);
log.fine(" --> start=" + start + " <---------------------------------------- ");
return start;
}
}

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;
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.CRPModel;
import org.eevolution.model.MPPMRP;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
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.renderer.category.BarRenderer;
import org.jfree.chart.resources.JFreeChartResources;
import org.jfree.data.category.CategoryDataset;
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();
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 utilization = DB.getSQLValue(null, "Select percentutilization From s_resource Where s_resource_id=?", r.getS_Resource_ID());
double dailyCapacity = r.getDailyCapacity().doubleValue();
double utilization = r.getPercentUtilization().doubleValue();
double summary = 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 *
* 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 *
@ -12,11 +12,13 @@
* 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.form.crp;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
@ -30,31 +32,34 @@ import org.compiere.model.MResource;
import org.compiere.model.MResourceType;
import org.compiere.model.MUOM;
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.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.MPPOrderNode;
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
* @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 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());
// UOM ID - 'Minutes' is base unit
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());
CRPDatasetFactory factory = new CRPDatasetFactory() {
protected BigDecimal convert(BigDecimal value) {
return MUOMConversion.convert(Env.getCtx(), uom1.get_ID(), uom2.get_ID(), value);
protected BigDecimal convert(BigDecimal minutes)
{
return MUOMConversion.convert(Env.getCtx(), uom1.get_ID(), uom2.get_ID(), minutes);
}
};
factory.generate(start, end, r);
return factory;
}
protected boolean generate(Timestamp start, Timestamp end, MResource r) {
if(start == null || end == null || r == null) {
return false;
private void generate(Timestamp start, Timestamp end, MResource r)
{
if(start == null || end == null || r == null)
{
return ;
}
String labelActCap = Msg.translate(Env.getCtx(), "DailyCapacity");
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 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;
BigDecimal dailyCapacity = getMaxRange(r);
String label = null;
DateFormat formatter = DateFormat.getDateInstance();
dataset = new DefaultCategoryDataset();
HashMap<DefaultMutableTreeNode, String> names = new HashMap<DefaultMutableTreeNode, String>();
DefaultMutableTreeNode root = new DefaultMutableTreeNode(r);
names.put(root, getTreeNodeRepresentation(null, root, r));
dataset = new DefaultCategoryDataset();
HashMap names = new HashMap();
DefaultMutableTreeNode root = new DefaultMutableTreeNode(r);
names.put(root, getTreeNodeRepresentation(null, root, r));
Timestamp dateTime = start;
while(end.after(dateTime)) {
Timestamp dateTime = start;
while(end.after(dateTime))
{
String label = formatter.format(dateTime);
names.putAll(addTreeNodes(dateTime, root, r));
label = formatter.format(dateTime);
names.putAll(addTreeNodes(dateTime, root, r));
boolean available = isAvailable(r, dateTime);
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;
dataset.addValue(isResourceAvailable(dateTime, r) ? dailyCapacity : BigDecimal.ZERO ,labelActCap, label);
dataset.addValue(isResourceAvailable(dateTime, r) ? load : BigDecimal.ZERO ,labelLoadAct, label);
dateTime = org.compiere.util.TimeUtil.addDays(dateTime, 1); // TODO: teo_sarca: increment should be more general, not only days
}
//dateTime = DateTimeUtil.incrementDay(dateTime);
dateTime = org.compiere.util.TimeUtil.addDays(dateTime,1);
}
tree = new JTree(root);
tree.setCellRenderer(new DiagramTreeCellRenderer(names));
return true;
tree = new JTree(root);
tree.setCellRenderer(new DiagramTreeCellRenderer(names));
}
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());
MPPOrderNode[] nodes = getPPOrderNodes(dateTime, r);
MUOM uom = MUOM.get(Env.getCtx(), t.getC_UOM_ID());
MPPOrder o = null;
BigDecimal qtyOpen;
long millis = 0l;
for(int i = 0; i < nodes.length; i++) {
o = new MPPOrder(Env.getCtx(), nodes[i].getPP_Order_ID(), null);
if(docStatus != null && !o.getDocStatus().equals(docStatus)) {
continue;
for(MPPOrderNode node : getPPOrderNodes(dateTime, r))
{
if (docStatus != null)
{
MPPOrder o = new MPPOrder(node.getCtx(), node.getPP_Order_ID(), node.get_TrxName());
if(!o.getDocStatus().equals(docStatus))
{
continue;
}
}
millis += calculateMillisForDay(dateTime, nodes[i], t);
millis += calculateMillisForDay(dateTime, node, t);
}
// Pre-converts to minutes, because its the lowest time unit of compiere
BigDecimal scale = new BigDecimal(1000*60);
BigDecimal minutes = new BigDecimal(millis).divide(scale, 2, BigDecimal.ROUND_HALF_UP);
return convert(minutes);
}
protected Timestamp[] getDayBorders(Timestamp dateTime, MPPOrderNode node, MResourceType t) {
Timestamp endDayTime = null;
/**
* Gets {StartDate, EndDate} times for given dateTime.
* 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 resource type's time slot value
if(t.isTimeSlot()) {
endDayTime = DateTimeUtil.getDayBorder(dateTime, t.getTimeSlotEnd(), true);
}
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.
Timestamp endDayTime = t.getDayEnd(dateTime);
// 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();
Timestamp startDayTime = null;
// The theoretical earliest time on a day, where the work begins, dependent on
// the resource type's time slot value
if(t.isTimeSlot()) {
startDayTime = DateTimeUtil.getDayBorder(dateTime, t.getTimeSlotStart(), false);
}
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.
Timestamp startDayTime = t.getDayStart(dateTime);
// Initialize the start time to the present, if the work begins at this day.
// Otherwise the latest possible start time for a day is set.
startDayTime = (startDayTime.after(node.getDateStartSchedule())) ? startDayTime : node.getDateStartSchedule();
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);
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);
names.put(parent, getTreeNodeRepresentation(null, parent, r));
DefaultMutableTreeNode child1 = null;
DefaultMutableTreeNode child2 = null;
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]);
parent.add(child1);
names.put(child1, getTreeNodeRepresentation(dateTime, child1, 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));
for(MPPOrderNode node : getPPOrderNodes(dateTime, r))
{
DefaultMutableTreeNode childNode = new DefaultMutableTreeNode(node);
childOrder.add(childNode);
names.put(childNode, getTreeNodeRepresentation(dateTime, childNode, r));
}
}
return names;
}
protected String getTreeNodeRepresentation(Timestamp dateTime, DefaultMutableTreeNode node, MResource r) {
private String getTreeNodeRepresentation(Timestamp dateTime, DefaultMutableTreeNode node, MResource r)
{
String name = null;
if(node.getUserObject() instanceof MResource) {
if(node.getUserObject() instanceof MResource)
{
MResource res = (MResource) node.getUserObject();
name = res.getName();
}
else if(node.getUserObject() instanceof Timestamp) {
else if(node.getUserObject() instanceof Timestamp)
{
Timestamp d = (Timestamp)node.getUserObject();
SimpleDateFormat df = Env.getLanguage(Env.getCtx()).getDateFormat();
name = df.format(d);
if(!isResourceAvailable(d, r)) {
if(!isAvailable(r, d))
{
name = "{"+name+"}";
}
}
else if(node.getUserObject() instanceof MPPOrder) {
else if(node.getUserObject() instanceof MPPOrder)
{
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()+")";
}
else if(node.getUserObject() instanceof MPPOrderNode) {
else if(node.getUserObject() instanceof MPPOrderNode)
{
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());
// no function
@ -270,19 +253,23 @@ public abstract class CRPDatasetFactory extends CRPReasoner implements CRPModel
return name;
}
protected BigDecimal getMaxRange(MResource r) {
return r.getDailyCapacity().divide(r.getPercentUtilization().divide(new BigDecimal(100)));
}
/**
* @return Daily Capacity * Utilization / 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() {
return dataset;
}
public CategoryDataset getDataset()
{
return dataset;
}
public JTree getTree() {
public JTree getTree()
{
return tree;
}
}

View File

@ -28,12 +28,10 @@ import org.jfree.data.category.CategoryDataset;
* @author Gunther Hoppe, tranSIT GmbH Ilmenau/Germany
* @version 1.0, October 14th 2005
*/
public interface CRPModel {
public JTree getTree();
public interface CRPModel
{
public JTree getTree();
public CategoryDataset getDataset();
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.util.Env;
import org.eevolution.form.tree.MapTreeCellRenderer;
import org.eevolution.model.MPPOrder;
import org.eevolution.model.MPPOrderNode;
@ -38,60 +36,60 @@ import org.eevolution.model.MPPOrderNode;
* @author Gunther Hoppe, tranSIT GmbH Ilmenau/Germany
* @version 1.0, October 14th 2005
*/
public class DiagramTreeCellRenderer extends MapTreeCellRenderer {
public DiagramTreeCellRenderer(HashMap map) {
public class DiagramTreeCellRenderer extends MapTreeCellRenderer
{
private static final long serialVersionUID = 1L;
public DiagramTreeCellRenderer(HashMap<?, ?> 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);
int y = getFont().getSize()/2;
g.drawLine(0, y, x1, y);
}
};
l.setFont(getFont());
return l;
}
return this;
}
@Override
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus)
{
Component c = 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) {
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("}");
}
protected ImageIcon getIcon(Object value) {
protected ImageIcon getIcon(Object value)
{
ImageIcon icon = null;
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");
}
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;