parent
786f6c1915
commit
377ff791cf
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue