/////////////////////////////////////////////////////////// // WorkorderService.cs // Implementation of Class WorkorderService // CSLA type: Editable Child // Created on: 07-Jun-2004 8:41:36 AM // Object design: Joyce // Coded: John 19-July-2004 /////////////////////////////////////////////////////////// using System; using System.Data; using CSLA.Data; using CSLA; using System.Threading; using CSLA.Security; using GZTW.Data; using System.ComponentModel; namespace GZTW.AyaNova.BLL { /// /// Service header component of a object of Service /// A workorder that is used to track service and parts provided to a /// [Serializable] public class WorkorderService : BusinessBase { #region Attributes private bool bReadOnly; private Guid mID; private Guid mCreator; private Guid mModifier; private SmartDate mCreated; private SmartDate mModified; private Guid mWorkorderID; private Guid mWorkorderStatusID; private SmartDate mServiceDate; private string mInvoiceNumber=""; private int mServiceNumber; private Guid mQuoteWorkorderID; private Guid mWorkorderPreventiveMaintenanceWorkorderID; private Guid mClientRequestID; private SmartDate mCloseByDate; //marked internal so that the Workorder object //can see if the close by date has changed for //Processing notification events //This is set to true when the //close by date property is changed internal bool mCloseByDateSignificant=false; //ditto, but with status internal bool mStatusSignificant=false; //case 1346 private AySignature mSignature = null; #endregion #region Constructor private WorkorderService() { //Set to read / write initially so that properties //can be set bReadOnly=false; //Child object MarkAsChild(); //New ID mID = Guid.NewGuid(); //default is zero which is tied into stored procedure //if it gets a zero then it will *not* try to set the ID //but will use identity value instead mServiceNumber=0; mServiceDate = new SmartDate(DBUtil.CurrentWorkingDateTime); //Set record history to defaults mCreated = new SmartDate(DBUtil.CurrentWorkingDateTime); mModified=new SmartDate(); mCreator=Guid.Empty; mModifier=Guid.Empty; mCloseByDate=new SmartDate(); if(AyaBizUtils.GlobalSettings.WorkorderCloseByAge>0) { //Notification for closebydate's might be on, so //set the property triggering a flag that there //is a change of close by date using the current date and time //and adding the number of minutes in the global setting default mCloseByDate.Date = DBUtil.CurrentWorkingDateTime.AddMinutes(AyaBizUtils.GlobalSettings.WorkorderCloseByAge); mCloseByDateSignificant=true; } //case 1346 mSignature = new AySignature(); } #endregion #region BusinessProperties //---Common properties /// /// Initial created date of this object /// public string Created { get { return mCreated.ToString(); } } /// /// User ID of who initially created this object /// public Guid Creator { get { return mCreator; } } /// /// Last modified date of this object /// public string Modified { get { return mModified.ToString(); } } /// /// User ID of who last modified this object /// public Guid Modifier { get { return mModifier; } } /// /// Unique ID of this object /// public Guid ID { get { return mID; } } //---WorkorderService specific properties /// /// ID of Workorder (type = WorkorderPreventiveMaintenance) that this WorkorderService object was /// created from /// If not made from a PreventiveMaintenanc can be null /// public Guid WorkorderPreventiveMaintenanceWorkorderID { get { return mWorkorderPreventiveMaintenanceWorkorderID; } set { if(bReadOnly) ThrowSetError(); else { if(mWorkorderPreventiveMaintenanceWorkorderID!=value) { mWorkorderPreventiveMaintenanceWorkorderID = value; MarkDirty(); } } } } /// /// ID of Workorder (type WorkorderQuote) that this WorkorderService object was created from /// If not made from a quote, than can be null /// public Guid QuoteWorkorderID { get { return mQuoteWorkorderID; } } /// /// ID of ClientRequest that this WorkorderService object was created from /// If not made from a ClientRequest can be null /// Not editable by the user /// public Guid ClientRequestID { get { return mClientRequestID; } } /// /// Incremental number from sql server /// ** USE AS A READ ONLY FIELD ONLY ** /// It is writeable only for the purpose of initial import /// into a fresh, empty database /// but should never normally be set after that. /// public int ServiceNumber { get { return mServiceNumber; } set { if(bReadOnly) ThrowSetError(); else { if(mServiceNumber!=value) { mServiceNumber = value; MarkDirty(); } } } } /// /// Takes first the created date but than can be overwritten by the user i.e /// WorkorderService info was obtained yesterday, but not actually created til today. this /// way user can edit the ServiceDate and use for response time etc /// public object ServiceDate { get { return mServiceDate.DBValue; } set { if(bReadOnly) ThrowSetError(); else { if (!AyaBizUtils.SmartDateEquals(mServiceDate, value)) //Case 298 { mServiceDate.DBValue = value; BrokenRules.Assert( "ServiceDateInvalid", "Error.Object.RequiredFieldEmpty,WorkorderService.Label.ServiceDate", "ServiceDate", mServiceDate.IsEmpty); MarkDirty(); } } } } /// /// direct access to smartdate value /// used by workorder dal code to /// flag client last service date /// internal SmartDate sdServiceDate { get { return mServiceDate; } } /// /// Status of entire service workorder /// public Guid WorkorderStatusID { //Uses same selection list of Status object - but this way allows for possibility // of different ways of reporting (either via status on workorder or status on // individual service items) // Need to set so that if user changed workorderstatus, it checks if serviceitems // are same status as selected - if not, gives message asking if user wishes to // change all serviceitems to match Servicestatus get { return mWorkorderStatusID; } set { if(bReadOnly) ThrowSetError(); else { if(mWorkorderStatusID!=value) { //flag status change for event notification mStatusSignificant=true; mWorkorderStatusID = value; MarkDirty(); } } } } /// /// One invoice number for entire workorder and all of its service items - if /// indivdual service items invoiced out separately, they should move the items to /// their own workorder. /// public string InvoiceNumber { get { return mInvoiceNumber; } set { if(bReadOnly) ThrowSetError(); else { if(mInvoiceNumber!=value) { mInvoiceNumber = value; MarkDirty(); } } } } /// /// ID of root object this address belongs to (workorder) /// public Guid WorkorderID { get { return mWorkorderID; } set { if(bReadOnly) ThrowSetError(); else { if(mWorkorderID!=value) { mWorkorderID = value; MarkDirty(); } } } } /// /// This is a user definable date and time used to indicate when a service workorder /// should be closed by. It's used to identify workorders that have been left to /// languish and not serviced promptly. /// /// A user needs the special Object.WorkorderService.CloseByDate right to be able /// to modify this even if they have full rights to the workorder object itself /// public object CloseByDate { get { return mCloseByDate.DBValue; } set { if(bReadOnly) ThrowSetError(); else { //User must have special rights to change this if(AyaBizUtils.Right("Object.WorkorderService.CloseByDate")<(int)SecurityLevelTypes.ReadWrite) { throw new System.Security.SecurityException ( string.Format ( LocalizedTextTable.GetLocalizedTextDirect("Error.Security.NotAuthorizedToChange"), LocalizedTextTable.GetLocalizedTextDirect("O.WorkorderService.CloseByDate") ) ); } if (!AyaBizUtils.SmartDateEquals(mCloseByDate, value)) //Case 298 { mCloseByDateSignificant=true; mCloseByDate.DBValue = value; MarkDirty(); } } } } /// /// Smart date version used by workorder notification Processor /// internal SmartDate sdCloseByDate { get { return mCloseByDate; } } /// /// AySignature object /// /// public AySignature Signature { get { if (mSignature == null) mSignature = new AySignature(""); return mSignature; } } /// /// Used internally to set the signature code from the client /// Not to be set via code directly /// [Browsable(false)] public string SetSignature { set { if (bReadOnly) ThrowSetError(); else { if (Signature.SignatureCode != value) { mSignature = new AySignature(value); mSignature.HostCapturedDateTime = new SmartDate(DateTime.Now); MarkDirty(); } } } } /// /// Used internally to clear the signature code from the client /// Not to be set via code directly /// [Browsable(false)] public bool ClearSignature { set { if (bReadOnly) ThrowSetError(); else { if (value && Signature.HasSignature) { Signature.Clear(); MarkDirty(); } } } } /// /// 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.WorkorderService") ) ); } #endregion #region Searching /// /// Returns a search result object based on search terms /// for the ID specified /// /// /// /// public static SearchResult GetSearchResult(Guid ID, string[]searchTerms) { //case 1387 if (Workorder.RightsToWorkorder(WorkorderIDFetcher.GetWorkorderByRelative(RootObjectTypes.WorkorderService, ID)) < SecurityLevelTypes.ReadOnly) return new SearchResult(); SearchResult sr=new SearchResult(); System.Text.StringBuilder sb = new System.Text.StringBuilder(); SafeDataReader dr = null; try { //Case 88 removed //"SELECT aID, aCreator, aModifier, aCreated, aModified, aInvoiceNumber, ASERVICENUMBER, " + // "FROM aWorkorderService WHERE (aID " + // "= @ID)" dr=DBUtil.GetReaderFromSQLString( //Case 88 "SELECT AWORKORDERSERVICE.AINVOICENUMBER, AWORKORDERSERVICE.ASERVICENUMBER, aClient.aRegionID AS ACLIENTREGION, ACLIENT.ANAME AS ACLIENTNAME, " + "AWORKORDERSERVICE.aCreator, " + " AWORKORDERSERVICE.aModifier, AWORKORDERSERVICE.aCreated, " + " AWORKORDERSERVICE.aModified " + "FROM ACLIENT INNER JOIN AWORKORDER " + "ON ACLIENT.AID = AWORKORDER.ACLIENTID RIGHT " + "OUTER JOIN AWORKORDERSERVICE ON AWORKORDER.AID = " + "AWORKORDERSERVICE.AWORKORDERID " + "WHERE (AWORKORDERSERVICE.AID = @ID)" ,ID); if(!dr.Read()) return new SearchResult();//DBUtil.ThrowFetchError("SearchResult for WorkorderItemLaborID: " + ID.ToString()); if (!AyaBizUtils.InYourRegion(dr.GetGuid("ACLIENTREGION"))) return new SearchResult();//case 58 //Case 88 sr.Description = LocalizedTextTable.GetLocalizedTextDirect("O.WorkorderService") + " " + dr.GetInt32("aServiceNumber").ToString() + " " + dr.GetString("ACLIENTNAME"); //sr.Description=""; sb.Append(dr.GetString("aInvoiceNumber")); sr.Created=DBUtil.ToLocal(dr.GetSmartDate("aCreated")); sr.Modified=DBUtil.ToLocal(dr.GetSmartDate("aModified")); sr.Creator=dr.GetGuid("aCreator"); sr.Modifier=dr.GetGuid("aModifier"); } finally { if(dr!=null) dr.Close(); } //Formulate results ExtractAndRank er = new ExtractAndRank(); er.Process(sb.ToString().Trim(),searchTerms); sr.Extract=er.Extract; sr.Rank=er.Ranking; sr.AncestorRootObjectID=ID; sr.AncestorRootObjectType=RootObjectTypes.WorkorderService; return sr; } #endregion #region System.object overrides /// /// /// /// public override string ToString() { return "WorkorderService" + mID.ToString(); } /// /// /// /// /// public override bool Equals(Object obj) { if ( obj == null || GetType ( ) != obj.GetType ( ) ) return false; WorkorderService c=(WorkorderService)obj; return mID==c.mID; } /// /// /// /// public override int GetHashCode() { return ("WorkorderService" + mID).GetHashCode(); } #endregion #region Static methods /// /// Create item /// /// Parent ID /// New Item internal static WorkorderService NewItem(Workorder obj) { //case 1387 no need to check rights here because parent workorder object now checks correct rights by type //if(AyaBizUtils.IsGenerator || AyaBizUtils.Right("Object.WorkorderService")>(int)SecurityLevelTypes.ReadOnly) //{ WorkorderService child=new WorkorderService(); child.mWorkorderID=obj.ID; return child; //} //else // throw new System.Security.SecurityException( // string.Format( // LocalizedTextTable.GetLocalizedTextDirect("Error.Security.NotAuthorizedToCreate"), // LocalizedTextTable.GetLocalizedTextDirect("O.WorkorderService"))); } /// /// Retrieve item /// /// Data reader /// item from database internal static WorkorderService GetItem(SafeDataReader dr) { //case 1387 no need to check rights here because parent workorder object now checks correct rights by type //if(AyaBizUtils.Right("Object.WorkorderService")>(int)SecurityLevelTypes.NoAccess) //{ WorkorderService child = new WorkorderService(); child.Fetch(dr); return child; //} //else // throw new System.Security.SecurityException( // string.Format( // LocalizedTextTable.GetLocalizedTextDirect("Error.Security.NotAuthorizedToRetrieve"), // LocalizedTextTable.GetLocalizedTextDirect("O.WorkorderService"))); } /// /// Sets new starting seed number for service workorders /// /// /// public static void SetVisibleIDNumber(int newID) { VisibleIDNumber.SetVisibleIDNumber(newID); } #endregion #region DAL DATA ACCESS #region Fetch /// /// Fetch from db /// /// private void Fetch(SafeDataReader dr) { //Standard items mCreated=DBUtil.ToLocal(dr.GetSmartDate("aCreated")); mCreator=dr.GetGuid("aCreator"); mModified=DBUtil.ToLocal(dr.GetSmartDate("aModified")); mModifier=dr.GetGuid("aModifier"); mID=dr.GetGuid("aID"); //WorkorderService specific parameters mClientRequestID=dr.GetGuid("aClientRequestID"); mInvoiceNumber=dr.GetString("aInvoiceNumber"); mWorkorderPreventiveMaintenanceWorkorderID=dr.GetGuid("aPreventiveMaintenanceID"); mQuoteWorkorderID=dr.GetGuid("aQuoteWorkorderID"); mServiceDate=DBUtil.ToLocal(dr.GetSmartDate("aServiceDate")); mServiceNumber=dr.GetInt32("aServiceNumber"); mWorkorderStatusID=dr.GetGuid("aWorkorderStatusID"); mWorkorderID=dr.GetGuid("aWorkorderID"); mCloseByDate=DBUtil.ToLocal(dr.GetSmartDate("aCloseByDate")); //case 1346 mSignature.SignatureCode = dr.GetString("ASIGNATURE"); mSignature.HostCapturedDateTime = DBUtil.ToLocal(dr.GetSmartDate("ASIGNED")); //Get access rights level bReadOnly=AyaBizUtils.Right("Object.WorkorderService")<(int)SecurityLevelTypes.ReadWrite; MarkOld(); } #endregion #region Add / Update /// /// Persist object to database /// /// Parent object /// Parents transaction object internal void Update(Workorder 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, "aWorkorderService", tr);//case 1960 #region Delete if(IsDeleted) { if(!IsNew) { DBCommandWrapper cmDelete = DBUtil.GetCommandFromSQL("DELETE FROM aWorkorderService WHERE aID=@ID;"); cmDelete.AddInParameter("@ID",DbType.Guid,this.mID); DBUtil.DB.ExecuteNonQuery(cmDelete, tr); } 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? { //CHECK IF IMPORTING... //If a new record has a service number already then it's importing //WARNING: THIS CODE WORKS ONLY IF THE IMPORTING DATA IS ALWAYS INCREMENTING THE //WO NUMBER. if(this.mServiceNumber!=0)//importing? SetVisibleIDNumber(this.mServiceNumber); cm=DBUtil.GetCommandFromSQL( "INSERT INTO aWorkorderService (aWorkorderID, aID, aWorkorderStatusID, " + "aServiceDate, " + "aInvoiceNumber, aQuoteWorkorderID, aClientRequestID, " + "aPreventiveMaintenanceID, aCloseByDate, ASIGNATURE, ASIGNED, aCreated,aModified,aCreator, " + "aModifier) VALUES (@WorkorderID,@ID,@WorkorderStatusID, " + "@ServiceDate, @InvoiceNumber, " + "@QuoteWorkorderID,@ClientRequestID, @PreventiveMaintenanceID, @CloseByDate, @SIGNATURE, @SIGNED, " + "@Created, @Modified, @CurrentUserID, @CurrentUserID)" ); } else cm=DBUtil.GetCommandFromSQL( "UPDATE aWorkorderService SET aWorkorderID=@WorkorderID, " + "aID=@ID, aWorkorderStatusID=@WorkorderStatusID, " + "aServiceDate=@ServiceDate, " + "aInvoiceNumber=@InvoiceNumber, " + "aQuoteWorkorderID=@QuoteWorkorderID, aClientRequestID=@ClientRequestID, " + "aPreventiveMaintenanceID=@PreventiveMaintenanceID, " + "aCloseByDate=@CloseByDate, ASIGNATURE=@SIGNATURE, ASIGNED=@SIGNED, " + "aModifier=@CurrentUserID, aModified=@Modified " + "WHERE aID=@ID" ); //WorkorderService specific parameters cm.AddInParameter("@ID",DbType.Guid,mID); cm.AddInParameter("@ClientRequestID",DbType.Guid,mClientRequestID); cm.AddInParameter("@InvoiceNumber",DbType.String,mInvoiceNumber); cm.AddInParameter("@PreventiveMaintenanceID",DbType.Guid,mWorkorderPreventiveMaintenanceWorkorderID); cm.AddInParameter("@QuoteWorkorderID",DbType.Guid,mQuoteWorkorderID); cm.AddInParameter("@ServiceDate",DbType.DateTime,DBUtil.ToUTC(mServiceDate).DBValue); cm.AddInParameter("@WorkorderStatusID",DbType.Guid,mWorkorderStatusID); cm.AddInParameter("@WorkorderID",DbType.Guid,mWorkorderID); cm.AddInParameter("@CloseByDate",DbType.DateTime,DBUtil.ToUTC(mCloseByDate).DBValue); //case 1346 cm.AddLargeStringInParameter("@SIGNATURE", mSignature.SignatureCode); cm.AddInParameter("@SIGNED", DbType.DateTime, DBUtil.ToUTC(mSignature.HostCapturedDateTime).DBValue); //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); //Get new DB generated identity value if(IsNew) this.mServiceNumber=DBUtil.GetIdentity("aServiceNumber","aWorkorderService",this.mID,tr); //Process keywords DBUtil.ProcessKeywords(tr,this.mID,RootObjectTypes.WorkorderService,IsNew,AyaBizUtils.Break(false, mInvoiceNumber)); MarkOld();//db is now synched with object //Successful update so //change modification time to match this.mModified.Date=dtModified; #endregion } #endregion #endregion #region Set VisibleIDNumber #pragma warning disable 1591 /// /// Set the DB generated visible ID number /// to a new user chosen starting point /// [Serializable(), System.ComponentModel.Browsable(false)] public class VisibleIDNumber//DO_NOT_OBFUSCATE { int _newStartID = -1; public VisibleIDNumber(int newStartID) { _newStartID = newStartID; } public static void SetVisibleIDNumber(int newStartID) { DataPortal.Update(new VisibleIDNumber(newStartID)); } public void DataPortal_Update() { //Find the highest existing number Object o=DBUtil.GetScalarFromSQLString( "SELECT MAX(aServiceNumber) FROM aWorkorderService" ); if(o==null || o==System.DBNull.Value) o=0; int nHighestExisting=(int)o; //ensure new number is larger than highest existing one if(_newStartID