/////////////////////////////////////////////////////////// // WorkorderItemScheduledUser.cs // Implementation of Class WorkorderItemScheduledUser // CSLA type: Editable Child // Created on: 07-Jun-2004 8:41:50 AM // Object design: Joyce // Coded: John 26-July-2004 /////////////////////////////////////////////////////////// using System; using System.Data; using CSLA.Data; using GZTW.Data; using CSLA; using System.Threading; using CSLA.Security; using System.ComponentModel; namespace GZTW.AyaNova.BLL { /// /// ScheduledUser object for object's collection /// [Serializable] public class WorkorderItemScheduledUser : BusinessBase { #region Attributes private bool bReadOnly; private Guid mID; private SmartDate mCreated; private SmartDate mModified; private Guid mCreator; private Guid mModifier; private decimal mEstimatedQuantity; private Guid mWorkorderItemID; private Guid mUserID; private SmartDate mStartDate; private SmartDate mStopDate; private Guid mServiceRateID; private bool mNotificationAffectingChangesMade=false; #endregion #region Constructor /// /// Private constructor to prevent direct instantiation /// private WorkorderItemScheduledUser() { //Set to read / write initially so that properties //can be set bReadOnly=false; //Child object MarkAsChild(); //New ID mID = Guid.NewGuid(); //Set defaults and pre break the validity rules mStartDate=new SmartDate(); mStopDate=new SmartDate(); UserID=Guid.Empty; //Set record history to defaults mCreated = new SmartDate(DBUtil.CurrentWorkingDateTime); mModified=new SmartDate(); mCreator=Guid.Empty; mModifier=Guid.Empty; } #endregion #region Business properties /// /// Get internal id number Read only property because it's set internally, not /// externally /// public Guid ID { get { return mID; } } /// /// Get created date /// /// /// public string Created { get { return mCreated.ToString(); } } /// /// Get modified date /// /// /// public string Modified { get { return mModified.ToString(); } } /// /// Get user record ID of person who created this record /// /// /// public Guid Creator { get { return mCreator; } } /// /// Get user ID of person who modified this record /// /// /// public Guid Modifier { get { return mModifier; } } /// /// /// Empty ID indicates there is a scheduled time slot but no active user yet otherwise /// this contains the ID of the scheduled /// /// public Guid UserID { get { return mUserID; } set { if(bReadOnly) ThrowSetError(); else { if(mUserID!=value) { mUserID = value; CheckComplete(); //not empty Start date is not valid without stop date BrokenRules.Assert( "ValidUserRequired", "User.Label.ErrorNotSelectable", "UserID", this.IsNew && !ScheduleableUserCanSelect.GetItem(value)); MarkDirty(); mNotificationAffectingChangesMade=true; } } } } /// /// Estimated amount of minutes that technician service would be required. Useful /// when no Scheduled daterange specified and tech needs to determine when best to /// slot in /// public decimal EstimatedQuantity { get { return mEstimatedQuantity; } set { if(bReadOnly) ThrowSetError(); else { if(mEstimatedQuantity!=value) { mEstimatedQuantity = value; MarkDirty(); } } } } /// /// Starting date and time /// public object StartDate { get { return mStartDate.DBValue; } set { if(bReadOnly) ThrowSetError(); else { if (!AyaBizUtils.SmartDateEquals(mStartDate, value)) //Case 298 { mStartDate.DBValue = value; //case 1392 //if it's a new record and it's a date other than today and it's not empty //and the global schedusernontodaystarttime is not empty //and the time is exactly midnight down to the millisecond //then adjust time to global default start time for this situation SmartDate sd = new SmartDate(); sd.Text = AyaBizUtils.GlobalSettings.SchedUserNonTodayStartTime; if (this.IsNew && !mStartDate.IsEmpty && !AyaBizUtils.DateIsToday(mStartDate) && !sd.IsEmpty && (mStartDate.Date.TimeOfDay == DateTime.Today.TimeOfDay)) mStartDate.Date = new DateTime(mStartDate.Date.Year, mStartDate.Date.Month, mStartDate.Date.Day, sd.Date.Hour, sd.Date.Minute, sd.Date.Second); //autocomplete time if(!mStartDate.IsEmpty && mStopDate.IsEmpty && (AyaBizUtils.GlobalSettings.LaborSchedUserDfltTimeSpan!=0)) mStopDate.Date = mStartDate.Date.AddMinutes(AyaBizUtils.GlobalSettings.LaborSchedUserDfltTimeSpan);//case 816 CheckComplete(); //not empty Start date is not valid without stop date BrokenRules.Assert("StopDateRequired","Error.Object.RequiredFieldEmpty,WorkorderItemScheduledUser.Label.StopDate","StartDate",!mStartDate.IsEmpty && mStopDate.IsEmpty); //Is stop date valid now? BrokenRules.Assert("StartDateRequired","Error.Object.RequiredFieldEmpty,WorkorderItemScheduledUser.Label.StartDate","StopDate",!mStopDate.IsEmpty && mStartDate.IsEmpty); if(!mStopDate.IsEmpty&&!mStartDate.IsEmpty) { BrokenRules.Assert("StartDateBeforeStopDate","Error.Object.StartDateAfterEndDate", "StartDate",mStartDate.CompareTo(mStopDate)>-1); } MarkDirty(); mNotificationAffectingChangesMade=true; } } } } /// /// Ending date and time /// public object StopDate { get { return mStopDate.DBValue; } set { if(bReadOnly) ThrowSetError(); else { if (!AyaBizUtils.SmartDateEquals(mStopDate, value)) //Case 298 { mStopDate.DBValue = value; //autocomplete time if (!mStopDate.IsEmpty && mStartDate.IsEmpty && (AyaBizUtils.GlobalSettings.LaborSchedUserDfltTimeSpan != 0))//case 816 mStartDate.Date = mStopDate.Date.AddMinutes(-AyaBizUtils.GlobalSettings.LaborSchedUserDfltTimeSpan); CheckComplete(); //Not empty Stop date is not valid without start date BrokenRules.Assert("StartDateRequired","Error.Object.RequiredFieldEmpty,WorkorderItemScheduledUser.Label.StartDate","StopDate",!mStopDate.IsEmpty && mStartDate.IsEmpty); //Rule needs to be checked here even though it's to do with start date because it can be broken //there but can only be unbroken here so it needs to be checked in both places... //Is start date valid now? BrokenRules.Assert("StopDateRequired","Error.Object.RequiredFieldEmpty,WorkorderItemScheduledUser.Label.StopDate","StartDate",!mStartDate.IsEmpty && mStopDate.IsEmpty); if(!mStopDate.IsEmpty&&!mStartDate.IsEmpty) { BrokenRules.Assert("StartDateBeforeStopDate","Error.Object.StartDateAfterEndDate", "StartDate",mStartDate.CompareTo(mStopDate)>-1); } MarkDirty(); mNotificationAffectingChangesMade=true; } } } } //case 1251 /// /// Used by AyaNova UI to ensure correct dates are filled in /// public bool StartOrStopDateIsEmpty { get { return mStopDate.IsEmpty || mStartDate.IsEmpty; } } #region PM versions of date props /// /// Starting date and time /// internal DateTime dtStartDate { get { return mStartDate.Date; } set { if(mStartDate.Date!=value) { mStartDate.Date = value; CheckComplete(); //not empty Start date is not valid without stop date BrokenRules.Assert("StopDateRequired","Error.Object.RequiredFieldEmpty,WorkorderItemScheduledUser.Label.StopDate","StartDate",!mStartDate.IsEmpty && mStopDate.IsEmpty); //Is stop date valid now? BrokenRules.Assert("StartDateRequired","Error.Object.RequiredFieldEmpty,WorkorderItemScheduledUser.Label.StartDate","StopDate",!mStopDate.IsEmpty && mStartDate.IsEmpty); if(!mStopDate.IsEmpty&&!mStartDate.IsEmpty) { BrokenRules.Assert("StartDateBeforeStopDate","Error.Object.StartDateAfterEndDate", "StartDate",mStartDate.CompareTo(mStopDate)>-1); } MarkDirty(); mNotificationAffectingChangesMade=true; } } } /// /// Ending date and time /// internal DateTime dtStopDate { get { return mStopDate.Date; } set { if(mStopDate.Date!=value) { mStopDate.Date = value; CheckComplete(); //Not empty Stop date is not valid without start date BrokenRules.Assert("StartDateRequired","Error.Object.RequiredFieldEmpty,WorkorderItemScheduledUser.Label.StartDate","StopDate",!mStopDate.IsEmpty && mStartDate.IsEmpty); //Rule needs to be checked here even though it's to do with start date because it can be broken //there but can only be unbroken here so it needs to be checked in both places... //Is start date valid now? BrokenRules.Assert("StopDateRequired","Error.Object.RequiredFieldEmpty,WorkorderItemScheduledUser.Label.StopDate","StartDate",!mStartDate.IsEmpty && mStopDate.IsEmpty); if(!mStopDate.IsEmpty&&!mStartDate.IsEmpty) { BrokenRules.Assert("StartDateBeforeStopDate","Error.Object.StartDateAfterEndDate", "StartDate",mStartDate.CompareTo(mStopDate)>-1); } MarkDirty(); mNotificationAffectingChangesMade=true; } } } #endregion /// /// Pre-selected service /// public Guid ServiceRateID { get { return mServiceRateID; } set { if(bReadOnly) ThrowSetError(); else { if(mServiceRateID!=value) { mServiceRateID = value; MarkDirty(); } } } } /// /// Guid ID of parent object /// public Guid WorkorderItemID { get { return mWorkorderItemID; } // set // { // if(bReadOnly) // ThrowSetError(); // else // { // if(mWorkorderItemID!=value) // { // mWorkorderItemID = value; // // MarkDirty(); // // } // } // } } /// /// Set a broken rule if there is not at *least* /// one of the following: /// A start date /// AND end date or a /// ScheduleableUser /// entered. /// /// /// true if broken rule private void CheckComplete() { if(mStartDate.IsEmpty && mUserID==Guid.Empty) { BrokenRules.Assert("Incomplete", "WorkorderItemScheduledUser.Label.Error.RecordIncomplete", "IncompleteRecord",true); } else { BrokenRules.Assert("Incomplete", "WorkorderItemScheduledUser.Label.Error.RecordIncomplete", "IncompleteRecord",false); } } /// /// Called by parent collection object /// when called in turn by workorder object that is read only due to /// security or closed or service completed /// /// Either true or the rights allowed for the current user public void SetReadOnly(bool RO) { bReadOnly=RO; } /// /// Throw an error when a read only user /// tries to set a property /// (this should normally never be called unless someone is using the developer api since the UI /// should prevent it from happening initially) /// private void ThrowSetError() { throw new System.Security.SecurityException ( string.Format ( LocalizedTextTable.GetLocalizedTextDirect("Error.Security.NotAuthorizedToChange"), LocalizedTextTable.GetLocalizedTextDirect("O.WorkorderItemScheduledUser") ) ); } #endregion #region System.object overrides /// /// /// /// public override string ToString() { return "WorkorderItemScheduledUser" + mID.ToString(); } /// /// /// /// /// public override bool Equals(Object obj) { if ( obj == null || GetType ( ) != obj.GetType ( ) ) return false; WorkorderItemScheduledUser c=(WorkorderItemScheduledUser)obj; return mID==c.mID; } /// /// /// /// public override int GetHashCode() { return ("WorkorderItemScheduledUser"+mID).GetHashCode(); } #endregion #region Static methods /// /// New item /// /// /// internal static WorkorderItemScheduledUser NewItem(WorkorderItem obj) { //case 1387 if (AyaBizUtils.IsGenerator || ((obj.mHeaderRights > SecurityLevelTypes.ReadOnly) && (AyaBizUtils.Right("Object.WorkorderItemScheduledUser") > (int)SecurityLevelTypes.ReadOnly))) { WorkorderItemScheduledUser child = new WorkorderItemScheduledUser(); child.mWorkorderItemID=obj.ID; return child; } else throw new System.Security.SecurityException( string.Format( LocalizedTextTable.GetLocalizedTextDirect("Error.Security.NotAuthorizedToCreate"), LocalizedTextTable.GetLocalizedTextDirect("O.WorkorderItemScheduledUser"))); } /// /// Get Item /// /// /// /// internal static WorkorderItemScheduledUser GetItem(SafeDataReader dr, WorkorderItem obj) { //case 1387 if ((obj.mHeaderRights > SecurityLevelTypes.NoAccess) && (AyaBizUtils.Right("Object.WorkorderItemScheduledUser") > (int)SecurityLevelTypes.NoAccess)) { WorkorderItemScheduledUser child = new WorkorderItemScheduledUser(); child.Fetch(dr); return child; } else throw new System.Security.SecurityException( string.Format( LocalizedTextTable.GetLocalizedTextDirect("Error.Security.NotAuthorizedToRetrieve"), LocalizedTextTable.GetLocalizedTextDirect("O.WorkorderItemScheduledUser"))); } #endregion #region Shared Notification Message Processor internal static NotifyMessage GetNotificationMessage(NotifyMessageRequestData d) { //string Language=User.GetUserLanguage(MessageForUserID); WorkorderItemScheduledUserDescriptionFetcher wdf = WorkorderItemScheduledUserDescriptionFetcher.GetItemFromWorkorderItemScheduledUserID(d.RootObjectID); string sEventDescription=""; switch (d.EventType) { case (int)WorkorderItemScheduledUserEvent.CreatedUpdated: sEventDescription = LocalizedTextTable.GetLocalizedTextDirect("WorkorderItemScheduledUser.Label.Event.CreatedUpdated", d.Language); break; case (int)WorkorderItemScheduledUserEvent.PendingAlert: sEventDescription = LocalizedTextTable.GetLocalizedTextDirect("WorkorderItemScheduledUser.Label.Event.PendingAlert", d.Language); break; } //case 1415 string sStartDate = ""; string sStopDate = ""; if (d.TimeZoneOffset != 0) { sStartDate = wdf.StartDate.Date.ToUniversalTime().AddHours(d.TimeZoneOffset).ToString(); sStopDate = wdf.StopDate.Date.ToUniversalTime().AddHours(d.TimeZoneOffset).ToString(); } else { sStartDate = wdf.StartDate.ToString(); sStopDate = wdf.StopDate.ToString(); } string sMessage=sEventDescription; string sSubject=sEventDescription; NotifyMessage nm=null; if (d.Format == NotifyDeliveryMessageFormats.Brief) { sMessage+=","+ LocalizedTextTable.GetLocalizedTextDirect("WorkorderItemScheduledUser.Label.StartDate", d.Language) + " " + sStartDate + "," + LocalizedTextTable.GetLocalizedTextDirect("WorkorderService.Label.ServiceNumber", d.Language) + " " + wdf.WorkorderNumber + "," + wdf.ClientName + ", " + LocalizedTextTable.GetLocalizedTextDirect("WorkorderItem.Label.Summary", d.Language) + " " + wdf.Summary; if (d.MaxCharacters > 0 && sMessage.Length > d.MaxCharacters) nm = new NotifyMessage("", sMessage.Substring(0, d.MaxCharacters)); else nm=new NotifyMessage("", sMessage); } else { sSubject += ": " + LocalizedTextTable.GetLocalizedTextDirect("WorkorderService.Label.ServiceNumber", d.Language) + " " + wdf.WorkorderNumber; sMessage += ": " + LocalizedTextTable.GetLocalizedTextDirect("WorkorderItemScheduledUser.Label.StartDate", d.Language) + " " + sStartDate + ", " + LocalizedTextTable.GetLocalizedTextDirect("WorkorderItemScheduledUser.Label.StopDate", d.Language) + " " + sStopDate + "\r\n" + LocalizedTextTable.GetLocalizedTextDirect("WorkorderService.Label.ServiceNumber", d.Language) + ": " + wdf.WorkorderNumber + "\r\n" + LocalizedTextTable.GetLocalizedTextDirect("O.Client", d.Language) + ": " + wdf.ClientName + "\r\n" + LocalizedTextTable.GetLocalizedTextDirect("WorkorderItem.Label.Summary", d.Language) + ": " + wdf.Summary + "\r\n" + LocalizedTextTable.GetLocalizedTextDirect("WorkorderItem.Label.TechNotes", d.Language) + ": " + wdf.TechNotes + "\r\n" + LocalizedTextTable.GetLocalizedTextDirect("WorkorderItemScheduledUser.Label.ServiceRateID", d.Language) + ": " + wdf.RateName + "\r\n" + LocalizedTextTable.GetLocalizedTextDirect("WorkorderItemScheduledUser.Label.EstimatedQuantity", d.Language) + ": " + wdf.EstimatedQuantity.ToString() + "\r\n" ; nm=new NotifyMessage(sSubject,sMessage); } return nm; } #endregion #region DAL DATA ACCESS #region Fetch /// /// /// /// protected void Fetch(SafeDataReader dr) { //Standard fields mCreated=DBUtil.ToLocal(dr.GetSmartDate("aCreated")); mModified=DBUtil.ToLocal(dr.GetSmartDate("aModified")); mCreator=dr.GetGuid("aCreator"); mModifier=dr.GetGuid("aModifier"); mID=dr.GetGuid("aID"); //WorkorderItemScheduledUser fields mEstimatedQuantity=dr.GetDecimal("aEstimatedQuantity"); mStartDate=DBUtil.ToLocal(dr.GetSmartDate("aStartDate")); mStopDate=DBUtil.ToLocal(dr.GetSmartDate("aStopDate")); mServiceRateID=dr.GetGuid("aServiceRateID"); mUserID=dr.GetGuid("aUserID"); mWorkorderItemID=dr.GetGuid("aWorkorderItemID"); //Get access rights level bReadOnly=AyaBizUtils.Right("Object.WorkorderItemScheduledUser")<(int)SecurityLevelTypes.ReadWrite; MarkOld(); } #endregion #region Add / Update / Delete /// /// Update child /// /// /// internal void Update(WorkorderItem obj,IDbTransaction tr) { //No need to update if there is nothing changed if(!this.IsDirty) return; // If not a new record, check if record was modified //by another user since original retrieval: if(!IsNew) DBUtil.CheckSafeToUpdateInsideTransaction(this.mModified.Date, this.mID, "aWorkorderItemScheduledUser", tr);//case 1960 #region Delete if(IsDeleted) { if(!IsNew) { DBCommandWrapper cmDelete = DBUtil.GetCommandFromSQL("DELETE FROM aWorkorderItemScheduledUser WHERE aID=@ID;"); cmDelete.AddInParameter("@ID",DbType.Guid,this.mID); DBUtil.DB.ExecuteNonQuery(cmDelete, tr); //Remove any events for this object if (AyaBizUtils.GlobalSettings.UseNotification)//Case 510 { NotifyEvent.RemoveAllEventsForObject(this.mID); } } MarkNew(); return; } #endregion #region Add / Update //get modification time temporarily, if update succeeds then //set to this time System.DateTime dtModified = DBUtil.CurrentWorkingDateTime; DBCommandWrapper cm = null; if(IsNew)//Add or update? cm=DBUtil.GetCommandFromSQL( "INSERT INTO aWorkorderItemScheduledUser (aWorkorderItemID, " + "aID, aUserID, aEstimatedQuantity, aCreated,aModified,aCreator, " + "aModifier, aStartDate, aStopDate, aServiceRateID) " + "VALUES (@WorkorderItemID,@ID,@UserID,@EstimatedQuantity, " + "@Created,@Modified,@CurrentUserID,@CurrentUserID, @StartDate, " + "@StopDate,@ServiceRateID)" ); else cm=DBUtil.GetCommandFromSQL( "UPDATE aWorkorderItemScheduledUser SET aWorkorderItemID=@WorkorderItemID, " + "aID=@ID, aUserID=@UserID, " + "aEstimatedQuantity=@EstimatedQuantity, aStartDate=@StartDate, " + "aStopDate=@StopDate, aServiceRateID=@ServiceRateID, " + "aModifier=@CurrentUserID, aModified=@Modified " + "WHERE aID=@ID" ); //WorkorderItemScheduledUser specific cm.AddInParameter("@ID",DbType.Guid,mID); cm.AddInParameter("@WorkorderItemID",DbType.Guid,mWorkorderItemID); cm.AddInParameter("@EstimatedQuantity",DbType.Decimal,mEstimatedQuantity); cm.AddInParameter("@ServiceRateID",DbType.Guid,mServiceRateID); cm.AddInParameter("@StartDate",DbType.DateTime, DBUtil.ToUTC(mStartDate).DBValue); cm.AddInParameter("@StopDate",DbType.DateTime, DBUtil.ToUTC(mStopDate).DBValue); cm.AddInParameter("@UserID",DbType.Guid,mUserID); //standard parameters cm.AddInParameter("@CurrentUserID",DbType.Guid, CurrentUserID); cm.AddInParameter("@Created",DbType.DateTime, DBUtil.ToUTC(mCreated.Date)); cm.AddInParameter("@Modified",DbType.DateTime, DBUtil.ToUTC(dtModified)); DBUtil.DB.ExecuteNonQuery(cm, tr); MarkOld();//db is now synched with object //Successful update so //change modification time to match this.mModified.Date=dtModified; #region Process notifications //Process events as necessary if(AyaBizUtils.GlobalSettings.UseNotification && this.mNotificationAffectingChangesMade //Case 510 && obj.mWorkorderType == WorkorderTypes.Service)//case 1851 { //Any changes should result in a new notification being created //so remove the old one that is present if(!this.IsNew) NotifyEvent.RemoveAllEventsForObject(this.mID); if(this.mUserID!=Guid.Empty)//a schedule could have no user, just a time in which case no one to notifiy { //Created event (remember, only add a date if it's a pending notification //this one isn't even though there is a relative date which will get //picked up by the notification message Processor anyway so leave the date empty //for this particular created type notfication //bugbug: case 1152, this next bit causes a lockup if a workorder is being saved //and the current user is the scheduled user, basically an endless timeout NotifyEvent.AddOrUpdateEvent(RootObjectTypes.WorkorderItemScheduledUser,this.mID, (int)WorkorderItemScheduledUserEvent.CreatedUpdated, this.mUserID,new SmartDate(),Guid.Empty); //PendingAlert event //Only Process if there is a start date set if(!this.mStartDate.IsEmpty) NotifyEvent.AddOrUpdateEvent(RootObjectTypes.WorkorderItemScheduledUser,this.mID, (int)WorkorderItemScheduledUserEvent.PendingAlert, this.mUserID,this.mStartDate,Guid.Empty); } } #endregion notification Processing #endregion add / update } #endregion add/update/delete #endregion DAL data access }//end WorkorderItemScheduledUser #region Notification events /// /// /// public enum WorkorderItemScheduledUserEvent : int { /// /// /// [Description("LT:WorkorderItemScheduledUser.Label.Event.CreatedUpdated")] CreatedUpdated=1, /// /// /// [Description("LT:WorkorderItemScheduledUser.Label.Event.PendingAlert")] PendingAlert=256 } #endregion }//end namespace GZTW.AyaNova.BLL