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