Files
ayanova7/source/bizobjects/AyaLib/GZTW.AyaNova.BLL/AppointmentList.cs
2018-06-29 19:47:36 +00:00

693 lines
25 KiB
C#

///////////////////////////////////////////////////////////
// AppointmentList.cs
// Implementation of Class AppointmentList
// CSLA type: Read only collection
// Created on: 06-Jan-2005
// Object design: John
// Coded: 06-Jan-2005
///////////////////////////////////////////////////////////
using System;
using System.Data;
using GZTW.Data;
using CSLA.Data;
using CSLA;
using System.Text.RegularExpressions;
using System.Threading;
using CSLA.Security;
namespace GZTW.AyaNova.BLL
{
/// <summary>
/// A list of appointments for scheduleable users in AyaNova
/// This list is what populates the schedule calendar
///
/// (Read only collection )
/// </summary>
[Serializable]
public class AppointmentList : ReadOnlyCollectionBase
{
#region Data structure
/// <summary>
///
/// </summary>
[Serializable]
public struct AppointmentListInfo
{
//used to indicate there is nothing in this
//struct
internal bool mIsEmpty;
internal Guid mWorkorderID;
internal Guid mWorkorderItemID;
internal int mServiceNumber;
internal RootObjectTypes mAppliesToObjectType;
internal Guid mAppliesToObjectID;
internal RootObjectTypes mSourceObjectType;
//This is the workorderitemscheduleduser record ID
internal Guid mSourceObjectID;
internal string mSubject;
internal string mDetails;
internal DateTime mStartDateTime;
internal DateTime mEndDateTime;
internal bool mAllDay;
//If
internal bool mShowPriorityFlag;
internal int mPriorityARGB;
internal int mBackColorARGB;
#pragma warning disable 1591
/// <summary>
/// true if there is nothing in this record
/// false if this record contains a valid appointment
/// </summary>
public bool IsEmpty {get{return mIsEmpty;}set{mIsEmpty=value;}}
/// <summary>
/// What object type this appointment applies to, can be single user
/// or another object type that represents a group of users
/// such as: region, sched user group etc etc
/// </summary>
public RootObjectTypes AppliesToObjectType{get{return mAppliesToObjectType;}}
/// <summary>
/// Object ID appointment applies to
/// </summary>
public Guid AppliesToObjectID{get{return mAppliesToObjectID;}}
/// <summary>
/// Type of appointment
/// either ScheduleMarker or WorkorderItemScheduledUser
/// </summary>
public RootObjectTypes SourceObjectType{get{return mSourceObjectType;}}
/// <summary>
/// The ID of the schedulemarker or workorderitemscheduleduser object
/// </summary>
public Guid SourceObjectID {get{return mSourceObjectID;}}
/// <summary>
/// ID of workorder if this appointment is a scheduled workorder user
/// </summary>
public Guid WorkorderID {get{return mWorkorderID;}}
/// <summary>
/// ID of workorder item if this appointment is a scheduled workorder user
/// </summary>
public Guid WorkorderItemID {get{return mWorkorderItemID;}}
/// <summary>
/// Visible sequential workorder number of workorder
/// if this appointment is a scheduled workorder user
/// </summary>
public int ServiceNumber {get{return mServiceNumber;}}
/// <summary>
/// Description of appointment, either a schedulemarker
/// description or a summary of the workorder
/// formatted according to the workorder
/// </summary>
public string Subject {get{return mSubject;}}
public string Details {get{return mDetails;}}
public DateTime StartDateTime {get{return mStartDateTime;}}
public DateTime EndDateTime {get{return mEndDateTime;}}
public bool AllDay {get{return mAllDay;}}
public int PriorityARGB {get{return mPriorityARGB;}}
public bool ShowPriorityFlag {get{return mShowPriorityFlag;}}
/// <summary>
/// Back color of appointment
/// could be workorder status or schedmarker colour
/// </summary>
public int BackColorARGB {get{return mBackColorARGB;} }
#pragma warning restore 1591
/// <summary>
///
/// </summary>
/// <param name="obj"></param>
public bool Equals(AppointmentListInfo obj)
{
return this.mSourceObjectID.Equals(obj.mSourceObjectID);
}
}//end AppointmentListInfo
#endregion
#region Constructor
/// <summary>
///
/// </summary>
protected AppointmentList()
{
// AllowSort=false;
// AllowFind=true;
// AllowEdit=false;
// AllowNew=false;
// AllowRemove=false;
}
#endregion
#region Business properties and methods
/// <summary>
/// Get item by index
/// </summary>
/// <param name="Item"></param>
public AppointmentListInfo this[int Item]
{
get
{
return (AppointmentListInfo) List[Item];
}
}
/// <summary>
/// Returns AppointmentListInfo item that matches passed in itemid value
/// </summary>
/// <param name="o"></param>
public AppointmentListInfo this[Guid o]
{
get
{
foreach (AppointmentListInfo child in List)
{
if(child.mSourceObjectID==o) return child;
}
throw new ArgumentException("AppointmentList: SourceObjectID not found\r\n");
}
}
#endregion
#region contains
/// <summary>
/// Check if item in collection
/// </summary>
/// <param name="obj"></param>
public bool Contains(AppointmentListInfo obj)
{
foreach (AppointmentListInfo child in List)
{
if(child.Equals(obj)) return true;
}
return false;
}
#endregion
#region Static methods
/// <summary>
/// Get list of <see cref="AppointmentListInfo"/> objects.
/// If UserID==Guid.Empty then all appointments for all
/// active scheduleable users are returned.
///
/// If UserID set to an Active *and* scheduleable specific user id then all workorders
/// for that specific user only are returned as well as
/// all <see cref="ScheduleMarker"/> for all users (since the UI has to
/// determine if they are applicable or not as some are not
/// for any specific user at all).
///
/// Closed work orders are *not* returned by default, use GetListWithClosed for that
/// behaviour.
///
/// </summary>
/// <param name="Start">Start date and time</param>
/// <param name="End">End date and time</param>
/// <param name="UserID">A <see cref="User"/> ID for a specific user's appointments
/// or Guid.Empty for all user's appointments</param>
/// <returns>A read only collection of <see cref="AppointmentListInfo"/> objects (ScheduleMarkers and WorkorderItemScheduledUser data)</returns>
public static AppointmentList GetList(DateTime Start, DateTime End, Guid UserID)
{
if (Start == DateTime.MinValue || End == DateTime.MinValue)
return new AppointmentList();
return (AppointmentList) DataPortal.Fetch(new Criteria(Start,End, UserID, false));
}
/// <summary>
/// Same as GetList, but includes closed work orders as well.
/// </summary>
/// <param name="Start"></param>
/// <param name="End"></param>
/// <param name="UserID"></param>
/// <returns></returns>
public static AppointmentList GetListWithClosed(DateTime Start, DateTime End, Guid UserID)
{
if (Start == DateTime.MinValue || End == DateTime.MinValue)
return new AppointmentList();
return (AppointmentList)DataPortal.Fetch(new Criteria(Start, End, UserID, true));
}
#endregion
#region DAL DATA ACCESS
///
/// <param name="Criteria"></param>
protected override void DataPortal_Fetch(object Criteria)
{
string strTemplate="";
//case 1705
System.Collections.Generic.List<string> ListOfAppointmentSubjects = new System.Collections.Generic.List<string>();
//We set global settings during login, but
//a 3rd party user of this lib might not, so if the global object is not set then
//we'll retrieve it here, this provides some insurance
if(AyaBizUtils.GlobalSettings!=null)
strTemplate=AyaBizUtils.GlobalSettings.WorkorderSummaryTemplate;
else
strTemplate=Global.GetItem().WorkorderSummaryTemplate;
if(strTemplate==null || strTemplate=="")
{
strTemplate="WO#: [WorkorderService.Label.ServiceNumber]\r\n (You can customize the information displayed here\r\n in Global Settings workorder summary template)";
}
Criteria crit = (Criteria)Criteria;
SafeDataReader dr = null;
UserListScheduleable ulist=UserListScheduleable.GetList();
try
{
#region appointments
string q = "SELECT aWorkorderItemScheduledUser.aStartDate, aWorkorderItemScheduledUser.aStopDate, " +
" aWorkorderItemScheduledUser.aUserID, " +
" aWorkorderService.aServiceNumber, " +
" aWorkorderItem.aWorkorderID, aWorkorderItemScheduledUser.aWorkorderItemID, " +
" aWorkorderItem.aTechNotes, " +
" aWorkorderStatus.AARGB AS aStatusARGB, aWorkorderItem.aWorkorderStatusID, " +
" aWorkorderItem.aPriorityID, " +
" aPriority.AARGB AS aPriorityARGB, aWorkorderItemScheduledUser.aID " +
"AS aSCHEDITEMID, aClient.aName " +
"AS aCLIENTNAME, aWorkorder.aCustomerContactName, " +
" aWorkorder.aCustomerReferenceNumber, aWorkorder.aInternalReferenceNumber, aWorkorder.aOnsite, " +//case 987
" aProject.aName AS aPROJECTNAME, " +
" aWorkorder.aSummary AS aWORKORDERSUMMARY, " +
" aWorkorderCategory.aName AS aWORKORDERCATEGORYNAME, " +
" aWorkorderService.aInvoiceNumber, aWorkorderItem.aRequestDate, " +
" aWorkorderItem.aSummary AS aWORKORDERITEMSUMMARY, " +
" aUnit.aSerial, aUnitModel.aName " +
"AS aUNITMODELNAME, aUnitModelCategory.aName AS aUNITMODELCATEGORYNAME, " +
" aWorkorderStatus.aName AS aWORKORDERITEMSTATUSNAME, " +
" aDispatchZone.aName AS aDISPATCHZONENAME, " +
" aVendor.aName AS aUNITMODELVENDORNAME, " +
" aWorkorder.aWorkorderType FROM aWorkorderItemScheduledUser " +
"inner JOIN ( aWorkorder INNER JOIN aWorkorderService " +
"ON aWorkorder.aID = aWorkorderService.aWorkorderID " +
"INNER JOIN aWorkorderItem ON aWorkorder.aID " +
"= aWorkorderItem.aWorkorderID LEFT JOIN " +
"aUnit ON aWorkorderItem.aUnitID = aUnit.aID LEFT JOIN " +
"aUnitModel ON aUnit.aUnitModelID = aUnitModel.aID " +
"LEFT JOIN aVendor ON aUnitModel.aVendorID = aVendor.aID " +
"LEFT JOIN aUnitModelCategory ON aUnitModel.aUnitModelCategoryID " +
"= aUnitModelCategory.aID LEFT " +
"JOIN aWorkorderCategory ON aWorkorder.aWorkorderCategoryID " +
"= aWorkorderCategory.aID LEFT JOIN aProject " +
"ON aWorkorder.aProjectID = aProject.aID LEFT " +
"JOIN aClient ON aWorkorder.aClientID = aClient.aID " +
"LEFT JOIN aDispatchZone ON aClient.aDispatchZoneID " +
"= aDispatchZone.aID LEFT JOIN aPriority ON aWorkorderItem.aPriorityID " +
"= aPriority.aID LEFT JOIN " +
"aWorkorderStatus ON aWorkorderItem.aWorkorderStatusID " +
"= aWorkorderStatus.aID ) ON aWorkorderItem.aID " +
"= aWorkorderItemScheduledUser.aWorkorderItemID " +
"WHERE (aWorkorder.aWorkorderType=1) AND " +
"(NOT((aWorkorderItemScheduledUser.aStopDate < @StartDateTime) or (aWorkorderItemScheduledUser.aStartDate > @EndDateTime)))"; //case 1075
//"(aWorkorderItemScheduledUser.aStartDate > @StartDateTime) AND (aWorkorderItemScheduledUser.aStartDate < @EndDateTime) ";
if (crit.UserID != Guid.Empty)
q = q + "AND (aWorkorderItemScheduledUser.aUserID=@UserID) ";
//case 540
if (crit.IncludeClosed == false)
q = q + "AND (aWorkorder.aClosed=@False) ";
//Case 58
if (User.CurrentUserRegionID != Region.DefaultRegionID)
{
//wrong, what about clients in all regions?
// q = q + " AND (aClient.aRegionID = '{" + User.CurrentUserRegionID.ToString().ToUpperInvariant() + "}') ";
q = q + DBUtil.RegionAClientClause;//case 1117
}
DBCommandWrapper cm = DBUtil.DB.GetSqlStringCommandWrapper(q);
//Add parameters
if (crit.UserID != Guid.Empty)
cm.AddInParameter("@UserID", DbType.Guid, crit.UserID);
if (crit.IncludeClosed == false)
cm.AddInParameter("@False", DbType.Boolean, false);
cm.AddInParameter("@StartDateTime", DbType.DateTime, DBUtil.ToUTC(crit.Start));
cm.AddInParameter("@EndDateTime", DbType.DateTime, DBUtil.ToUTC(crit.End));
dr=new SafeDataReader(DBUtil.DB.ExecuteReader(cm));
//First result: Workorder item scheduled users
while (dr.Read())
{
//screen the user to make sure they are scheduleable and active
//If not, skip 'em
if(dr.GetGuid("aUserID")!=Guid.Empty)//is it a user?
{
if(!ulist.ContainsActiveUser(dr.GetGuid("aUserID")))
continue;
}
AppointmentListInfo info=new AppointmentListInfo();
info.mAllDay=false;
info.mIsEmpty=false;
info.mAppliesToObjectType=RootObjectTypes.User;
info.mAppliesToObjectID=dr.GetGuid("aUserID");
info.mSourceObjectType=RootObjectTypes.WorkorderItemScheduledUser;
info.mSourceObjectID=dr.GetGuid("aSCHEDITEMID");
info.mWorkorderID=dr.GetGuid("aWorkorderID");
info.mWorkorderItemID=dr.GetGuid("aWorkorderItemID");
info.mServiceNumber=dr.GetInt32("aServiceNumber");
//Not used currently, all data goes into subject
info.mDetails="";
//Copy template to subject
info.mSubject=strTemplate;
//case 1705
//need unique subject guaranteed for case 1705
string UniqueSubject = info.mSubject;
int n = 0;
while (ListOfAppointmentSubjects.Contains(UniqueSubject))
{
n++;
UniqueSubject = info.mSubject + " (" + n.ToString() + ")";
}
if (info.mSubject != UniqueSubject)
{
info.mSubject = UniqueSubject;
}
//Match all keywords and substitute queried data for them
MatchCollection matches=Regex.Matches(strTemplate,@"\[(.|\n)*?\]",RegexOptions.IgnorePatternWhitespace
| RegexOptions.Compiled);
foreach(Match KeyMatch in matches)
{
switch(KeyMatch.Value)
{
case "[O.Client]":
info.mSubject=info.mSubject.Replace(KeyMatch.Value,dr.GetString("aCLIENTNAME"));
break;
case "[Workorder.Label.CustomerContactName]":
info.mSubject=info.mSubject.Replace(KeyMatch.Value,dr.GetString("aCustomerContactName"));
break;
case "[Workorder.Label.CustomerReferenceNumber]":
info.mSubject=info.mSubject.Replace(KeyMatch.Value,dr.GetString("aCustomerReferenceNumber"));
break;
case "[Workorder.Label.InternalReferenceNumber]":
info.mSubject=info.mSubject.Replace(KeyMatch.Value,dr.GetString("aInternalReferenceNumber"));
break;
//case 987
case "[Workorder.Label.Onsite]":
info.mSubject = info.mSubject.Replace(KeyMatch.Value, dr.GetBoolean("aOnsite").ToString());
break;
case "[O.Project]":
info.mSubject=info.mSubject.Replace(KeyMatch.Value,dr.GetString("aPROJECTNAME"));
break;
case "[Workorder.Label.Summary]":
info.mSubject=info.mSubject.Replace(KeyMatch.Value,dr.GetString("aWORKORDERSUMMARY"));
break;
case "[O.WorkorderCategory]":
info.mSubject=info.mSubject.Replace(KeyMatch.Value,dr.GetString("aWORKORDERCATEGORYNAME"));
break;
case "[WorkorderService.Label.InvoiceNumber]":
info.mSubject=info.mSubject.Replace(KeyMatch.Value,dr.GetString("aInvoiceNumber"));
break;
case "[WorkorderService.Label.ServiceNumber]":
info.mSubject=info.mSubject.Replace(KeyMatch.Value,dr.GetInt32("aServiceNumber").ToString());
break;
case "[WorkorderItem.Label.RequestDate]":
info.mSubject=info.mSubject.Replace(KeyMatch.Value,DBUtil.ToLocal(dr.GetSmartDate("aRequestDate")).ToString());
break;
case "[WorkorderItem.Label.Summary]":
info.mSubject=info.mSubject.Replace(KeyMatch.Value,dr.GetString("aWORKORDERITEMSUMMARY"));
break;
case "[WorkorderItem.Label.TechNotes]":
info.mSubject=info.mSubject.Replace(KeyMatch.Value,dr.GetString("aTechNotes"));
break;
case "[O.Unit]":
info.mSubject=info.mSubject.Replace(KeyMatch.Value,dr.GetString("aSerial"));
break;
case "[O.UnitModel]":
info.mSubject=info.mSubject.Replace(KeyMatch.Value,dr.GetString("aUNITMODELNAME"));
break;
case "[O.UnitModelCategory]":
info.mSubject=info.mSubject.Replace(KeyMatch.Value,dr.GetString("aUNITMODELCATEGORYNAME"));
break;
case "[O.Vendor]":
info.mSubject=info.mSubject.Replace(KeyMatch.Value,dr.GetString("aUNITMODELVENDORNAME"));
break;
case "[O.WorkorderStatus]":
info.mSubject=info.mSubject.Replace(KeyMatch.Value,dr.GetString("aWORKORDERITEMSTATUSNAME"));
break;
case "[O.DispatchZone]":
info.mSubject=info.mSubject.Replace(KeyMatch.Value,dr.GetString("aDISPATCHZONENAME"));
break;
case "[WorkorderItemScheduledUser.Label.StartDate]":
info.mSubject=info.mSubject.Replace(KeyMatch.Value,DBUtil.ToLocal(dr.GetSmartDate("aStartDate")).ToString());
break;
case "[WorkorderItemScheduledUser.Label.StopDate]":
info.mSubject=info.mSubject.Replace(KeyMatch.Value,DBUtil.ToLocal(dr.GetSmartDate("aStopDate")).ToString());
break;
case "[O.WorkorderItemScheduledUser]":
if(dr.GetGuid("aUserID")!=Guid.Empty)
info.mSubject=info.mSubject.Replace(KeyMatch.Value,ulist[dr.GetGuid("aUserID")].Name(AyaBizUtils.GlobalSettings.DefaultScheduleableUserNameDisplayFormat));
else
info.mSubject=info.mSubject.Replace(KeyMatch.Value,"-?-");
break;
}
}
info.mEndDateTime=DBUtil.ToLocal(dr.GetDateTime("aStopDate"));
info.mStartDateTime=DBUtil.ToLocal(dr.GetDateTime("aStartDate"));
//Added:30-Oct-2006 for wbi infra schedule seems to ignore times exactly
//at midnight
//if (info.mEndDateTime.Hour == 12 && info.mEndDateTime.Minute == 0 && info.mEndDateTime.Second == 0)
// info.mEndDateTime.AddSeconds(-59);
//if (info.mStartDateTime.Hour == 0 && info.mStartDateTime.Minute == 0 && info.mStartDateTime.Second == 0)
// info.mStartDateTime.AddSeconds(59);
if(dr.GetGuid("aPriorityID")!=Guid.Empty)
{
info.mPriorityARGB=dr.GetInt32("aPriorityARGB");
info.mShowPriorityFlag=true;
}
else
{
info.mPriorityARGB=0;
info.mShowPriorityFlag=false;
}
//Workorder status color
info.mBackColorARGB=dr.GetInt32("aStatusARGB");
// info.mBold=dr.GetBoolean("aBold");
// info.mUnderline=dr.GetBoolean("aUnderline");
InnerList.Add(info);
}
if(dr!=null) dr.Close();
#endregion appointments
#region Schedule markers
//Not filtered by user if specific user is specified which is what we want
//next query
DBCommandWrapper cmSM = DBUtil.DB.GetSqlStringCommandWrapper(
"SELECT aScheduleMarkerSourceType, aSourceID,aID,aNotes,aName, " +
"aStopDate,aStartDate, AARGB FROM aScheduleMarker " +
"WHERE (NOT((aStopDate < @StartDateTime) or (aStartDate > @EndDateTime)))" //case 1075
//"WHERE aScheduleMarker.aStartDate BETWEEN @StartDateTime AND @EndDateTime"
);
//Add parameters
cmSM.AddInParameter("@StartDateTime",DbType.DateTime,DBUtil.ToUTC(crit.Start));
cmSM.AddInParameter("@EndDateTime",DbType.DateTime,DBUtil.ToUTC(crit.End));
dr=new SafeDataReader(DBUtil.DB.ExecuteReader(cmSM));
while (dr.Read())
{
AppointmentListInfo info=new AppointmentListInfo();
info.mAllDay=false;
info.mIsEmpty=false;
ScheduleMarkerSourceTypes smt=(ScheduleMarkerSourceTypes)dr.GetInt16("aScheduleMarkerSourceType");
info.mAppliesToObjectID = dr.GetGuid("aSourceID");
switch(smt)
{
case ScheduleMarkerSourceTypes.User:
info.mAppliesToObjectType=RootObjectTypes.User;
//screen the user to make sure they are scheduleable and active
//If not, skip 'em
if(dr.GetGuid("aSourceID")!=Guid.Empty &&
dr.GetGuid("aSourceID")!=ScheduleMarker.ScheduleMarkerGlobalSourceID)//is it a user?
{
if(!ulist.ContainsActiveUser(dr.GetGuid("aSourceID")))
continue;
}
break;
case ScheduleMarkerSourceTypes.Regional:
//Case 58
//If it applies to a specific region besides default and the current user is not default region and the applies to region id is not
//the current users then don't show it
if ((info.mAppliesToObjectID!=Region.DefaultRegionID) && (User.CurrentUserRegionID != Region.DefaultRegionID) && info.mAppliesToObjectID != User.CurrentUserRegionID)
continue;
info.mAppliesToObjectType=RootObjectTypes.Region;
break;
case ScheduleMarkerSourceTypes.Global:
info.mAppliesToObjectType=RootObjectTypes.Global;
break;
case ScheduleMarkerSourceTypes.DispatchZone:
info.mAppliesToObjectType=RootObjectTypes.DispatchZone;
break;
case ScheduleMarkerSourceTypes.ScheduleableUserGroup:
info.mAppliesToObjectType=RootObjectTypes.ScheduleableUserGroup;
break;
}
info.mSourceObjectType=RootObjectTypes.ScheduleMarker;
info.mSourceObjectID=dr.GetGuid("aID");
info.mDetails=dr.GetString("aNotes");
info.mSubject=dr.GetString("aName");
info.mEndDateTime=DBUtil.ToLocal(dr.GetDateTime("aStopDate"));
info.mStartDateTime=DBUtil.ToLocal(dr.GetDateTime("aStartDate"));
//priority doesn't apply here, but don't
//leave it dangling
info.mShowPriorityFlag=false;
info.mPriorityARGB=0;
info.mBackColorARGB=dr.GetInt32("AARGB");
InnerList.Add(info);
}
#endregion schedulemarkers
}
finally
{
if(dr!=null) dr.Close();
}
}
#endregion
#region criteria
/// <summary>
/// Criteria for identifying existing object
/// </summary>
[Serializable]
private class Criteria
{
public DateTime Start;
public DateTime End;
public Guid UserID;
public bool IncludeClosed;//Added case 540
public Criteria(DateTime _Start, DateTime _End, Guid _UserID, bool _IncludeClosed)
{
Start = _Start;
End = _End;
UserID = _UserID;
IncludeClosed = _IncludeClosed;
}
}
#endregion
}//end AppointmentList
}//end namespace GZTW.AyaNova.BLL