📄 mschedule.java
字号:
/******************************************************************************
* The contents of this file are subject to the Compiere License Version 1.1
* ("License"); You may not use this file except in compliance with the License
* You may obtain a copy of the License at http://www.compiere.org/license.html
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
* the specific language governing rights and limitations under the License.
* The Original Code is Compiere ERP & CRM Business Solution
* The Initial Developer of the Original Code is Jorg Janke and ComPiere, Inc.
* Portions created by Jorg Janke are Copyright (C) 1999-2002 Jorg Janke, parts
* created by ComPiere are Copyright (C) ComPiere, Inc.; All Rights Reserved.
* Contributor(s): ______________________________________.
*****************************************************************************/
package org.compiere.model;
import java.sql.*;
import java.math.*;
import java.util.*;
import org.compiere.util.*;
/**
* Scheduling Utilities.
*
* @author Jorg Janke
* @version $Id: MSchedule.java,v 1.8 2003/02/24 04:34:55 jjanke Exp $
*/
public class MSchedule
{
/**
* Constructor
* @param ctx context
*/
public MSchedule (Properties ctx)
{
m_ctx = ctx;
} // MSchedule
private Properties m_ctx;
private int m_S_Resource_ID;
private boolean m_isAvailable = true;
private boolean m_isSingleAssignment = true;
private int m_S_ResourceType_ID = 0;
private int m_C_UOM_ID = 0;
private Timestamp m_startDate = null;
private Timestamp m_endDate = null;
/** Resource Type Name */
private String m_typeName = null;
/** Resource Type Start Time */
private Timestamp m_slotStartTime = null;
/** Resource Type End Time */
private Timestamp m_slotEndTime = null;
/** Time Slots */
private MAssignmentSlot[] m_timeSlots = null;
/** Begin Timestamp 1/1/1970 */
public static final Timestamp EARLIEST = new Timestamp(new GregorianCalendar(1970,1,1).getTimeInMillis());
/** End Timestamp 12/31/2070 */
public static final Timestamp LATEST = new Timestamp(new GregorianCalendar(2070,12,31).getTimeInMillis());
/*************************************************************************/
/**
* Get Assignments for timeframe.
* <pre>
* - Resource is Active and Available
* - Resource UnAvailability
* - NonBusinessDay
* - ResourceType Available
* </pre>
* @param S_Resource_ID resource
* @param start_Date start date
* @param end_Date optional end date, need to provide qty to calculate it
* @param qty optional qty in ResourceType UOM - ignored, if end date is not null
* @param getAll if true return all errors
* @return Array of existing Assigments or null - if free
*/
public MAssignmentSlot[] getAssignmentSlots (int S_Resource_ID,
Timestamp start_Date, Timestamp end_Date,
BigDecimal qty, boolean getAll)
{
Log.trace(Log.l4_Data, "MSchedule.getAssignmentSlots", start_Date);
if (m_S_Resource_ID != S_Resource_ID)
getBaseInfo (S_Resource_ID);
//
ArrayList list = new ArrayList();
MAssignmentSlot ma = null;
if (!m_isAvailable)
{
ma = new MAssignmentSlot (EARLIEST, LATEST,
Msg.getMsg (m_ctx, "ResourceNotAvailable"), "", MAssignmentSlot.STATUS_NotAvailable);
if (!getAll)
return new MAssignmentSlot[] {ma};
list.add(ma);
}
m_startDate = start_Date;
m_endDate = end_Date;
if (m_endDate == null)
m_endDate = TimeUtil.getEndDate(m_ctx, m_startDate, m_C_UOM_ID, qty);
Log.trace(Log.l5_DData, "- EndDate=" + m_endDate);
// Resource Unavailability -------------------------------------------
// Log.trace(Log.l6_Database, "- Unavailability -");
String sql = "SELECT Description, DateFrom, DateTo "
+ "FROM S_ResourceUnavailable "
+ "WHERE S_Resource_ID=?" // #1
+ " AND DateTo >= ?" // #2 start
+ " AND DateFrom <= ?" // #3 end
+ " AND IsActive='Y'";
try
{
// Log.trace(Log.l6_Database, sql, "ID=" + S_Resource_ID + ", Start=" + m_startDate + ", End=" + m_endDate);
PreparedStatement pstmt = DB.prepareStatement(sql);
pstmt.setInt(1, m_S_Resource_ID);
pstmt.setTimestamp(2, m_startDate);
pstmt.setTimestamp(3, m_endDate);
ResultSet rs = pstmt.executeQuery();
while (rs.next())
{
ma = new MAssignmentSlot (TimeUtil.getDay(rs.getTimestamp(2)),
TimeUtil.getNextDay(rs.getTimestamp(3)), // user entered date need to convert to not including end time
Msg.getMsg (m_ctx, "ResourceUnAvailable"), rs.getString(1),
MAssignmentSlot.STATUS_UnAvailable);
// Log.trace(Log.l6_Database, "- Unavailable", ma);
if (getAll)
createDaySlot (list, ma);
else
list.add(ma);
}
rs.close();
pstmt.close();
}
catch (SQLException e)
{
Log.error("MSchedule.getAssignmentSlots-2", e);
ma = new MAssignmentSlot (EARLIEST, LATEST,
Msg.getMsg (m_ctx, "ResourceUnAvailable"), e.toString(),
MAssignmentSlot.STATUS_UnAvailable);
}
if (ma != null && !getAll)
return new MAssignmentSlot[] {ma};
// NonBusinessDay ----------------------------------------------------
// Log.trace(Log.l6_Database, "- NonBusinessDay -");
// "WHERE TRUNC(Date1) BETWEEN TRUNC(?) AND TRUNC(?)" causes
// ORA-00932: inconsistent datatypes: expected NUMBER got TIMESTAMP
sql = Access.addROAccessSQL (m_ctx,
"SELECT Name, Date1 FROM C_NonBusinessDay "
+ "WHERE TRUNC(Date1) BETWEEN ? AND ?",
"C_NonBusinessDay", false);
try
{
Timestamp startDay = TimeUtil.getDay(m_startDate);
Timestamp endDay = TimeUtil.getDay(m_endDate);
// Log.trace(Log.l6_Database, sql, "Start=" + startDay + ", End=" + endDay);
PreparedStatement pstmt = DB.prepareStatement(sql);
pstmt.setTimestamp(1, startDay);
pstmt.setTimestamp(2, endDay);
ResultSet rs = pstmt.executeQuery();
while (rs.next())
{
ma = new MAssignmentSlot (TimeUtil.getDay(rs.getTimestamp(2)),
TimeUtil.getNextDay(rs.getTimestamp(2)), // user entered date need to convert to not including end time
Msg.getMsg(m_ctx, "NonBusinessDay"), rs.getString(1),
MAssignmentSlot.STATUS_NonBusinessDay);
Log.trace(Log.l6_Database, "- NonBusinessDay", ma);
list.add(ma);
}
rs.close();
pstmt.close();
}
catch (SQLException e)
{
Log.error("MSchedule.getAssignmentSlots-3", e);
ma = new MAssignmentSlot (EARLIEST, LATEST,
Msg.getMsg(m_ctx, "NonBusinessDay"), e.toString(),
MAssignmentSlot.STATUS_NonBusinessDay);
}
if (ma != null && !getAll)
return new MAssignmentSlot[] {ma};
// ResourceType Available --------------------------------------------
// Log.trace(Log.l6_Database, "- ResourceTypeAvailability -");
sql = "SELECT Name, IsTimeSlot,TimeSlotStart,TimeSlotEnd, " // 1..4
+ "IsDateSlot,OnMonday,OnTuesday,OnWednesday," // 5..8
+ "OnThursday,OnFriday,OnSaturday,OnSunday " // 9..12
+ "FROM S_ResourceType "
+ "WHERE S_ResourceType_ID=?";
try
{
PreparedStatement pstmt = DB.prepareStatement(sql);
pstmt.setInt(1, m_S_ResourceType_ID);
ResultSet rs = pstmt.executeQuery();
if (rs.next())
{
m_typeName = rs.getString(1);
// TimeSlot
if ("Y".equals(rs.getString(2)))
{
m_slotStartTime = TimeUtil.getDayTime (m_startDate, rs.getTimestamp(3));
m_slotEndTime = TimeUtil.getDayTime (m_endDate, rs.getTimestamp(4));
if (TimeUtil.inRange(m_startDate, m_endDate, m_slotStartTime, m_slotEndTime))
{
ma = new MAssignmentSlot (m_slotStartTime, m_slotEndTime,
Msg.getMsg(m_ctx, "ResourceNotInSlotTime"), m_typeName,
MAssignmentSlot.STATUS_NotInSlotTime);
if (getAll)
createTimeSlot (list,
rs.getTimestamp(3), rs.getTimestamp(4));
}
} // TimeSlot
// DaySlot
if ("Y".equals(rs.getString(5)))
{
if (TimeUtil.inRange(m_startDate, m_endDate,
"Y".equals(rs.getString(6)), "Y".equals(rs.getString(7)), // Mo..Tu
"Y".equals(rs.getString(8)), "Y".equals(rs.getString(9)), "Y".equals(rs.getString(10)), // We..Fr
"Y".equals(rs.getString(11)), "Y".equals(rs.getString(12))))
{
ma = new MAssignmentSlot (m_startDate, m_endDate,
Msg.getMsg(m_ctx, "ResourceNotInSlotDay"), m_typeName,
MAssignmentSlot.STATUS_NotInSlotDay);
if (getAll)
createDaySlot (list,
"Y".equals(rs.getString(6)), "Y".equals(rs.getString(7)), // Mo..Tu
"Y".equals(rs.getString(8)), "Y".equals(rs.getString(9)), "Y".equals(rs.getString(10)), // We..Fr
"Y".equals(rs.getString(11)), "Y".equals(rs.getString(12)));
}
} // DaySlot
}
rs.close();
pstmt.close();
}
catch (SQLException e)
{
Log.error("MSchedule.getAssignmentSlots-4", e);
ma = new MAssignmentSlot (EARLIEST, LATEST,
Msg.getMsg(m_ctx, "ResourceNotInSlotDay"), e.toString(),
MAssignmentSlot.STATUS_NonBusinessDay);
}
if (ma != null && !getAll)
return new MAssignmentSlot[] {ma};
// Assignments -------------------------------------------------------
sql = "SELECT S_ResourceAssignment_ID "
+ "FROM S_ResourceAssignment "
+ "WHERE S_Resource_ID=?" // #1
+ " AND AssignDateTo >= ?" // #2 start
+ " AND AssignDateFrom <= ?" // #3 end
+ " AND IsActive='Y'";
try
{
PreparedStatement pstmt = DB.prepareStatement(sql);
pstmt.setInt(1, m_S_Resource_ID);
pstmt.setTimestamp(2, m_startDate);
pstmt.setTimestamp(3, m_endDate);
ResultSet rs = pstmt.executeQuery();
while (rs.next())
{
MAssignment mAssignment = new MAssignment(Env.getCtx(), rs.getInt(1));
ma = new MAssignmentSlot (mAssignment);
if (!getAll)
break;
list.add(ma);
}
rs.close();
pstmt.close();
}
catch (SQLException e)
{
Log.error("MSchedule.getAssignmentSlots-5", e);
ma = new MAssignmentSlot (EARLIEST, LATEST,
Msg.translate(m_ctx, "S_R"), e.toString(),
MAssignmentSlot.STATUS_NotConfirmed);
}
if (ma != null && !getAll)
return new MAssignmentSlot[] {ma};
/*********************************************************************/
// fill m_timeSlots (required for layout)
createTimeSlots();
// Clean list - date range
ArrayList clean = new ArrayList(list.size());
for (int i = 0; i < list.size(); i++)
{
MAssignmentSlot mas = (MAssignmentSlot)list.get(i);
if ((mas.getStartTime().equals(m_startDate) || mas.getStartTime().after(m_startDate))
&& (mas.getEndTime().equals(m_endDate) || mas.getEndTime().before(m_endDate)))
clean.add(mas);
}
// Delete Unavailability TimeSlots when all day assigments exist
MAssignmentSlot[] sorted = new MAssignmentSlot[clean.size()];
clean.toArray(sorted);
Arrays.sort(sorted, new MAssignmentSlot()); // sorted by start/end date
list.clear(); // used as day list
clean.clear(); // cleaned days
Timestamp sortedDay = null;
for (int i = 0; i < sorted.length; i++)
{
if (sortedDay == null)
sortedDay = TimeUtil.getDay(sorted[i].getStartTime());
if (sortedDay.equals(TimeUtil.getDay(sorted[i].getStartTime())))
list.add(sorted[i]);
else
{
// process info list -> clean
layoutSlots (list, clean);
// prepare next
list.clear();
list.add(sorted[i]);
sortedDay = TimeUtil.getDay(sorted[i].getStartTime());
}
}
// process info list -> clean
layoutSlots (list, clean);
// Return
MAssignmentSlot[] retValue = new MAssignmentSlot[clean.size()];
clean.toArray(retValue);
Arrays.sort(retValue, new MAssignmentSlot()); // sorted by start/end date
return retValue;
} // getAssignmentSlots
/**
* Copy valid Slots of a day from list to clear and layout
* @param list list with slos of the day
* @param clean list with only valid slots
*/
private void layoutSlots (ArrayList list, ArrayList clean)
{
int size = list.size();
// System.out.println("Start List=" + size + ", Clean=" + clean.size());
if (size == 0)
return;
else if (size == 1)
{
MAssignmentSlot mas = (MAssignmentSlot)list.get(0);
layoutY (mas);
clean.add (mas);
return;
}
// Delete Unavailability TimeSlots when all day assigments exist
boolean allDay = false;
for (int i = 0; !allDay && i < size; i++)
{
MAssignmentSlot mas = (MAssignmentSlot)list.get(i);
if (mas.getStatus() == MAssignmentSlot.STATUS_NotAvailable
|| mas.getStatus() == MAssignmentSlot.STATUS_UnAvailable
|| mas.getStatus() == MAssignmentSlot.STATUS_NonBusinessDay
|| mas.getStatus() == MAssignmentSlot.STATUS_NotInSlotDay)
allDay = true;
}
if (allDay)
{
// delete Time Slot
for (int i = 0; i < list.size(); i++)
{
MAssignmentSlot mas = (MAssignmentSlot)list.get(i);
if (mas.getStatus() == MAssignmentSlot.STATUS_NotInSlotTime)
list.remove(i--);
}
}
// Copy & Y layout remaining
for (int i = 0; i < list.size(); i++)
{
MAssignmentSlot mas = (MAssignmentSlot)list.get(i);
layoutY (mas);
clean.add (mas);
}
// X layout
int maxYslots = m_timeSlots.length;
int[] xSlots = new int[maxYslots]; // number of parallel slots
for (int i = 0; i < list.size(); i++)
{
MAssignmentSlot mas = (MAssignmentSlot)list.get(i);
for (int y = mas.getYStart(); y < mas.getYEnd(); y++)
xSlots[y]++;
}
// Max parallel X Slots
int maxXslots = 0;
for (int y = 0; y < xSlots.length; y++)
{
if (xSlots[y] > maxXslots)
maxXslots = xSlots[y];
}
// Only one column
if (maxXslots < 2)
{
for (int i = 0; i < list.size(); i++)
{
MAssignmentSlot mas = (MAssignmentSlot)list.get(i);
mas.setX(0, 1);
}
return;
}
// Create xy Matrix
ArrayList[][] matrix = new ArrayList[maxXslots][maxYslots];
// Populate Matrix first column
for (int y = 0; y < maxYslots; y++)
{
ArrayList xyList = new ArrayList();
matrix[0][y] = xyList;
// see if one assignment fits into slot
for (int i = 0; i < list.size(); i++)
{
MAssignmentSlot mas = (MAssignmentSlot)list.get(i);
if (y >= mas.getYStart() && y <= mas.getYEnd())
xyList.add(mas);
}
// initiate right columns
for (int x = 1; x < maxXslots; x++)
matrix[x][y] = new ArrayList();
} // for all y slots
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -