/////////////////////////////////////////////////////////// // Workorder.cs // Implementation of Class Workorder // CSLA type: Editable Root // Created on: 07-Jun-2004 8:41:45 AM // Object design: Joyce // Coded: John 29-July-2004 /////////////////////////////////////////////////////////// using System; using System.Data; using CSLA.Data; using GZTW.Data; using CSLA; using System.Threading; using CSLA.Security; using System.ComponentModel; using System.Text; namespace GZTW.AyaNova.BLL { /// /// Workorder object - the heart of AyaNova. /// This is the parent object of all forms of workorders including quotes, pm, service and template forms. /// [Serializable] public class Workorder : BusinessBase { #region Attributes private bool bReadOnly; private Guid mID; private SmartDate mCreated; private SmartDate mModified; private Guid mCreator; private Guid mModifier; private AssignedDocs mDocs; //Workorder properties private Guid mClientID; private Guid mProjectID; private string mInternalReferenceNumber = ""; private string mCustomerReferenceNumber = ""; private bool mOnsite; private string mCustomerContactName = ""; //case 58 private Guid mRegionID; private string mSummary = ""; private string mTemplateDescription = ""; private Guid mFormLayoutID; private WorkorderTypes mWorkorderType; //private bool mTemplate; private Guid mWorkorderCategoryID; //Children private WorkorderQuote mQuote; private WorkorderService mService; private WorkorderPreventiveMaintenance mWorkorderPreventiveMaintenance; private WorkorderItems mWorkorderItems; private bool mUseInventory; //applicable only if it's a service workorder private bool mServiceCompleted; private bool mClosed; internal Guid mFromQuoteID; internal Guid mFromPMID; //case 1387 internal SecurityLevelTypes mRights; //case 3132 private bool mTemplateFreshPrice; #endregion #region Constructor /// /// Private constructor to prevent direct instantiation /// private Workorder() { //Set to read / write initially so that properties //can be set bReadOnly = false; //New ID mID = Guid.NewGuid(); mWorkorderItems = WorkorderItems.NewItems(); //Built-in "Default" region mRegionID = Region.DefaultRegionID;//case 58 //Set record history to defaults mCreated = new SmartDate(DBUtil.CurrentWorkingDateTime); mModified = new SmartDate(); mCreator = Guid.Empty; mModifier = Guid.Empty; mUseInventory = AyaBizUtils.GlobalSettings.UseInventory; mClosed = false; mServiceCompleted = false; mDocs = AssignedDocs.NewItems(); //Changed 15-March-2006 mOnsite = true; //case 3132 mTemplateFreshPrice = false; } #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; } } /// /// object collection assigned to this workorder /// public AssignedDocs Docs { get { return mDocs; } } /// /// Category of workorder /// public Guid WorkorderCategoryID { get { return mWorkorderCategoryID; } set { if (bReadOnly) ThrowSetError(); else { if (mWorkorderCategoryID != value) { mWorkorderCategoryID = value; MarkDirty(); } } } } /// /// Client this work order applies to /// public Guid ClientID { get { return mClientID; } set { if (bReadOnly) ThrowSetError(); else { if (mClientID != value) { mClientID = value; if (this.CustomerContactName == "") { Client c = Client.GetItemNoMRU(value); this.CustomerContactName = c.Contact; c = null; } MarkDirty(); } } } } /// /// Brief description of the purpose of the workorder as a whole /// displays on many reports and in various grids. Should be an overview /// of what the service is about for the work order in general. /// public string Summary { get { return mSummary; } set { if (bReadOnly) ThrowSetError(); else { if (mSummary != value) { mSummary = value; MarkDirty(); } } } } /// /// Need to flesh out a lot more as refers to a collection etc /// /// ID of the FormLayout which is object describing the field positions and field /// titles of a workorder input form as designed by a user /// public Guid FormLayoutID { get { return mFormLayoutID; } set { if (bReadOnly) ThrowSetError(); else { if (mFormLayoutID != value) { mFormLayoutID = value; MarkDirty(); } } } } /// /// GUID of project selected /// public Guid ProjectID { get { return mProjectID; } set { if (bReadOnly) ThrowSetError(); else { if (mProjectID != value) { mProjectID = value; MarkDirty(); } } } } /// /// In addition to Workorder number - may have letters in it, therefore used in /// addition to numerial wo number /// public string InternalReferenceNumber { get { return mInternalReferenceNumber; } set { if (bReadOnly) ThrowSetError(); else { if (mInternalReferenceNumber != value) { mInternalReferenceNumber = value; MarkDirty(); } } } } /// /// Client's reference number /// public string CustomerReferenceNumber { get { return mCustomerReferenceNumber; } set { if (bReadOnly) ThrowSetError(); else { if (mCustomerReferenceNumber != value) { mCustomerReferenceNumber = value; MarkDirty(); } } } } /// /// Onsite indicates at client site /// Default is true /// Can be set in regional settings /// public bool Onsite { get { return mOnsite; } set { if (bReadOnly) ThrowSetError(); else { if (mOnsite != value) { mOnsite = value; MarkDirty(); } } } } /// /// Takes as default name in client contact list when client first selected, but /// can be edited by user /// public string CustomerContactName { get { return mCustomerContactName; } set { if (bReadOnly) ThrowSetError(); else { if (mCustomerContactName != value) { mCustomerContactName = value; MarkDirty(); } } } } /// /// Determines if a workorder is a template, a quote, a PM item, a workorder for a /// client or an internal workorder /// public WorkorderTypes WorkorderType { get { return mWorkorderType; } set { if (bReadOnly) ThrowSetError(); else { if (mWorkorderType != value) { mWorkorderType = value; MarkDirty(); } } } } /// /// /// Brief description of the purpose of the workorder template as a whole /// displays on many reports and in various grids. /// /// public string TemplateDescription { get { return mTemplateDescription; } set { if (bReadOnly) ThrowSetError(); else { if (mTemplateDescription != value) { mTemplateDescription = value; BrokenRules.Assert("TemplateDescriptionLength", "Error.Object.FieldLengthExceeded255,Workorder.Label.TemplateDescription", "TemplateDescription", value.Length > 255); MarkDirty(); } } } } /// /// Only used if this is a template workorder /// Regular Service, Quote and PM work orders follow the client's region /// /// Any attempt to set this field on a non template work order /// will do nothing. /// /// Limit template to specific region or available to all regions using Region.DefaultRegionID /// public Guid RegionID { get { return mRegionID; } set { if (bReadOnly) ThrowSetError(); else { if (this.IsTemplate) { if (mRegionID != value) { mRegionID = value; BrokenRules.Assert("RegionIDRequired", "Error.Object.RequiredFieldEmpty,O.Region", "RegionID", value == Guid.Empty); MarkDirty(); } } } } } //Child objects /// /// If not a WorkorderPreventiveMaintenance, is null /// If a WorkorderPreventiveMaintenance contains the WorkorderPreventiveMaintenance child object /// public WorkorderPreventiveMaintenance WorkorderPreventiveMaintenance { get { return mWorkorderPreventiveMaintenance; } } /// /// If not a WorkorderService, is null /// If a WorkorderService contains the WorkorderService child object /// public WorkorderService WorkorderService { get { return mService; } } /// /// Workorder items collection /// public WorkorderItems WorkorderItems { get { return mWorkorderItems; } } /// /// If not a quote, is null /// If a quote, contains the WorkorderQuote child object /// public WorkorderQuote WorkorderQuote { get { return mQuote; } } //*************** CONTRACT / SERVICEBANK RELATED CODE ************************** /// /// Returns populated TypeAndID if the client or head office for this workorder is bankable /// (If the unit is bankable that's handled separately) /// /// Returns null if not bankable /// public TypeAndID BankableResolved() { if (AyaBizUtils.Lite) return null; //internal service? if (this.ClientID == Guid.Empty) return null; //Case 576 return ServiceBankResolver.BankableObject(this.ClientID); ////CLIENT //Client c = Client.GetItem(this.ClientID); //if (c.UsesBanking) // return new TypeAndID(RootObjectTypes.Client, this.ClientID); ////HEADOFFICE //if (c.HeadOfficeID == Guid.Empty) return null; //if (HeadOffice.GetItem(c.HeadOfficeID).UsesBanking) // return new TypeAndID(RootObjectTypes.HeadOffice, c.HeadOfficeID); //return null; } /// /// Checks *all* possible bankable objects in this order: /// Unit->Client->HeadOffice /// If any of those objects are bankable then the type and id is returned /// /// If none are bankable then it returns a type and ID of Guid empty and object type Nothing. /// /// This method supersedes the original BankableResolved method and should be used in /// it's place when there is a unit involved /// public TypeAndID BankableResolved(Guid WorkorderItemId) { if (this.WorkorderItems[WorkorderItemId].HasUnit) { Unit u = Unit.GetItem(this.WorkorderItems[WorkorderItemId].UnitID); if (u != null && u.UsesBanking) { return new TypeAndID(RootObjectTypes.Unit, u.ID); } } TypeAndID woTid = this.BankableResolved(); if (woTid == null) return new TypeAndID(RootObjectTypes.Nothing, Guid.Empty); else return woTid; } //Added 28-Aug-2006 to speed up contract resolution for UI //"cache" the resolved contract so the expense //of determining it is only done once. //contract resolved is used quite heavily by both //web and winform UI's private Contract mResolvedContract = null; private bool mContractHasBeenResolved = false; /// /// Returns Contract that is most specific /// or null if no contract /// /// public Contract ContractResolved() { //Added 28-Aug-2006 to speed up contract resolution for UI if (mContractHasBeenResolved) return mResolvedContract; //internal service? if (this.ClientID == Guid.Empty) { mContractHasBeenResolved = true; return null; } mResolvedContract = ContractResolver.ResolvedContract(mClientID); mContractHasBeenResolved = true; return mResolvedContract; //Case 577 ////CLIENT //Client c=Client.GetItem(this.ClientID); ////Case 231 now check for contract in effect ////not just contract id exists //if (c.ContractInEffect) //{ // mContractHasBeenResolved = true; // mResolvedContract= Contract.GetItem(c.ContractID); // return mResolvedContract; //} ////HEADOFFICE //if (c.HeadOfficeID == Guid.Empty) //{ // mContractHasBeenResolved = true; // return null; //} ////Case 231 changes to use new contractineffect property of ////head office instead of just returning the contract if it existed ////expired or not //HeadOffice ho = HeadOffice.GetItem(c.HeadOfficeID); //if (ho.ContractInEffect) //{ // mContractHasBeenResolved = true; // mResolvedContract= Contract.GetItem(ho.ContractID); // return mResolvedContract; //} ////Resolved to be no contract applicable //mContractHasBeenResolved = true; //return null; } //Added:17-Aug-2006 for wbi /// /// Returns ID only of Contract that is most specific to /// this workorder or empty Guid if no Contract applies at all /// /// public Guid ContractIDResolved() { Contract c = ContractResolved(); if (c == null) return Guid.Empty; else return c.ID; } //****************************************************************************** /// /// Mirror of global object's UseInventory setting /// public bool UseInventory { get { return mUseInventory; } } /// /// Move workorderItem from current workorder to another /// (Requires full rights and not a closed or read only workorder) /// /// /// public void MoveWorkorderItem(Guid ToWorkorderID, Guid WorkorderItemID) { //case 1387 now checks rights to this object if (this.mClosed || this.mServiceCompleted || Rights < SecurityLevelTypes.ReadWrite) ThrowSetError(); //make sure the workorder is not dirty or unsaved if (this.IsDirty || !this.IsValid) { throw new System.ApplicationException ( LocalizedTextTable.GetLocalizedTextDirect("Workorder.Label.Error.NotMoveableUntilSavedAndValid") ); } //this will throw a localized exception of there is less than 2 workorder items this.WorkorderItems.EnsureAtLeastOneWorkorderItem(); //Do the move Workorder.WorkorderItemMover.Move(this.mID, ToWorkorderID, WorkorderItemID); try { //flag as moved so it won't be updated this.WorkorderItems[WorkorderItemID.ToString()].mMoved = true; this.WorkorderItems.Remove(WorkorderItemID); } catch { //do nothing, it's an annoying visual thing only? } } /// /// Flag to indicate that service has been completed for this workorder /// When true it means that all but workorder header items will become read only /// this property can only be set from true to false by someone with full rights /// to the workorder object /// public bool ServiceCompleted { get { return mServiceCompleted; } set { if (mWorkorderType != WorkorderTypes.Service) return; //Attempting to service completed a workorder with broken rules? //Can't allow because if we make it read only there is no //way to fix the broken rules if (!this.IsValid && value == true) { throw new System.ApplicationException ( LocalizedTextTable.GetLocalizedTextDirect("Workorder.Label.Error.NotCompleteableDueToErrors") ); } if (bReadOnly) ThrowSetError(); else { if (mServiceCompleted != value) { if (mServiceCompleted == true) { //User is attempting to set service to NOT completed, make sure they have rights... //case 413 changed rights check from > than read/write to > than readonly if (Rights > SecurityLevelTypes.ReadOnly) { mServiceCompleted = value; MarkDirty(); //set all workorder items to correct status this.mWorkorderItems.SetReadOnly(mServiceCompleted); } else { throw new System.Security.SecurityException ( string.Format ( LocalizedTextTable.GetLocalizedTextDirect("Error.Security.NotAuthorizedToChange"), LocalizedTextTable.GetLocalizedTextDirect("O.WorkorderService") ) ); } } else { mServiceCompleted = value; MarkDirty(); //set all workorder items to correct status this.mWorkorderItems.SetReadOnly(mServiceCompleted); } } } } } /// /// Used to close a workorder. /// A closed workorder can never be re-opened, so this is a write once setting. /// A closed workorder can no longer be edited in any manner permanently. /// /// Closing a work order triggers a whost of tertiary methods that update related objects /// this process can not be reversed. /// public bool Closed { get { return mClosed; } set { if (mWorkorderType != WorkorderTypes.Service) return; //case 986 ////Attempt to re-open a closed workorder? //if(mClosed==true && value==false) //{//unclose // throw new System.ApplicationException // ( // LocalizedTextTable.GetLocalizedTextDirect("Workorder.Label.Error.ClosedIsPermanent") // ); //} if (value == true)//is it a close attempt instead of a reopen? case 986 { //Attempting to close a workorder with broken rules? //Can't allow because if we make it read only there is no //way to fix the broken rules if (!this.IsValid) { throw new System.ApplicationException ( LocalizedTextTable.GetLocalizedTextDirect("Workorder.Label.Error.NotCloseableDueToErrors") ); } if (this.HasOutstandingLoanItems) { throw new System.ApplicationException ( LocalizedTextTable.GetLocalizedTextDirect("Workorder.Label.Error.LoanItemsNotReturned") ); } //Case 398 (sort of, actually added when didn't fully understand the problem, but this should be here anyway //to handle api use of closing a wo when it has parts on order) if (this.HasPartRequestsOnOrder) { throw new System.ApplicationException ( LocalizedTextTable.GetLocalizedTextDirect("Workorder.Label.Error.PartRequestsOnOrder") ); } //Case 398 if (this.HasPartRequestsUnOrdered) { throw new System.ApplicationException ( LocalizedTextTable.GetLocalizedTextDirect("Workorder.Label.Error.PartRequestsUnOrdered") ); } } if (bReadOnly) ThrowSetError(); else { if (mClosed != value) { mClosed = value; MarkDirty(); } if (mClosed) { //case 6 //Note that you can only close a service work order that's why there is no //specific check here for type of workorder if (AyaBizUtils.AllowAutomaticClosedWorkorderStatus && AyaBizUtils.GlobalSettings.WorkorderClosedStatus != Guid.Empty) this.WorkorderService.WorkorderStatusID = AyaBizUtils.GlobalSettings.WorkorderClosedStatus; //bReadOnly = true; //set all workorder items to read only status this.mWorkorderItems.SetReadOnly(true); } else { //case 986 - reopening a workorder bReadOnly = false; this.mWorkorderItems.SetReadOnly(false); } } } } //case 3132 /// /// If a template setting to true will result in the prices being updated to current in the generated order /// public bool TemplateFreshPrice { get { return mTemplateFreshPrice; } set { if (bReadOnly) ThrowSetError(); else { if (mTemplateFreshPrice != value) { mTemplateFreshPrice = value; MarkDirty(); } } } } /// /// False if any outstanding parts (not set to "Used in service") /// True if all parts are set to used in service. /// public bool AllPartsUsed { get { //If it's not a service invoice then always return true if (mWorkorderType != WorkorderTypes.Service) return true; foreach (WorkorderItem wi in this.WorkorderItems) { foreach (WorkorderItemPart wip in wi.Parts) { if (wip.Used != true) return false; } } return true; } } /// /// Sets all parts to used = true on entire workorder /// public void SetAllPartsUsed() { //If it's not a service invoice then nothing to set if (mWorkorderType != WorkorderTypes.Service) return; foreach (WorkorderItem wi in this.WorkorderItems) { foreach (WorkorderItemPart wip in wi.Parts) { if (wip.Used != true) wip.Used = true; } } } /// /// Create a labor object from a scheduled user object to save entry time /// /// /// /// public Guid CreateLaborFromScheduledUser(Guid SourceWorkorderItemID, Guid SourceWorkorderItemScheduledUserID) { if (this.bReadOnly) return Guid.Empty; if (mWorkorderType != WorkorderTypes.Service) return Guid.Empty; if (mClosed || mServiceCompleted) return Guid.Empty; foreach (WorkorderItem wi in this.WorkorderItems) { if (wi.ID == SourceWorkorderItemID) { foreach (WorkorderItemScheduledUser u in wi.ScheduledUsers) { if (u.ID == SourceWorkorderItemScheduledUserID) { WorkorderItemLabor wil = wi.Labors.Add(wi); wil.UserID = u.UserID; wil.ServiceStartDate = u.StartDate; wil.ServiceStopDate = u.StopDate; wil.ServiceRateID = u.ServiceRateID; wil.ServiceRateQuantity = u.EstimatedQuantity; return wil.ID; } } } } //records not found return Guid.Empty; } /// /// Find the workorder item ID that contains the object passed in /// /// Type of workorder item descendant object /// ID of descendant of workorder item /// public Guid GetWorkorderItemIDFromDescendant(RootObjectTypes DescendantObjectType, Guid DescendantID) { foreach (WorkorderItem wi in this.WorkorderItems) { switch (DescendantObjectType) { case RootObjectTypes.WorkorderItemLabor: { foreach (WorkorderItemLabor d in wi.Labors) { if (d.ID == DescendantID) return wi.ID; } } break; case RootObjectTypes.WorkorderItemMiscExpense: { foreach (WorkorderItemMiscExpense d in wi.Expenses) { if (d.ID == DescendantID) return wi.ID; } } break; case RootObjectTypes.WorkorderItemOutsideService: { if (wi.OutsideService.ID == DescendantID) return wi.ID; } break; case RootObjectTypes.WorkorderItemPart: { foreach (WorkorderItemPart d in wi.Parts) { if (d.ID == DescendantID) return wi.ID; } } break; case RootObjectTypes.WorkorderItemScheduledUser: { foreach (WorkorderItemScheduledUser d in wi.ScheduledUsers) { if (d.ID == DescendantID) return wi.ID; } } break; case RootObjectTypes.WorkorderItemTravel: { foreach (WorkorderItemTravel d in wi.Travels) { if (d.ID == DescendantID) return wi.ID; } } break; case RootObjectTypes.WorkorderItemPartRequest://case 1086 { foreach (WorkorderItemPartRequest d in wi.PartRequests) { if (d.ID == DescendantID) return wi.ID; } } break; case RootObjectTypes.WorkorderItemLoan://case 1975 { foreach (WorkorderItemLoan d in wi.Loans) { if (d.ID == DescendantID) return wi.ID; } } break; #if(DEBUG) default: throw new System.NotSupportedException("Workorder->GetWorkorderItemIDFromDescendant Error - object type not supported: " + DescendantObjectType.ToString()); #endif } } //Not found return Guid.Empty; } /// /// ID of quote that created this workorder /// Set internally when the Quote workorder generates a service /// workorder. /// public Guid FromQuoteID { get { return mFromQuoteID; } } /// /// ID of PreventiveMaintenance that created this workorder /// Set internally when the PM workorder generates a service /// workorder. /// public Guid FromPMID { get { return mFromPMID; } } /// /// True if on a service workorder there are any parts with a reserved quantity > 0 /// /// Non service workorders (quotes / pm) always return false /// /// Used in Workorder form to determine whether to show the /// reserved parts field or not. /// /// Reserved parts are only on workorders generated from P.M. or quotes /// when inventory is being used. /// public bool HasReservedParts { get { //If it's not a service invoice then always return false if (mWorkorderType != WorkorderTypes.Service) return false; foreach (WorkorderItem wi in this.WorkorderItems) { foreach (WorkorderItemPart wip in wi.Parts) { if (wip.QuantityReserved > 0) return true; } } return false; } } /// /// True means there are loan items not yet returned /// /// /// public bool HasOutstandingLoanItems { get { //If it's not a service invoice then always return false if (mWorkorderType != WorkorderTypes.Service) return false; foreach (WorkorderItem wi in this.WorkorderItems) { foreach (WorkorderItemLoan w in wi.Loans) { if (w.ReturnDate == System.DBNull.Value) return true; } } return false; } } /// /// True means there are WorkorderItemPartRequest items /// still on order and not fully received /// /// Note: if GlobalSettings.UseInventory is set to false this will /// always return false /// public bool HasPartRequestsOnOrder { get { //If it's not a service invoice then always return false if (mWorkorderType != WorkorderTypes.Service) return false; //case 932 if (!AyaBizUtils.GlobalSettings.UseInventory) return false; foreach (WorkorderItem wi in this.WorkorderItems) { if (wi.HasPartRequestsOnOrder) return true; } return false; } } //Case 398 /// /// True means there are WorkorderItemPartRequest items /// not yet ordered or received /// /// Note: if GlobalSettings.UseInventory is false this will always return false /// /// public bool HasPartRequestsUnOrdered { get { //If it's not a service invoice then always return false if (mWorkorderType != WorkorderTypes.Service) return false; //case 932 if (!AyaBizUtils.GlobalSettings.UseInventory) return false; foreach (WorkorderItem wi in this.WorkorderItems) { if (wi.HasPartRequestsUnOrdered) return true; } return false; } } //Added 25-April-2006 to ensure a serial number can't be selected twice /// /// Returns true if the serial number record is selected /// anywhere in the workorder item parts collections /// /// ID of PartSerial record /// public bool HasSerialNumberSelected(Guid PartSerialID) { foreach (WorkorderItem wi in this.WorkorderItems) { foreach (WorkorderItemPart p in wi.Parts) { if (p.PartSerialID == PartSerialID) return true; } } return false; } //Added:17-Aug-2006 for wbi /// /// A List of Guid's of labor rates selected /// anywhere in this work order. /// /// /// public System.Collections.Generic.List ListOfLaborRatesSelected() { System.Collections.Generic.List l = new System.Collections.Generic.List(); //Add manual items that are inactive but need to be displayed to list //from the AllRates foreach (WorkorderItem wi in this.WorkorderItems) { foreach (WorkorderItemLabor wl in wi.Labors) { if (!l.Contains(wl.ServiceRateID)) l.Add(wl.ServiceRateID); } } return l; } //Added:18-Aug-2006 for wbi /// /// A List of Guid's of units selected /// anywhere in this work order. /// /// /// public System.Collections.Generic.List ListOfUnitsSelected() { System.Collections.Generic.List l = new System.Collections.Generic.List(); foreach (WorkorderItem wi in this.WorkorderItems) { if (wi.UnitID != Guid.Empty && !l.Contains(wi.UnitID)) l.Add(wi.UnitID); } return l; } //Added:18-Aug-2006 for wbi /// /// A List of Guid's of labor users selected /// anywhere in this work order. /// /// /// public System.Collections.Generic.List ListOfLaborUsersSelected() { System.Collections.Generic.List l = new System.Collections.Generic.List(); foreach (WorkorderItem wi in this.WorkorderItems) { foreach (WorkorderItemLabor wl in wi.Labors) { if (!l.Contains(wl.UserID)) l.Add(wl.UserID); } } return l; } //Added:18-Aug-2006 for wbi /// /// A List of Guid's of travel user id's selected /// anywhere in this work order. /// /// /// public System.Collections.Generic.List ListOfTravelUsersSelected() { System.Collections.Generic.List l = new System.Collections.Generic.List(); foreach (WorkorderItem wi in this.WorkorderItems) { foreach (WorkorderItemTravel wl in wi.Travels) { if (!l.Contains(wl.UserID)) l.Add(wl.UserID); } } return l; } //Added:18-Aug-2006 for wbi /// /// A List of Guid's of travel rates selected /// anywhere in this work order. /// /// /// public System.Collections.Generic.List ListOfTravelRatesSelected() { System.Collections.Generic.List l = new System.Collections.Generic.List(); foreach (WorkorderItem wi in this.WorkorderItems) { foreach (WorkorderItemTravel wl in wi.Travels) { if (!l.Contains(wl.TravelRateID)) l.Add(wl.TravelRateID); } } return l; } //Added:18-Aug-2006 for wbi /// /// A List of Guid's of parts selected /// anywhere in this work order. /// /// /// public System.Collections.Generic.List ListOfPartsSelected() { System.Collections.Generic.List l = new System.Collections.Generic.List(); foreach (WorkorderItem wi in this.WorkorderItems) { foreach (WorkorderItemPart wl in wi.Parts) { if (!l.Contains(wl.PartID)) l.Add(wl.PartID); } } return l; } //Case 640 /// /// A List of Guid's of Part Warehouses selected /// anywhere in this work order. /// /// /// public System.Collections.Generic.List ListOfPartWarehousesSelected() { System.Collections.Generic.List l = new System.Collections.Generic.List(); foreach (WorkorderItem wi in this.WorkorderItems) { foreach (WorkorderItemPart wl in wi.Parts) { if (!l.Contains(wl.PartWarehouseID)) l.Add(wl.PartWarehouseID); } } return l; } //Added:22-Aug-2006 for wbi /// /// A List of Guid's of Scheduleable users selected /// anywhere in this work order. /// /// /// public System.Collections.Generic.List ListOfScheduledUsersSelected() { System.Collections.Generic.List l = new System.Collections.Generic.List(); foreach (WorkorderItem wi in this.WorkorderItems) { foreach (WorkorderItemScheduledUser wl in wi.ScheduledUsers) { if (!l.Contains(wl.UserID)) l.Add(wl.UserID); } } return l; } //Added:22-Aug-2006 for wbi /// /// A List of Guid's of Scheduleable users suggested labor rates selected /// anywhere in this work order. /// /// /// public System.Collections.Generic.List ListOfScheduledUsersLaborRatesSelected() { System.Collections.Generic.List l = new System.Collections.Generic.List(); foreach (WorkorderItem wi in this.WorkorderItems) { foreach (WorkorderItemScheduledUser wl in wi.ScheduledUsers) { if (!l.Contains(wl.ServiceRateID)) l.Add(wl.ServiceRateID); } } return l; } //Added:22-Aug-2006 for wbi /// /// A List of Guid's of Misc expense users selected /// anywhere in this work order. /// /// /// public System.Collections.Generic.List ListOfMiscExpenseUsersSelected() { System.Collections.Generic.List l = new System.Collections.Generic.List(); foreach (WorkorderItem wi in this.WorkorderItems) { foreach (WorkorderItemMiscExpense wl in wi.Expenses) { if (!l.Contains(wl.UserID)) l.Add(wl.UserID); } } return l; } //Added:22-Aug-2006 for wbi /// /// A List of Guid's of Loan items selected /// anywhere in this work order. /// /// /// public System.Collections.Generic.List ListOfLoanItemsSelected() { System.Collections.Generic.List l = new System.Collections.Generic.List(); foreach (WorkorderItem wi in this.WorkorderItems) { foreach (WorkorderItemLoan wl in wi.Loans) { if (!l.Contains(wl.LoanItemID)) l.Add(wl.LoanItemID); } } return l; } //Added:28-Sept-2006 for wbi /// /// A List of Guid's of serial numbers selected /// anywhere in this work order. /// /// Used to prevent duplicate sn selection by presening /// user with only available sn's /// /// A partserial ID to exclude (not add to this list) /// even when present. This is used to not exclude the currently selected /// serial number during editing /// public System.Collections.Generic.List ListOfSerialNumbersSelected(Guid excludeID) { System.Collections.Generic.List l = new System.Collections.Generic.List(); foreach (WorkorderItem wi in this.WorkorderItems) { foreach (WorkorderItemPart wl in wi.Parts) { if (!l.Contains(wl.PartSerialID) && wl.PartSerialID != excludeID) l.Add(wl.PartSerialID); } } return l; } //Case 11 /// /// A List of Guid's of workorder item status selected /// anywhere in this work orders workorder items collection. /// /// Used to determine which inactive status still need to be added /// to list for existing workorders /// /// public System.Collections.Generic.List ListOfWorkorderItemStatusSelected() { System.Collections.Generic.List l = new System.Collections.Generic.List(); foreach (WorkorderItem wi in this.WorkorderItems) { if (!l.Contains(wi.WorkorderStatusID)) l.Add(wi.WorkorderStatusID); } return l; } //case 1121 /// /// A List of Guid's of workorder item priorities selected /// anywhere in this work orders workorder items collection. /// /// Used to determine which inactive priorities still need to be added /// to list for existing workorders /// /// public System.Collections.Generic.List ListOfWorkorderItemPrioritiesSelected() { System.Collections.Generic.List l = new System.Collections.Generic.List(); foreach (WorkorderItem wi in this.WorkorderItems) { if (!l.Contains(wi.PriorityID)) l.Add(wi.PriorityID); } return l; } //case 1121 /// /// A List of Guid's of workorder item types selected /// anywhere in this work orders workorder items collection. /// /// Used to determine which inactive types still need to be added /// to list for existing workorders /// /// public System.Collections.Generic.List ListOfWorkorderItemTypesSelected() { System.Collections.Generic.List l = new System.Collections.Generic.List(); foreach (WorkorderItem wi in this.WorkorderItems) { if (!l.Contains(wi.TypeID)) l.Add(wi.TypeID); } return l; } //Case 360 tax codes /// /// A List of Guid's of tax codes selected /// anywhere in this work order. /// /// /// public System.Collections.Generic.List ListOfTaxCodesSelected() { System.Collections.Generic.List l = new System.Collections.Generic.List(); foreach (WorkorderItem wi in this.WorkorderItems) { foreach (WorkorderItemLabor wl in wi.Labors) { if (!l.Contains(wl.TaxRateSaleID)) l.Add(wl.TaxRateSaleID); } foreach (WorkorderItemTravel wt in wi.Travels) { if (!l.Contains(wt.TaxRateSaleID)) l.Add(wt.TaxRateSaleID); } foreach (WorkorderItemPart wp in wi.Parts) { if (!l.Contains(wp.TaxPartSaleID)) l.Add(wp.TaxPartSaleID); } foreach (WorkorderItemMiscExpense we in wi.Expenses) { if (!l.Contains(we.ChargeTaxCodeID)) l.Add(we.ChargeTaxCodeID); } foreach (WorkorderItemLoan wa in wi.Loans) { if (!l.Contains(wa.TaxCodeID)) l.Add(wa.TaxCodeID); } } return l; } //Added 04-Nov-2006 the following bunch of properties for AyaNova WBI /// /// Quick check if workorder is editable or not /// Workorder is not editable if insufficient rights to workorder object /// Workorder is not editable if closed=true /// Workorder is not editable if Servicecompleted=true with the single exception /// of ServiceCompleted which can be checked for using the IsServicecompletedEditable property /// public bool IsEditable { get { if (Rights < SecurityLevelTypes.ReadWrite) return false; if (Closed) return false; if (WorkorderType == WorkorderTypes.Service && ServiceCompleted) return false; return true; } } /// /// Confirms if service completed can be changed or not /// Use in conjunction with IsEditable to handle /// UI enablement of edit controls or to check before /// updating through API /// public bool IsServiceCompletedEditable { get { if (Rights < SecurityLevelTypes.ReadWrite) return false; if (Closed) return false; return true; } } /// /// Quick check if workorder item is editable or not /// First checks if workorder is editable, if yes then checks rights /// to WorkorderItem object /// public bool IsWorkorderItemEditable//case 1562 { get { if (!IsEditable) return false; if (AyaBizUtils.Right(RootObjectTypes.WorkorderItem) < (int)SecurityLevelTypes.ReadWrite) return false; return true; } } /// /// Quick check if workorder item is deletable or not /// First checks if workorder is editable, if yes then checks rights /// to WorkorderItem object /// public bool IsWorkorderItemDeletable//case 1562 { get { if (!IsEditable) return false; if (AyaBizUtils.Right(RootObjectTypes.WorkorderItem) < (int)SecurityLevelTypes.ReadWriteDelete) return false; return true; } } /// /// Quick check if workorder item child is editable or not /// First checks IsWorkorderItemEditable, if yes then checks rights /// to object type specified /// /// (note that it doesn't check if the type is a valid child object of a workorder item or not, only /// what the current users rights to it are.) /// public bool IsWorkorderItemChildEditable(RootObjectTypes WorkorderItemChildObjectType)//case 1562 { if (!IsWorkorderItemEditable) return false; if (AyaBizUtils.Right(WorkorderItemChildObjectType) < (int)SecurityLevelTypes.ReadWrite) return false; return true; } /// /// Quick check if workorder item child can be deleted. /// (note that it doesn't check if the type is a valid child object of a workorder item or not, only /// what the current users rights to it are.) /// public bool IsWorkorderItemChildDeletable(RootObjectTypes WorkorderItemChildObjectType)//case 1562 { if (!IsWorkorderItemEditable) return false; if (AyaBizUtils.Right(WorkorderItemChildObjectType) < (int)SecurityLevelTypes.ReadWriteDelete) return false; return true; } /// /// Quick check if workorder item child is viewable or not /// public bool IsWorkorderItemChildViewable(RootObjectTypes WorkorderItemChildObjectType)//case 1975 { return (AyaBizUtils.Right(WorkorderItemChildObjectType) > (int)SecurityLevelTypes.NoAccess); } /// /// Fetches effective rights to workorder item child object /// taking into account the rights to the Workorder, the WorkorderItem and /// also the state of the workorder (closed/service completed etc) /// public SecurityLevelTypes WorkorderItemChildEffectiveRights(RootObjectTypes WorkorderItemChildObjectType)//case 1975 { if (!IsWorkorderItemEditable) return SecurityLevelTypes.ReadOnly; return (SecurityLevelTypes)AyaBizUtils.Right(WorkorderItemChildObjectType); } /// /// Confirms if Invoice number can be changed or not /// Invoice number can only be changed if a workorder is set /// to service completed=true and not closed /// (and user has sufficient rights) /// public bool IsInvoiceNumberEditable { get { if (Rights < SecurityLevelTypes.ReadWrite) return false; if (Closed) return false; if (!ServiceCompleted) return false; return true; } } /// /// Confirms if workorder status can be changed or not /// public bool IsWorkorderStatusEditable { get { if (Rights < SecurityLevelTypes.ReadWrite) return false; if (Closed) return false; return true; } } /// /// Confirms if workorder can be signed or not /// Signature can only be changed if a workorder is set /// to service completed=true and not closed /// (and user has sufficient rights) /// public bool IsSignable { get { if (Rights < SecurityLevelTypes.ReadWrite) return false; if (Closed) return false; if (!ServiceCompleted) return false; return true; } } /// /// Returns true if workorder type is WorkorderTypes.Service /// public bool IsServiceWorkorder { get { return (WorkorderType == WorkorderTypes.Service); } } /// /// Returns true if workorder type is WorkorderTypes.TemplateService /// public bool IsServiceTemplateWorkorder { get { return (WorkorderType == WorkorderTypes.TemplateService); } } /// /// Returns true if workorder type is WorkorderTypes.TemplateQuote /// public bool IsQuoteTemplateWorkorder { get { return (WorkorderType == WorkorderTypes.TemplateQuote); } } /// /// Returns true if workorder type is WorkorderTypes.TemplatePreventiveMaintenance /// public bool IsPreventiveMaintenanceTemplateWorkorder { get { return (WorkorderType == WorkorderTypes.TemplatePreventiveMaintenance); } } /// /// Returns true if workorder type is WorkorderTypes.Service /// public bool IsTemplate { get { if (WorkorderType == WorkorderTypes.TemplateService || WorkorderType == WorkorderTypes.TemplateQuote || WorkorderType == WorkorderTypes.TemplatePreventiveMaintenance ) return true; return false; } } /// /// Returns true if sufficient rights and workorder is not closed /// or service completed /// public bool IsDeleteable { get { if (Closed) return false; if (Rights < SecurityLevelTypes.ReadWriteDelete) return false; if (ServiceCompleted) return false; //case 875 - this property is used by wbi only so far and //should have had this check originally if (HasPartRequestsOnOrder) return false; return true; } } /// /// Returns true if sufficient rights to save workorder and workorder is not closed /// /// public bool IsSaveAllowed { get { if (Closed) return false; if (Rights < SecurityLevelTypes.ReadWrite) return false; return true; } } /// /// Returns true if sufficient rights to /// change close by date /// (Object.WorkorderService.CloseByDate) /// and workorder is editable /// /// public bool IsCloseByDateAllowed { get { if (!IsEditable) return false; if (AyaBizUtils.Right("Object.WorkorderService.CloseByDate") < (int)SecurityLevelTypes.ReadWrite) return false; return true; } } /// /// Returns true if sufficient rights to /// outside service fields /// (Object.WorkorderItemOutsideService) /// and workorder is editable /// /// public bool IsOutsideServiceAllowed { get { if (!IsEditable) return false; if (AyaBizUtils.Right("Object.WorkorderItemOutsideService") < (int)SecurityLevelTypes.ReadWrite) return false; return true; } } /// /// Returns true if workorder is closeable /// Closeable=sufficient rights and workorder is in a state where /// it can be closed. /// /// This is primarily used to enable UI buttons to close the work order. /// public bool IsCloseAllowed { get { //Case 350 - rewrote this to work properly bool bIsCloseAllowed = true; if (!this.ServiceCompleted) bIsCloseAllowed = false; if (bIsCloseAllowed && AyaBizUtils.Right("Object.Workorder.Close") < (int)SecurityLevelTypes.ReadWrite) bIsCloseAllowed = false; if (bIsCloseAllowed && Rights < SecurityLevelTypes.ReadWrite) bIsCloseAllowed = false; if (bIsCloseAllowed && this.Closed) bIsCloseAllowed = false; return bIsCloseAllowed; } } /// /// Returns true if workorder is reopenable /// reopenable=sufficient rights and workorder is in a state where /// it can be closed. /// /// This is primarily used to enable UI buttons to reopen the work order. /// public bool IsReopenAllowed { get { //Case 350 - rewrote this to work properly if (!this.Closed) return false; if (!User.IsAdmin && !AyaBizUtils.Lite)//case 1172 return false; return true; } } //Case 455 /// /// Diagnostic method used to determine what has been changed /// in any node of the workorder hiearchy /// (this method is used for development testing and diagnosis /// during utility and add-on software development) /// public string WhatsDirty { get { if (!IsDirty) return "Nothing"; System.Text.StringBuilder sb = new System.Text.StringBuilder(); sb.Append("Dirty (changed and unsaved) objects in workorder tree:\r\n"); if (base.IsDirty) sb.Append("WorkorderHeader\r\n"); if ((this.WorkorderType == WorkorderTypes.PreventiveMaintenance || this.WorkorderType == WorkorderTypes.TemplatePreventiveMaintenance) && mWorkorderPreventiveMaintenance.IsDirty) sb.Append("WorkorderPreventiveMaintenance\r\n"); if ((this.WorkorderType == WorkorderTypes.Quote || this.WorkorderType == WorkorderTypes.TemplateQuote) && mQuote.IsDirty) sb.Append("WorkOrderQuote\r\n"); if ((this.WorkorderType == WorkorderTypes.Service || this.WorkorderType == WorkorderTypes.TemplateService) && mService.IsDirty) sb.Append("WorkorderService\r\n"); if (mDocs.IsDirty) sb.Append("AssignedDocs\r\n"); if (mWorkorderItems.IsDirty) { sb.Append("The following WorkorderItems are dirty:\r\n"); foreach (WorkorderItem wi in this.mWorkorderItems) { if (wi.IsDirty) { sb.Append("Item: " + wi.TechNotes + "\r\n"); if (wi.Expenses.IsDirty) sb.Append("\tExpenses\r\n"); if (wi.Labors.IsDirty) sb.Append("\tLabors\r\n"); if (wi.Loans.IsDirty) sb.Append("\tLoans\r\n"); if (wi.OutsideService.IsDirty) sb.Append("\tOutsideService\r\n"); if (wi.PartRequests.IsDirty) sb.Append("\tPartRequests\r\n"); if (wi.Parts.IsDirty) sb.Append("\tParts\r\n"); if (wi.ScheduledUsers.IsDirty) sb.Append("\tScheduledUsers\r\n"); if (wi.Travels.IsDirty) sb.Append("\tTravels\r\n"); } } } return sb.ToString(); } } /// /// Diagnostic method used to determine what business rules are broken /// in any node of the workorder hiearchy /// (this method is used for development testing and diagnosis /// during utility and add-on software development) /// public string WhatsBroken { get { if (IsValid) return "Nothing"; System.Text.StringBuilder sb = new System.Text.StringBuilder(); sb.Append("Objects with broken rules in workorder tree:\r\n"); if (!base.IsValid) { sb.AppendLine("WorkorderHeader broken rules:"); sb.AppendLine(base.BrokenRulesText); } if ((this.WorkorderType == WorkorderTypes.PreventiveMaintenance || this.WorkorderType == WorkorderTypes.TemplatePreventiveMaintenance) && (!mWorkorderPreventiveMaintenance.IsValid)) sb.AppendLine("WorkorderPreventiveMaintenance\r\n" + mWorkorderPreventiveMaintenance.BrokenRulesText); if ((this.WorkorderType == WorkorderTypes.Quote || this.WorkorderType == WorkorderTypes.TemplateQuote) && (!mQuote.IsValid)) sb.AppendLine("WorkOrderQuote\r\n" + mQuote.BrokenRulesText); if ((this.WorkorderType == WorkorderTypes.Service || this.WorkorderType == WorkorderTypes.TemplateService) && (!mService.IsValid)) sb.AppendLine("WorkorderService\r\n" + mService.BrokenRulesText); foreach (WorkorderItem wi in this.mWorkorderItems) { if (!wi.IsValid) { sb.AppendLine("WorkorderItem: " + wi.TechNotes); if (!wi.Expenses.IsValid) { foreach (WorkorderItemMiscExpense i in wi.Expenses) { if (!i.IsValid) sb.AppendLine("\tExpense (name) " + i.Name + "\r\n" + i.BrokenRulesText); } } if (!wi.Labors.IsValid) { foreach (WorkorderItemLabor i in wi.Labors) { if (!i.IsValid) sb.AppendLine("\tLabor (start date time)" + i.ServiceStartDate.ToString() + "\r\n" + i.BrokenRulesText); } } if (!wi.Loans.IsValid) { foreach (WorkorderItemLoan i in wi.Loans) { if (!i.IsValid) sb.AppendLine("\tLoan (out date) " + i.OutDate.ToString() + "\r\n" + i.BrokenRulesText); } } if (!wi.OutsideService.IsValid) sb.AppendLine("\tOutsideService\r\n" + wi.OutsideService.BrokenRulesText); if (!wi.PartRequests.IsValid) { foreach (WorkorderItemPartRequest i in wi.PartRequests) { if (!i.IsValid) sb.AppendLine("\tPartRequest (qty) " + i.Quantity.ToString() + "\r\n" + i.BrokenRulesText); } } if (!wi.Parts.IsValid) { foreach (WorkorderItemPart i in wi.Parts) { if (!i.IsValid) sb.AppendLine("\tPart (price - qty) " + i.Price.ToString() + " - " + i.Quantity.ToString() + "\r\n" + i.BrokenRulesText); } } if (!wi.ScheduledUsers.IsValid) { foreach (WorkorderItemScheduledUser i in wi.ScheduledUsers) { if (!i.IsValid) sb.AppendLine("\tScheduledUser (start date) " + i.StartDate.ToString() + "\r\n" + i.BrokenRulesText); } } if (!wi.Travels.IsValid) { foreach (WorkorderItemTravel i in wi.Travels) { if (!i.IsValid) sb.AppendLine("\tTravel (start date time)" + i.TravelStartDate.ToString() + "\r\n" + i.BrokenRulesText); } } } } return sb.ToString(); } } /// /// Name and address to display on work order form /// or template type name if it's a template /// public string NameAndAddress { get { if (IsTemplate) return EnumDescConverter.GetEnumDescription(RootObjectTypeFromWorkorderType(mWorkorderType)); else { //Need a selected Client to be able to do this //If there isn't one, then bail if (ClientID == Guid.Empty) { return LocalizedTextTable.GetLocalizedTextDirect("Unit.Label.CompanyOwned"); } //retrieve the client record Client c = Client.GetItemNoMRU(ClientID); StringBuilder b = new StringBuilder(); b.Append(c.Name); b.Append("\r\n"); b.Append(c.GoToAddress.FullAddress); b.Append("\r\n"); b.Append(c.GetPrimaryContactDefaultContactInfo()); if (c.TechNotes != "") { b.Append(LocalizedTextTable.GetLocalizedTextDirect("Client.Label.TechNotes")); b.Append(":\r\n"); b.Append(c.TechNotes); } return b.ToString(); } } } /// /// RootObjectType and id suitable /// for FollowUp schedulemarkers /// (returns the derived RootObjectType and /// accompanying ID. I.E. if this workorder /// is a quote then the typeandid is a rootobjectypes.quote /// and the id is of the quote object itself, not the workorder) /// public TypeAndID FollowTypeAndID { get { RootObjectTypes rotype = Workorder.RootObjectTypeFromWorkorderType(this.WorkorderType); switch (this.WorkorderType) { case WorkorderTypes.Quote: case WorkorderTypes.TemplateQuote: return new TypeAndID(rotype, mQuote.ID); case WorkorderTypes.Service: case WorkorderTypes.TemplateService: return new TypeAndID(RootObjectTypes.Workorder, mID); case WorkorderTypes.PreventiveMaintenance: case WorkorderTypes.TemplatePreventiveMaintenance: return new TypeAndID(rotype, this.mWorkorderPreventiveMaintenance.ID); default: return new TypeAndID(RootObjectTypes.Nothing, Guid.Empty); } } } /// /// Flag - indicates if current user can open the wiki page for this object /// See method for details /// /// This is cached for the lifetime of this object /// public bool CanWiki//case 73 { get { if (!bCanWiki.HasValue) bCanWiki = WikiPage.ShowWikiLink(RootObjectType, mID); return bCanWiki.Value; } } //cache the result in case the UI calls this repeatedly private bool? bCanWiki = null; /// /// Flag - indicates if this object has a wikipage or not /// /// public bool HasWiki//case 1630 { get { return WikiPageExistanceChecker.WikiPageExists(mID); } } //case 941 /// /// Returns the general RootObjectType associated with this workorder's workorder type /// public RootObjectTypes RootObjectType { get { switch (mWorkorderType) { case WorkorderTypes.Service: return RootObjectTypes.WorkorderService;//case 1387 case WorkorderTypes.Quote: return RootObjectTypes.WorkorderQuote; case WorkorderTypes.PreventiveMaintenance: return RootObjectTypes.WorkorderPreventiveMaintenance; case WorkorderTypes.TemplateService: return RootObjectTypes.WorkorderServiceTemplate; case WorkorderTypes.TemplateQuote: return RootObjectTypes.WorkorderQuoteTemplate; case WorkorderTypes.TemplatePreventiveMaintenance: return RootObjectTypes.WorkorderPreventiveMaintenanceTemplate; default: return RootObjectTypes.Nothing; } } } //case 866 /// /// Generate a unit for the current workorder's client /// from specified WorkorderItemPartID for current work order /// /// A new unit ready to edit public Unit GenerateUnitFromPart(Guid WorkorderItemPartID) { WorkorderItemPart src = null; foreach (WorkorderItem wi in mWorkorderItems) { if (src != null) break; foreach (WorkorderItemPart wip in wi.Parts) { if (wip.ID == WorkorderItemPartID) { src = wip; break; } } } if (src == null) throw new System.ApplicationException("GenerateUnitFromPart -> WorkorderItemPartID specified not found in Workorder"); Part p = Part.GetItem(src.PartID); Client c = Client.GetItem(mClientID); string sSerial = DBUtil.CurrentWorkingDateTime.ToString(); if (src.PartSerialID != Guid.Empty) { sSerial = PartSerial.GetSerialNumberFromPartSerialID(src.PartSerialID); } Unit u = Unit.NewItem(); u.Active = true; u.ClientID = mClientID; u.Serial = sSerial; u.Description = p.Name; Address.Copy(c.GoToAddress, u.GoToAddress); u.PurchasedDate = this.mService.ServiceDate; u.BoughtHere = true; return u; } //case 866 /// /// Check to see if current thread user has more than read only rights to Object.Unit /// public bool CanGenerateUnit { get { return (AyaBizUtils.Right("Object.Unit") > (int)SecurityLevelTypes.ReadOnly); } } //case 1387 /// /// Current user's rights to this service workorder / quote / pm / template /// public SecurityLevelTypes Rights { get { return mRights; } } /// /// Read only UI convenience method to get the unique visible ID number presented to the user /// regardless of type (quote, service, pm, template) /// public string uiDisplayVisibleIDNumber { get { switch (mWorkorderType) { case WorkorderTypes.Service: case WorkorderTypes.TemplateService: return mService.ServiceNumber.ToString(); case WorkorderTypes.Quote: case WorkorderTypes.TemplateQuote: return mQuote.QuoteNumber.ToString(); case WorkorderTypes.PreventiveMaintenance: case WorkorderTypes.TemplatePreventiveMaintenance: return mWorkorderPreventiveMaintenance.PreventiveMaintenanceNumber.ToString(); default: return "Workorder->uiDisplayVisibleIDNumber unsupported type:" + mWorkorderType.ToString(); } } } /// /// Read only UI convenience method to get the name of the client /// public string uiDisplayclientName { get { return NameFetcher.GetItem(RootObjectTypes.Client, mClientID, true).RecordName; } } //case 1975 /// /// Read only UI convenience method to get the status of the workorder regardless of type /// (quote, service, pm) /// public string uiDisplayHeaderStatus { get { switch (mWorkorderType) { case WorkorderTypes.Service: case WorkorderTypes.TemplateService: { if (mService.WorkorderStatusID == Guid.Empty) return "-"; return NameFetcher.GetItem(RootObjectTypes.WorkorderStatus, mService.WorkorderStatusID, true).RecordName; } case WorkorderTypes.Quote: case WorkorderTypes.TemplateQuote: { return EnumDescConverter.GetEnumDescription(mQuote.QuoteStatus); } case WorkorderTypes.PreventiveMaintenance: case WorkorderTypes.TemplatePreventiveMaintenance: { if (mWorkorderPreventiveMaintenance.WorkorderStatusID == Guid.Empty) return "-"; return NameFetcher.GetItem(RootObjectTypes.WorkorderStatus, mWorkorderPreventiveMaintenance.WorkorderStatusID, true).RecordName; } default: return "Workorder->uiDisplayHeaderStatus unsupported type:" + mWorkorderType.ToString(); } } } /// /// Read only UI convenience property /// true if client for this workorder has popup notes /// public bool uiHasPopupNotes { get { //insurance if (mClientID == Guid.Empty) return false; return (!string.IsNullOrWhiteSpace(ClientPopUpNotesFetcher.GetNotes(mClientID))); } } /// /// Read only UI convenience method to get popup notes for this workorder's client /// public string uiPopupNotes { get { //insurance if (mClientID == Guid.Empty) return string.Empty; return ClientPopUpNotesFetcher.GetNotes(mClientID); } } /// /// Read only UI convenience method to get this workorder's client object /// public Client uiClient { get { //insurance if (mClientID == Guid.Empty) return null; return Client.GetItemNoMRU(mClientID); } } /// /// Read only UI convenience property /// true if there is a contract in effect for this workorder /// public bool uiHasContract { get { return ContractResolved() != null; } } /// /// Read only UI convenienece property /// Resolves rights based on users security level as well as /// workorder closed / service completed status /// public SecurityLevelTypes uiResolvedRights { get { SecurityLevelTypes baseLevel = (SecurityLevelTypes)AyaBizUtils.Right(this.RootObjectType); //if they have limited rights in any case then just return them as they will be the most //limited of all rights if (baseLevel < SecurityLevelTypes.ReadWrite) return baseLevel; if (mServiceCompleted || mClosed) return SecurityLevelTypes.ReadOnly; return baseLevel; } } /// /// Read only UI convenience property /// true if this workorder can have a signature /// public bool uiCanViewSignaturePanel { get { if (mWorkorderType != WorkorderTypes.Service) return false; return true; } } //case 1975 /// /// Report key to use for summary reports for this workorder type /// public string SummaryReportKey { get { switch (mWorkorderType) { case WorkorderTypes.Service: return WorkorderServiceList.ReportKey; case WorkorderTypes.Quote: return WorkorderQuoteList.ReportKey; case WorkorderTypes.PreventiveMaintenance: return WorkorderPMList.ReportKey; default: return string.Empty; } } } //case 1975 /// /// Report key to use for detailed reports for this workorder type /// public string DetailedReportKey { get { switch (mWorkorderType) { case WorkorderTypes.Service: return WorkorderServiceDetailedReportData.ReportKey; case WorkorderTypes.Quote: return WorkorderQuoteDetailedReportData.ReportKey; case WorkorderTypes.PreventiveMaintenance: return WorkorderPMDetailedReportData.ReportKey; default: return string.Empty; } } } /// /// Read only UI convenience property /// true if this workorder can be signed /// public bool uiCanSign { get { if (mWorkorderType != WorkorderTypes.Service) return false; if (mClosed) return false; if (mRights < SecurityLevelTypes.ReadWrite) return false; if (!mServiceCompleted) return false; return true; } } /// /// Read only UI convenience property /// true if this workorder has a signature /// public bool uiHasSignature { get { if (mWorkorderType != WorkorderTypes.Service) return false; return mService.Signature.HasSignature; } } /// /// 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.Workorder") ) ); } #endregion #region System.object overrides /// /// /// /// public override string ToString() { return "WO Header" + mID.ToString(); } /// /// /// /// /// public override bool Equals(Object obj) { if (obj == null || GetType() != obj.GetType()) return false; Workorder c = (Workorder)obj; return mID == c.mID; } /// /// /// /// public override int GetHashCode() { return ("WO Header" + mID.ToString()).GetHashCode(); } #endregion #region Searching /// /// Returns a search result object based on search terms /// for the ID specified /// /// /// /// public static SearchResult GetSearchResult(Guid ID, string[] searchTerms) { SearchResult sr = new SearchResult(); System.Text.StringBuilder sb = new System.Text.StringBuilder(); SafeDataReader dr = null; try { dr = DBUtil.GetReaderFromSQLString( "SELECT aWorkorder.aID, aWorkorder.aCreated, aWorkorder.aModified, " + " aWorkorder.aModifier, aWorkorder.aCreator, aWorkorder.ATemplateDescription, " +//Case 670 " aClient.aName, aClient.aRegionID AS ACLIENTREGION, aWorkorder.aInternalReferenceNumber, " + " aWorkorder.aCustomerReferenceNumber, " + " aWorkorder.aCustomerContactName, aWorkorder.aSummary, " + " aWorkorder.aWorkorderType, aWorkorderQuote.aQuoteNumber, " + " aWorkorderService.aServiceNumber, aWorkorderPreventiveMaintenance.aPreventiveMaintenanceNumber " + "FROM aWorkorder LEFT OUTER JOIN aWorkorderPreventiveMaintenance " + "ON aWorkorder.aID " + "= aWorkorderPreventiveMaintenance.aWorkorderID " + "LEFT OUTER JOIN aWorkorderService ON aWorkorder.aID " + "= aWorkorderService.aWorkorderID LEFT OUTER " + "JOIN aWorkorderQuote ON aWorkorder.aID = aWorkorderQuote.aWorkorderID " + "LEFT OUTER JOIN aClient " + "ON aWorkorder.aClientID = aClient.aID WHERE " + "(aWorkorder.aID = @ID)" , ID); if (!dr.Read()) return new SearchResult();//DBUtil.ThrowFetchError("SearchResult for WorkorderID: " + ID.ToString()); if (!AyaBizUtils.InYourRegion(dr.GetGuid("ACLIENTREGION"))) return new SearchResult();//case 58 WorkorderTypes wotype = (WorkorderTypes)dr.GetInt16("aWorkorderType"); if ((SecurityLevelTypes)AyaBizUtils.Right(Workorder.RootObjectTypeFromWorkorderType(wotype)) < SecurityLevelTypes.ReadOnly) return new SearchResult(); switch (wotype) { case WorkorderTypes.PreventiveMaintenance: sr.Description = LocalizedTextTable.GetLocalizedTextDirect("O.PreventiveMaintenance") + " " + dr.GetInt32("aPreventiveMaintenanceNumber").ToString() + " " + dr.GetString("aName"); break; case WorkorderTypes.Quote: sr.Description = LocalizedTextTable.GetLocalizedTextDirect("O.WorkorderQuote") + " " + dr.GetInt32("aQuoteNumber").ToString() + " " + dr.GetString("aName"); break; case WorkorderTypes.Service: sr.Description = LocalizedTextTable.GetLocalizedTextDirect("O.Workorder") + " " + dr.GetInt32("aServiceNumber").ToString() + " " + dr.GetString("aName"); break; case WorkorderTypes.TemplatePreventiveMaintenance: sr.Description = LocalizedTextTable.GetLocalizedTextDirect("O.PreventiveMaintenanceTemplate") + " " + dr.GetInt32("aPreventiveMaintenanceNumber").ToString() + " " + dr.GetString("aName"); break; case WorkorderTypes.TemplateQuote: sr.Description = LocalizedTextTable.GetLocalizedTextDirect("O.WorkorderQuoteTemplate") + " " + dr.GetInt32("aQuoteNumber").ToString() + " " + dr.GetString("aName"); break; case WorkorderTypes.TemplateService: sr.Description = LocalizedTextTable.GetLocalizedTextDirect("O.WorkorderServiceTemplate") + " " + dr.GetInt32("aServiceNumber").ToString() + " " + dr.GetString("aName"); break; } sb.Append(sr.Description); sb.Append(" "); sb.Append(dr.GetString("aTemplateDescription")); sb.Append(" "); sb.Append(dr.GetString("aInternalReferenceNumber")); sb.Append(" "); sb.Append(dr.GetString("aCustomerReferenceNumber")); sb.Append(" "); sb.Append(dr.GetString("aCustomerContactName")); sb.Append(" "); sb.Append(dr.GetString("aSummary")); sb.Append(" "); 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.Workorder; return sr; } #endregion #region Static methods #region New item /// /// Generate a new workorder / quote / pm from /// supplied template and client ID /// /// REquired /// Required /// public static Workorder NewItem(Guid TemplateID, Guid ClientID) { if (Guid.Empty == ClientID) { throw new System.ApplicationException("Workorder->NewItem(ClientID): Required, empty is not a valid value"); } Workorder t = Workorder.GetItem(TemplateID); if (null == t || !t.IsTemplate) { throw new System.ApplicationException("Workorder->NewItem(TemplateID): TemplateID not found or is not a template"); } Workorder dest = null; switch (t.WorkorderType) { case WorkorderTypes.TemplatePreventiveMaintenance: dest = NewItem(WorkorderTypes.PreventiveMaintenance); break; case WorkorderTypes.TemplateQuote: dest = NewItem(WorkorderTypes.Quote); break; case WorkorderTypes.TemplateService: dest = NewItem(WorkorderTypes.Service); break; } dest.ClientID = ClientID; return CopyTemplateToWorkorder(t, dest); } /// /// Create a new workorder overload to accept a root object type rather than a enum /// /// Must be a valid workorder type of RootObject, i.e. quote, pm, service /// New workorder public static Workorder NewItem(RootObjectTypes rootObjectType) { WorkorderTypes wt = WorkorderTypeFromRootObjectType(rootObjectType); if (wt == WorkorderTypes.Unknown) throw new System.ApplicationException("Workorder->NewItem(RootObjectType) \"" + rootObjectType.ToString() + "\" is not a valid root object type to match a work order"); return NewItem(wt); } /// /// Create new Workorder /// /// Workorder public static Workorder NewItem(WorkorderTypes WorkorderType) { Workorder c; //set rights //case 1387 c = new Workorder(); c.mRights = (SecurityLevelTypes)AyaBizUtils.Right(Workorder.RootObjectTypeFromWorkorderType(WorkorderType)); if (AyaBizUtils.IsGenerator || c.mRights > SecurityLevelTypes.ReadOnly) { //case 3646 removed this block ////Count the workorders if it's a trial, sb no more than 30 //if(AyaBizUtils.Trial) //{ // if(WorkorderCountFetcher.GetItem()>29) // throw new TrialException(LocalizedTextTable.GetLocalizedTextDirect("Error.Trial.Restricted")); //} //c = new Workorder(); c.WorkorderType = WorkorderType; switch (WorkorderType) { case WorkorderTypes.PreventiveMaintenance: case WorkorderTypes.TemplatePreventiveMaintenance: c.mWorkorderPreventiveMaintenance = WorkorderPreventiveMaintenance.NewItem(c); break; case WorkorderTypes.Quote: case WorkorderTypes.TemplateQuote: c.mQuote = WorkorderQuote.NewItem(c); break; case WorkorderTypes.Service: case WorkorderTypes.TemplateService: c.mService = WorkorderService.NewItem(c); break; } //A new workorder *always* has at least one workorder item, //so add it now... c.WorkorderItems.Add(c); return c; } else throw new System.Security.SecurityException( string.Format( LocalizedTextTable.GetLocalizedTextDirect("Error.Security.NotAuthorizedToCreate"), LocalizedTextTable.GetLocalizedTextDirect("O.Workorder"))); } #endregion #region Get by various id's /// /// Fetch existing Workorder, track MRU /// /// Workorder /// Workorder Guid public static Workorder GetItem(Guid _ID) { return GetItemMRU(_ID, true); } /// /// Fetch existing Workorder, don't track in MRU list /// /// Workorder /// Workorder Guid public static Workorder GetItemNoMRU(Guid _ID) { return GetItemMRU(_ID, false); } /// /// Determines current user's rights to specific workorder object /// be it a quote or service workorder or pm or template etc. /// /// /// public static SecurityLevelTypes RightsToWorkorder(Guid _ID) { //case 2018 commented out try block so proper error is bubbled up instead of security exception //try //{ //case 3626 if (_ID == Guid.Empty) return SecurityLevelTypes.NoAccess; return (SecurityLevelTypes)AyaBizUtils.Right(Workorder.RootObjectTypeFromWorkorderType(WorkorderTypeFetcher.GetItem(_ID))); //} //catch { } //return SecurityLevelTypes.NoAccess; } /// /// Get item optionally track MRU /// See /// /// /// /// public static Workorder GetItemMRU(Guid _ID, bool TrackMRU) { if (ScheduleableUserCountFetcher.GetItem() > AyaBizUtils.GlobalX.ScheduleableUsers) { throw new System.Security.SecurityException( "\r\nLICENSE VIOLATION\r\n\r\n" + "AyaNova has detected an attempt to circumvent AyaNova licensing.\r\n\r\n" + "This database is licensed for " + AyaBizUtils.GlobalX.ScheduleableUsers.ToString() + " scheduleable users\r\n" + "Currently there are " + ScheduleableUserCountFetcher.GetItem().ToString() + " scheduleable users active.\r\n\r\n" + "All AyaNova accounts other than Manager have been suspended until\r\n" + "the extra scheduleable users that are not licensed are\r\n" + "set inactive, removed or changed to non-scheduleable users\r\n" + "to bring this database back into license compliance.\r\n\r\n" + "Directly editing the AyaNova database can lead to lost or damaged data\r\n" + "Please ensure no one tampers with the AyaNova database in future.\r\n\r\n" + "** License violations are logged for the protection of the licensee and licensor **"); } if (RightsToWorkorder(_ID) > SecurityLevelTypes.NoAccess) return (Workorder)DataPortal.Fetch(new Criteria(RootObjectTypes.Workorder, _ID, TrackMRU)); else throw new System.Security.SecurityException( string.Format( LocalizedTextTable.GetLocalizedTextDirect("Error.Security.NotAuthorizedToRetrieve"), LocalizedTextTable.GetLocalizedTextDirect("O.Workorder"))); } /// /// Fetch existing Workorder by related item ID /// /// Given a rootobjectType and an ID opens the work order that hosts /// that rootobject type and ID /// /// (Tracks MRU) /// /// Workorder /// Related object type i.e. /// Related object from a workorder hiearchy (child/grandchild etc) Guid /// /// Fetching a work order when you only know the workorderitempart object's ID /// /// Workorder w = Workorder.GetWorkorderByRelative(RootObjectTypes.WorkorderItemPart, WorkorderItemPartID); /// /// public static Workorder GetWorkorderByRelative(RootObjectTypes RootObject, Guid _ID) { return GetWorkorderByRelativeMRU(RootObject, _ID, true); } /// /// Fetch existing Workorder by related item ID /// /// Given a rootobjectType and an ID opens the work order that hosts /// that rootobject type and ID /// /// (Does NOT track MRU) /// /// Workorder /// Related object type i.e. /// Related object from a workorder hiearchy (child/grandchild etc) Guid /// /// Fetching a work order when you only know the workorderitempart object's ID /// /// Workorder w = Workorder.GetWorkorderByRelative(RootObjectTypes.WorkorderItemPart, WorkorderItemPartID); /// /// public static Workorder GetWorkorderByRelativeNoMRU(RootObjectTypes RootObject, Guid _ID) { return GetWorkorderByRelativeMRU(RootObject, _ID, false); } /// /// Fetch existing Workorder by related item ID /// /// Given a rootobjectType and an ID opens the work order that hosts /// that rootobject type and ID /// /// (Optionally track MRU) /// /// Workorder /// Related object type i.e. /// Related object from a workorder hiearchy (child/grandchild etc) Guid /// True for MRU tracking (so it appears in users most recently used list in UI) or false to "stealth" open it with no MRU tracking /// /// Fetching a work order when you only know the workorderitempart object's ID /// /// Workorder w = Workorder.GetWorkorderByRelative(RootObjectTypes.WorkorderItemPart, WorkorderItemPartID); /// /// public static Workorder GetWorkorderByRelativeMRU(RootObjectTypes RootObject, Guid _ID, bool TrackMRU) { switch (RootObject) { case RootObjectTypes.WorkorderItem: break; case RootObjectTypes.WorkorderItemLabor: break; case RootObjectTypes.WorkorderItemTravel: break; case RootObjectTypes.WorkorderItemScheduledUser: break; case RootObjectTypes.WorkorderItemOutsideService: break; case RootObjectTypes.WorkorderItemPartRequest: break; case RootObjectTypes.WorkorderItemPart: break; case RootObjectTypes.WorkorderPreventiveMaintenance: break; case RootObjectTypes.WorkorderQuote: break; case RootObjectTypes.WorkorderService: break; case RootObjectTypes.WorkorderItemLoan: break; case RootObjectTypes.WorkorderItemMiscExpense: break; default: throw new System.NotSupportedException("GetWorkorderByDescendant(" + RootObject.ToString() + ") not supported"); } Guid gWorkorderID = WorkorderIDFetcher.GetWorkorderByRelative(RootObject, _ID); if (RightsToWorkorder(gWorkorderID) > SecurityLevelTypes.NoAccess) { return (Workorder)DataPortal.Fetch(new Criteria(RootObjectTypes.Workorder, gWorkorderID, TrackMRU)); } else throw new System.Security.SecurityException( string.Format( LocalizedTextTable.GetLocalizedTextDirect("Error.Security.NotAuthorizedToRetrieve"), LocalizedTextTable.GetLocalizedTextDirect("O.Workorder"))); } /// /// Retrieve internal ID from Workorder Number and type /// /// Service number, Quote number or Preventive maintenance number /// Type of workorder (service, quote, pm) /// Guid of workorder in database or Guid.Empty if not found or input string invalid /// /// See WorkorderTypes enum public static Guid GetIDFromNumber(string WorkorderNumber, WorkorderTypes Type) { return WorkorderInternalIDFetcher.GetItem(WorkorderNumber, Type); } //case 1477 /// /// Given a workorder's child or grandchild ID returns /// that object /// /// Type of workorder descendant, i.e. WorkorderItemPart. /// Note: this is not a RootObjectType, this is a generic parameter and is the actual object desired (see example). /// Unique GUID ID of descendant object /// The related object /// /// Example usage - populating an asp.net combo box with saved grid filters /// /// WorkorderItemScheduledUser wis = Workorder.GetDescendant<WorkorderItemScheduledUser>(MyWoItemSchedUserObjectID); /// /// public static T GetDescendant(Guid ID) { T bizobject = default(T); RootObjectTypes objectType = RootObjectTypes.Nothing; #region Type to RootObjectType if (typeof(T) == typeof(WorkorderItem)) { objectType = RootObjectTypes.WorkorderItem; } else if (typeof(T) == typeof(WorkorderItemLabor)) { objectType = RootObjectTypes.WorkorderItemLabor; } else if (typeof(T) == typeof(WorkorderItemTravel)) { objectType = RootObjectTypes.WorkorderItemTravel; } else if (typeof(T) == typeof(WorkorderItemScheduledUser)) { objectType = RootObjectTypes.WorkorderItemScheduledUser; } else if (typeof(T) == typeof(WorkorderItemOutsideService)) { objectType = RootObjectTypes.WorkorderItemOutsideService; } else if (typeof(T) == typeof(WorkorderItemPartRequest)) { objectType = RootObjectTypes.WorkorderItemPartRequest; } else if (typeof(T) == typeof(WorkorderItemPart)) { objectType = RootObjectTypes.WorkorderItemPart; } else if (typeof(T) == typeof(WorkorderPreventiveMaintenance)) { objectType = RootObjectTypes.WorkorderPreventiveMaintenance; } else if (typeof(T) == typeof(WorkorderQuote)) { objectType = RootObjectTypes.WorkorderQuote; } else if (typeof(T) == typeof(WorkorderService)) { objectType = RootObjectTypes.WorkorderService; } else if (typeof(T) == typeof(WorkorderItemLoan)) { objectType = RootObjectTypes.WorkorderItemLoan; } else if (typeof(T) == typeof(WorkorderItemMiscExpense)) { objectType = RootObjectTypes.WorkorderItemMiscExpense; } #endregion #region Check if supported switch (objectType) { case RootObjectTypes.WorkorderItem: break; case RootObjectTypes.WorkorderItemLabor: break; case RootObjectTypes.WorkorderItemTravel: break; case RootObjectTypes.WorkorderItemScheduledUser: break; case RootObjectTypes.WorkorderItemOutsideService: break; case RootObjectTypes.WorkorderItemPartRequest: break; case RootObjectTypes.WorkorderItemPart: break; case RootObjectTypes.WorkorderItemLoan: break; case RootObjectTypes.WorkorderItemMiscExpense: break; default: throw new System.NotSupportedException("GetDescendant(" + typeof(T).ToString() + ") not supported"); } #endregion #region Fetch and return Workorder w = Workorder.GetWorkorderByRelativeNoMRU(objectType, ID); if (objectType == RootObjectTypes.WorkorderItem) return (T)(object)w.WorkorderItems[ID]; WorkorderItem wi = w.WorkorderItems[w.GetWorkorderItemIDFromDescendant(objectType, ID)]; switch (objectType) { case RootObjectTypes.WorkorderItemLabor: return (T)(object)wi.Labors[ID.ToString()]; case RootObjectTypes.WorkorderItemTravel: return (T)(object)wi.Travels[ID.ToString()]; case RootObjectTypes.WorkorderItemScheduledUser: return (T)(object)wi.ScheduledUsers[ID.ToString()]; case RootObjectTypes.WorkorderItemOutsideService: return (T)(object)wi.OutsideService; case RootObjectTypes.WorkorderItemPartRequest: return (T)(object)wi.PartRequests[ID.ToString()]; case RootObjectTypes.WorkorderItemPart: return (T)(object)wi.Parts[ID.ToString()]; case RootObjectTypes.WorkorderItemLoan: return (T)(object)wi.Loans[ID.ToString()]; case RootObjectTypes.WorkorderItemMiscExpense: return (T)(object)wi.Expenses[ID.ToString()]; } #endregion return bizobject; } #endregion #region Reopen /// /// Reopen closed Workorder /// has no effect on already open work orders /// /// Workorder GUID public static void Reopen(Guid _ID) { if (RightsToWorkorder(_ID) > SecurityLevelTypes.ReadOnly) Workorder.WorkorderReopener.Open(_ID); else throw new System.Security.SecurityException( string.Format( LocalizedTextTable.GetLocalizedTextDirect("Error.Security.NotAuthorizedToChange"), LocalizedTextTable.GetLocalizedTextDirect("O.Workorder"))); } #endregion #region Template copy-inator /// /// Generate a work order from a template /// /// /// /// private static Workorder CopyTemplateToWorkorder(Workorder t, Workorder dest) { //get the empty workorderitem that is automatically //created on a new workorder so we can delete it later Guid DummyWorkorderItemID = dest.WorkorderItems[0].ID; RatePickList rates = null; if (dest.ContractResolved() == null) rates = RatePickList.GetList(false); else rates = RatePickList.GetListWithContract(dest.ContractIDResolved()); //WORKORDER HEADER dest.CustomerContactName = t.CustomerContactName; dest.CustomerReferenceNumber = t.CustomerReferenceNumber; dest.InternalReferenceNumber = t.InternalReferenceNumber; dest.Onsite = t.Onsite; dest.ProjectID = t.ProjectID; dest.Summary = t.Summary; dest.WorkorderCategoryID = t.WorkorderCategoryID; //case 3160 RootObjectTypes destExactType = RootObjectTypes.Nothing; //Workorder type header switch (t.WorkorderType) { case WorkorderTypes.TemplateService: { //Definitely NOT copy these two see case 588 //dest.WorkorderService.CloseByDate = t.WorkorderService.CloseByDate; //dest.WorkorderService.ServiceDate = t.WorkorderService.ServiceDate; dest.WorkorderService.WorkorderStatusID = t.WorkorderService.WorkorderStatusID; destExactType = RootObjectTypes.WorkorderService; } break; case WorkorderTypes.TemplateQuote: { dest.WorkorderQuote.Introduction = t.WorkorderQuote.Introduction; dest.WorkorderQuote.PreparedByID = t.WorkorderQuote.PreparedByID; //case 589 //dest.WorkorderQuote.QuoteRequestDate = t.WorkorderQuote.QuoteRequestDate; dest.WorkorderQuote.QuoteStatus = t.WorkorderQuote.QuoteStatus; //case 589 //dest.WorkorderQuote.ValidUntilDate = t.WorkorderQuote.ValidUntilDate; destExactType = RootObjectTypes.WorkorderQuote; } break; case WorkorderTypes.TemplatePreventiveMaintenance: { dest.WorkorderPreventiveMaintenance.Active = false;//for protection //case 778 dest.WorkorderPreventiveMaintenance.DayOfTheWeek = t.WorkorderPreventiveMaintenance.DayOfTheWeek; dest.WorkorderPreventiveMaintenance.GenerateSpan = t.WorkorderPreventiveMaintenance.GenerateSpan; dest.WorkorderPreventiveMaintenance.GenerateSpanUnit = t.WorkorderPreventiveMaintenance.GenerateSpanUnit; //Case 590 //dest.WorkorderPreventiveMaintenance.NextServiceDate = t.WorkorderPreventiveMaintenance.NextServiceDate; // dest.WorkorderPreventiveMaintenance.StopGeneratingDate = t.WorkorderPreventiveMaintenance.StopGeneratingDate; dest.WorkorderPreventiveMaintenance.ThresholdSpan = t.WorkorderPreventiveMaintenance.ThresholdSpan; dest.WorkorderPreventiveMaintenance.ThresholdSpanUnit = t.WorkorderPreventiveMaintenance.ThresholdSpanUnit; dest.WorkorderPreventiveMaintenance.WorkorderStatusID = t.WorkorderPreventiveMaintenance.WorkorderStatusID; destExactType = RootObjectTypes.WorkorderPreventiveMaintenance; } break; } //WORKORDERITEMS foreach (WorkorderItem wisource in t.WorkorderItems) { WorkorderItem widest = dest.WorkorderItems.Add(dest); widest.Custom0 = wisource.Custom0; widest.Custom1 = wisource.Custom1; widest.Custom2 = wisource.Custom2; widest.Custom3 = wisource.Custom3; widest.Custom4 = wisource.Custom4; widest.Custom5 = wisource.Custom5; widest.Custom6 = wisource.Custom6; widest.Custom7 = wisource.Custom7; widest.Custom8 = wisource.Custom8; widest.Custom9 = wisource.Custom9; widest.PriorityID = wisource.PriorityID; //Case 588 //widest.RequestDate = wisource.RequestDate; widest.Summary = wisource.Summary; widest.TechNotes = wisource.TechNotes; widest.TypeID = wisource.TypeID; //widest.UnitID = wisource.UnitID; //widest.WarrantyService = wisource.WarrantyService; widest.WorkorderItemUnitServiceTypeID = wisource.WorkorderItemUnitServiceTypeID; widest.WorkorderStatusID = wisource.WorkorderStatusID; //case 3132 //cache part prices if required PartPickList partList = null; if (t.mTemplateFreshPrice) partList = PartPickList.GetListFromIDList(t.ListOfPartsSelected()); //PARTS foreach (WorkorderItemPart partsource in wisource.Parts) { WorkorderItemPart partdest = widest.Parts.Add(widest); partdest.Description = partsource.Description; partdest.Discount = partsource.Discount; partdest.DiscountType = partsource.DiscountType; partdest.PartID = partsource.PartID; partdest.PartWarehouseID = partsource.PartWarehouseID; //case 3132: update prices here if the template says to do that if (t.mTemplateFreshPrice) { if (partdest.PartID != Guid.Empty) { partdest.Cost = partList[partdest.PartID].Cost; partdest.Price = partList[partdest.PartID].Retail; } } else { partdest.Cost = partsource.Cost; partdest.Price = partsource.Price; } if (AyaBizUtils.GlobalSettings.UseInventory) { //case 2076 if (dest.IsServiceWorkorder) { partdest.QuantityReserved = partsource.Quantity; partdest.Quantity = 0; } else { partdest.Quantity = partsource.Quantity; } } else partdest.Quantity = partsource.Quantity; partdest.TaxPartSaleID = partsource.TaxPartSaleID; } //********************************************************** //Part requests would be here if copying a service workorder //********************************************************** //SCHEDULED USERS foreach (WorkorderItemScheduledUser usersource in wisource.ScheduledUsers) { WorkorderItemScheduledUser userdest = widest.ScheduledUsers.Add(widest); //Case 862 Case 890 if (usersource.ServiceRateID != Guid.Empty && rates.Contains(usersource.ServiceRateID) && rates[usersource.ServiceRateID].Selectable) userdest.ServiceRateID = usersource.ServiceRateID; userdest.EstimatedQuantity = usersource.EstimatedQuantity; //Case 588 //userdest.StartDate = usersource.StartDate; //userdest.StopDate = usersource.StopDate; userdest.UserID = usersource.UserID; } //LABOR foreach (WorkorderItemLabor laborsource in wisource.Labors) { WorkorderItemLabor labordest = widest.Labors.Add(widest); labordest.NoChargeQuantity = laborsource.NoChargeQuantity; labordest.ServiceDetails = laborsource.ServiceDetails; //Case 862 Case 890 if (laborsource.ServiceRateID != Guid.Empty && rates.Contains(laborsource.ServiceRateID) && rates[laborsource.ServiceRateID].Selectable) labordest.ServiceRateID = laborsource.ServiceRateID; labordest.ServiceRateQuantity = laborsource.ServiceRateQuantity; //Case 588 //labordest.ServiceStartDate = laborsource.ServiceStartDate; //labordest.ServiceStopDate = laborsource.ServiceStopDate; labordest.TaxRateSaleID = laborsource.TaxRateSaleID; labordest.UserID = laborsource.UserID; } //********************************************************** //Expenses if service workorder //********************************************************** if (t.IsServiceTemplateWorkorder) { foreach (WorkorderItemMiscExpense e in wisource.Expenses) { WorkorderItemMiscExpense exdest = widest.Expenses.Add(widest); exdest.ChargeAmount = e.ChargeAmount; exdest.ChargeTaxCodeID = e.ChargeTaxCodeID; exdest.ChargeToClient = e.ChargeToClient; exdest.Description = e.Description; exdest.Name = e.Name; exdest.ReimburseUser = e.ReimburseUser; exdest.TaxPaid = e.TaxPaid; exdest.TotalCost = e.TotalCost; exdest.UserID = e.UserID; //exdest.WorkorderItemID = e.WorkorderItemID; } } //********************************************************** //Loans for a service workorder (but we've deced they won't be templatizable) //********************************************************** //TRAVEL foreach (WorkorderItemTravel travelsource in wisource.Travels) { WorkorderItemTravel traveldest = widest.Travels.Add(widest); traveldest.TravelDetails = travelsource.TravelDetails; //Case 862 Case 890 if (travelsource.TravelRateID != Guid.Empty && rates.Contains(travelsource.TravelRateID) && rates[travelsource.TravelRateID].Selectable) traveldest.TravelRateID = travelsource.TravelRateID; traveldest.TravelRateQuantity = travelsource.TravelRateQuantity; //Case 588 //traveldest.TravelStartDate = travelsource.TravelStartDate; //traveldest.TravelStopDate = travelsource.TravelStopDate; traveldest.TaxRateSaleID = travelsource.TaxRateSaleID; traveldest.UserID = travelsource.UserID; traveldest.Distance = travelsource.Distance; traveldest.Notes = travelsource.Notes; traveldest.NoChargeQuantity = travelsource.NoChargeQuantity; } //TASKS foreach (WorkorderItemTask tasksource in wisource.Tasks) { WorkorderItemTask taskdest = widest.Tasks.Add(widest); taskdest.TaskGroupID = tasksource.TaskGroupID; taskdest.TaskID = tasksource.TaskID; } //********************************************************** //Outside service would be here if copying a service workorder //********************************************************** }//foreach workorderitem loop ////Delete the auto-created dummy workorder item ////if there are more than it present if (dest.WorkorderItems.Count > 1) dest.WorkorderItems.RemoveAt(0); //case 3160 //copy wikipage from template to created wo if (t.HasWiki) { WikiPage.DuplicateItem(new TypeAndID(RootObjectTypes.Workorder, t.ID), new TypeAndID(destExactType, dest.ID)); } return dest; } #endregion template copyinator #region Generate service workorder from quote /// /// Generates a service workorder from a Quote type Workorder /// /// ID of Quote /// A new service workorder public static Workorder NewServiceWorkorderFromQuote(Guid SourceWorkorderID) { //revamped for case 1387 now calls the one single static newitem method //Fetch the source workorder and verify it's a quote Workorder source = Workorder.GetItemNoMRU(SourceWorkorderID); if (source.WorkorderType != WorkorderTypes.Quote) throw new NotSupportedException(LocalizedTextTable.GetLocalizedTextDirect("Workorder.Label.Error.SourceInvalidType")); //Ok, so far so goo, create the new one bool bUseInventory = AyaBizUtils.GlobalSettings.UseInventory; //NOTE: THIS DOES *NOT* CALL THE SHARED NEWITEM METHOD IN WORKORDER //Workorder dest = new Workorder(); //dest.WorkorderType=WorkorderTypes.Service; //dest.mService=WorkorderService.NewItem(dest); Workorder dest = Workorder.NewItem(WorkorderTypes.Service); //get the empty workorderitem that is automatically //created on a new workorder so we can delete it later Guid DummyWorkorderItemID = dest.WorkorderItems[0].ID; //WORKORDER HEADER dest.ClientID = source.ClientID; // dest.Custom0=source.Custom0; // dest.Custom1=source.Custom1; // dest.Custom2=source.Custom2; // dest.Custom3=source.Custom3; // dest.Custom4=source.Custom4; // dest.Custom5=source.Custom5; // dest.Custom6=source.Custom6; // dest.Custom7=source.Custom7; // dest.Custom8=source.Custom8; // dest.Custom9=source.Custom9; dest.CustomerContactName = source.CustomerContactName; dest.CustomerReferenceNumber = source.CustomerReferenceNumber; dest.mFromQuoteID = source.WorkorderQuote.ID; dest.InternalReferenceNumber = source.InternalReferenceNumber; dest.Onsite = source.Onsite; dest.ProjectID = source.ProjectID; //dest.RegionID=source.RegionID; dest.Summary = source.Summary; dest.WorkorderCategoryID = source.WorkorderCategoryID; //WORKORDERITEMS foreach (WorkorderItem wisource in source.WorkorderItems) { WorkorderItem widest = dest.WorkorderItems.Add(dest); widest.Custom0 = wisource.Custom0; widest.Custom1 = wisource.Custom1; widest.Custom2 = wisource.Custom2; widest.Custom3 = wisource.Custom3; widest.Custom4 = wisource.Custom4; widest.Custom5 = wisource.Custom5; widest.Custom6 = wisource.Custom6; widest.Custom7 = wisource.Custom7; widest.Custom8 = wisource.Custom8; widest.Custom9 = wisource.Custom9; widest.PriorityID = wisource.PriorityID; widest.RequestDate = wisource.RequestDate; widest.Summary = wisource.Summary; widest.TechNotes = wisource.TechNotes; widest.TypeID = wisource.TypeID; widest.UnitID = wisource.UnitID; widest.WarrantyService = wisource.WarrantyService; widest.WorkorderItemUnitServiceTypeID = wisource.WorkorderItemUnitServiceTypeID; widest.WorkorderStatusID = wisource.WorkorderStatusID; //PARTS foreach (WorkorderItemPart partsource in wisource.Parts) { WorkorderItemPart partdest = widest.Parts.Add(widest); partdest.Cost = partsource.Cost; partdest.Description = partsource.Description; partdest.Discount = partsource.Discount; partdest.DiscountType = partsource.DiscountType; partdest.PartID = partsource.PartID; partdest.PartWarehouseID = partsource.PartWarehouseID; partdest.Price = partsource.Price; if (bUseInventory) { partdest.QuantityReserved = partsource.Quantity; partdest.Quantity = 0; } else partdest.Quantity = partsource.Quantity; partdest.TaxPartSaleID = partsource.TaxPartSaleID; } //********************************************************** //Part requests would be here if copying a service workorder //********************************************************** //SCHEDULED USERS foreach (WorkorderItemScheduledUser usersource in wisource.ScheduledUsers) { WorkorderItemScheduledUser userdest = widest.ScheduledUsers.Add(widest); userdest.EstimatedQuantity = usersource.EstimatedQuantity; userdest.ServiceRateID = usersource.ServiceRateID; userdest.StartDate = usersource.StartDate; userdest.StopDate = usersource.StopDate; userdest.UserID = usersource.UserID; } //LABOR foreach (WorkorderItemLabor laborsource in wisource.Labors) { WorkorderItemLabor labordest = widest.Labors.Add(widest); labordest.NoChargeQuantity = laborsource.NoChargeQuantity; labordest.ServiceDetails = laborsource.ServiceDetails; labordest.ServiceRateID = laborsource.ServiceRateID; labordest.ServiceRateQuantity = laborsource.ServiceRateQuantity; labordest.ServiceStartDate = laborsource.ServiceStartDate; labordest.ServiceStopDate = laborsource.ServiceStopDate; labordest.TaxRateSaleID = laborsource.TaxRateSaleID; labordest.UserID = laborsource.UserID; } //********************************************************** //Expenses would be here if copying a service workorder //********************************************************** //********************************************************** //Loans would be here if copying a service workorder //********************************************************** //TRAVEL foreach (WorkorderItemTravel travelsource in wisource.Travels) { WorkorderItemTravel traveldest = widest.Travels.Add(widest); traveldest.TravelDetails = travelsource.TravelDetails; traveldest.TravelRateID = travelsource.TravelRateID; traveldest.TravelRateQuantity = travelsource.TravelRateQuantity; traveldest.TravelStartDate = travelsource.TravelStartDate; traveldest.TravelStopDate = travelsource.TravelStopDate; traveldest.TaxRateSaleID = travelsource.TaxRateSaleID; traveldest.UserID = travelsource.UserID; traveldest.Distance = travelsource.Distance; traveldest.Notes = travelsource.Notes; traveldest.NoChargeQuantity = travelsource.NoChargeQuantity; } //TASKS foreach (WorkorderItemTask tasksource in wisource.Tasks) { WorkorderItemTask taskdest = widest.Tasks.Add(widest); taskdest.TaskGroupID = tasksource.TaskGroupID; taskdest.TaskID = tasksource.TaskID; } //********************************************************** //Outside service would be here if copying a service workorder //********************************************************** }//foreach workorderitem loop //case 1387 //Delete the auto-created dummy workorder item //if there are more than it present if (dest.WorkorderItems.Count > 1) dest.WorkorderItems.RemoveAt(0); //case 1630 //copy wikipage from quote to service workorder if (dest.CanWiki && source.HasWiki) { try { WikiPage wpSource = WikiPage.GetItem(new TypeAndID(RootObjectTypes.WorkorderQuote, source.ID)); WikiPage wpDest = WikiPage.GetItem(new TypeAndID(RootObjectTypes.WorkorderService, dest.ID)); wpDest.SetContent(wpSource.GetContent()); wpDest.Save(); } catch { }; } return dest; } #endregion #region Generate service workorder from PM /// /// Generates a service workorder from a PM type Workorder /// /// ID of PM /// A new service workorder public static Workorder NewServiceWorkorderFromPM(Guid SourceWorkorderID) { //Fetch the source workorder and verify it's a PM Workorder source = Workorder.GetItemNoMRU(SourceWorkorderID); if (source.WorkorderType != WorkorderTypes.PreventiveMaintenance) throw new NotSupportedException(LocalizedTextTable.GetLocalizedTextDirect("Workorder.Label.Error.SourceInvalidType")); //if it's inactive then there is nothing to Process //this is a backstop, the list the pm is being generated off of //should have already selected only active items that have not reached their //expiry date if (source.WorkorderPreventiveMaintenance.Active == false) { throw new System.ApplicationException("NewServiceWorkorderFromPM: source PM workorder is not active"); } if (source.WorkorderPreventiveMaintenance.StopGeneratingDate != System.DBNull.Value && source.WorkorderPreventiveMaintenance.dtStopGeneratingDate < DBUtil.CurrentWorkingDateTime) { throw new System.ApplicationException("NewServiceWorkorderFromPM: source PM workorder is past StopGeneratingDate"); } //Ok, so far so good, create the new one bool bUseInventory = AyaBizUtils.GlobalSettings.UseInventory; //case 1387 Workorder dest = Workorder.NewItem(WorkorderTypes.Service); ////NOTE: THIS DOESN'T CALL THE SHARED NEW ITEM METHOD //Workorder dest = new Workorder(); //dest.WorkorderType=WorkorderTypes.Service; //dest.mService=WorkorderService.NewItem(dest); #region copy workorder data //WORKORDER HEADER dest.ClientID = source.ClientID; dest.CustomerContactName = source.CustomerContactName; dest.CustomerReferenceNumber = source.CustomerReferenceNumber; dest.mFromPMID = source.WorkorderPreventiveMaintenance.ID; dest.InternalReferenceNumber = source.InternalReferenceNumber; dest.Onsite = source.Onsite; dest.ProjectID = source.ProjectID; //dest.RegionID=source.RegionID; dest.Summary = source.Summary; dest.WorkorderCategoryID = source.WorkorderCategoryID; //PM SPECIFIC dest.WorkorderService.WorkorderStatusID = source.WorkorderPreventiveMaintenance.WorkorderStatusID; //Date stuff (note that date is assumed to have been advanced the last time a workorder was //generated off the pm (see bottom of this method for that)) dest.WorkorderService.ServiceDate = source.WorkorderPreventiveMaintenance.NextServiceDate; //WORKORDERITEMS foreach (WorkorderItem wisource in source.WorkorderItems) { WorkorderItem widest = dest.WorkorderItems.Add(dest); widest.Custom0 = wisource.Custom0; widest.Custom1 = wisource.Custom1; widest.Custom2 = wisource.Custom2; widest.Custom3 = wisource.Custom3; widest.Custom4 = wisource.Custom4; widest.Custom5 = wisource.Custom5; widest.Custom6 = wisource.Custom6; widest.Custom7 = wisource.Custom7; widest.Custom8 = wisource.Custom8; widest.Custom9 = wisource.Custom9; widest.PriorityID = wisource.PriorityID; widest.RequestDate = wisource.RequestDate; widest.Summary = wisource.Summary; widest.TechNotes = wisource.TechNotes; widest.TypeID = wisource.TypeID; widest.UnitID = wisource.UnitID; widest.WarrantyService = wisource.WarrantyService; widest.WorkorderItemUnitServiceTypeID = wisource.WorkorderItemUnitServiceTypeID; widest.WorkorderStatusID = wisource.WorkorderStatusID; //PARTS foreach (WorkorderItemPart partsource in wisource.Parts) { WorkorderItemPart partdest = widest.Parts.Add(widest); partdest.Cost = partsource.Cost; partdest.Description = partsource.Description; partdest.Discount = partsource.Discount; partdest.DiscountType = partsource.DiscountType; partdest.PartID = partsource.PartID; partdest.PartWarehouseID = partsource.PartWarehouseID; partdest.Price = partsource.Price; if (bUseInventory) { partdest.QuantityReserved = partsource.Quantity; partdest.Quantity = 0; } else partdest.Quantity = partsource.Quantity; partdest.TaxPartSaleID = partsource.TaxPartSaleID; } //********************************************************** //Part requests would be here if copying a service workorder //********************************************************** //SCHEDULED USERS foreach (WorkorderItemScheduledUser usersource in wisource.ScheduledUsers) { WorkorderItemScheduledUser userdest = widest.ScheduledUsers.Add(widest); userdest.EstimatedQuantity = usersource.EstimatedQuantity; userdest.ServiceRateID = usersource.ServiceRateID; userdest.StartDate = usersource.StartDate; userdest.StopDate = usersource.StopDate; userdest.UserID = usersource.UserID; } //LABOR foreach (WorkorderItemLabor laborsource in wisource.Labors) { WorkorderItemLabor labordest = widest.Labors.Add(widest); labordest.NoChargeQuantity = laborsource.NoChargeQuantity; labordest.ServiceDetails = laborsource.ServiceDetails; labordest.ServiceRateID = laborsource.ServiceRateID; labordest.ServiceRateQuantity = laborsource.ServiceRateQuantity; labordest.ServiceStartDate = laborsource.ServiceStartDate; labordest.ServiceStopDate = laborsource.ServiceStopDate; labordest.TaxRateSaleID = laborsource.TaxRateSaleID; labordest.UserID = laborsource.UserID; } //********************************************************** //Expenses would be here if copying a service workorder //********************************************************** //********************************************************** //Loans would be here if copying a service workorder //********************************************************** //TRAVEL foreach (WorkorderItemTravel travelsource in wisource.Travels) { WorkorderItemTravel traveldest = widest.Travels.Add(widest); traveldest.TravelDetails = travelsource.TravelDetails; traveldest.TravelRateID = travelsource.TravelRateID; traveldest.TravelRateQuantity = travelsource.TravelRateQuantity; traveldest.TravelStartDate = travelsource.TravelStartDate; traveldest.TravelStopDate = travelsource.TravelStopDate; traveldest.TaxRateSaleID = travelsource.TaxRateSaleID; traveldest.UserID = travelsource.UserID; traveldest.Distance = travelsource.Distance; traveldest.Notes = travelsource.Notes; traveldest.NoChargeQuantity = travelsource.NoChargeQuantity; } //TASKS foreach (WorkorderItemTask tasksource in wisource.Tasks) { WorkorderItemTask taskdest = widest.Tasks.Add(widest); taskdest.TaskGroupID = tasksource.TaskGroupID; taskdest.TaskID = tasksource.TaskID; } //********************************************************** //Outside service would be here if copying a service workorder //********************************************************** }//foreach workorderitem loop //case 1387 //Delete the auto-created dummy workorder item //if there are more than it present if (dest.WorkorderItems.Count > 1) dest.WorkorderItems.RemoveAt(0); #endregion copy workorder data //Now save it to ensure it was created properly so //that we know it's now safe to advance the next service date and all others //case 868 previously didn't set dest to result of save causing it to be a copy dest = (Workorder)dest.Save(); #region Calculate reschedule dates //Get the current next service date for calcs DateTime dtNext = GetDateFromSpanAndUnit(source.WorkorderPreventiveMaintenance.dtNextServiceDate, source.WorkorderPreventiveMaintenance.GenerateSpanUnit, source.WorkorderPreventiveMaintenance.GenerateSpan); //Get to the desired day of the week if necessary... if (source.mWorkorderPreventiveMaintenance.DayOfTheWeek != AyaDayOfWeek.AnyDayOfWeek) { DayOfWeek desired = AyaToSystemDayOfWeek(source.mWorkorderPreventiveMaintenance.DayOfTheWeek); while (dtNext.DayOfWeek != desired) { dtNext = dtNext.AddDays(1); } } //Get the time span to add to all the other relevant dates on teh workorder to match //the amount the next service date has been advanced System.TimeSpan tsToNext = dtNext - source.WorkorderPreventiveMaintenance.dtNextServiceDate; #endregion //Will the next workorder service date fall after the //stop generating date? if (source.WorkorderPreventiveMaintenance.StopGeneratingDate != System.DBNull.Value && source.WorkorderPreventiveMaintenance.dtStopGeneratingDate < dtNext) { //Yes it will, so set it to inactive and bail out source.WorkorderPreventiveMaintenance.Active = false; source.Save(); return dest; } #region Reschedule PM source.WorkorderPreventiveMaintenance.dtNextServiceDate = dtNext; //Calcs the generate date (threshold date) source.WorkorderPreventiveMaintenance.SetGenerateDate(); //WORKORDERITEMS foreach (WorkorderItem wisource in source.WorkorderItems) { wisource.RequestDate = wisource.RequestDate; //PARTS //no date changes required //SCHEDULED USERS foreach (WorkorderItemScheduledUser usersource in wisource.ScheduledUsers) { //Changed: 2-Oct-2006 //check to not add a date if the original date was empty if (usersource.StartDate != System.DBNull.Value) usersource.dtStartDate = usersource.dtStartDate.Add(tsToNext); if (usersource.StopDate != System.DBNull.Value) usersource.dtStopDate = usersource.dtStopDate.Add(tsToNext); } //LABOR foreach (WorkorderItemLabor laborsource in wisource.Labors) { //Changed: 2-Oct-2006 //check to not add a date if the original date was empty if (laborsource.ServiceStartDate != System.DBNull.Value) laborsource.dtServiceStartDate = laborsource.dtServiceStartDate.Add(tsToNext); if (laborsource.ServiceStopDate != System.DBNull.Value) laborsource.dtServiceStopDate = laborsource.dtServiceStopDate.Add(tsToNext); } //********************************************************** //Expenses would be here if copying a service workorder //********************************************************** //********************************************************** //Loans would be here if copying a service workorder //********************************************************** //TRAVEL foreach (WorkorderItemTravel travelsource in wisource.Travels) { //Changed: 2-Oct-2006 //check to not add a date if the original date was empty if (travelsource.TravelStartDate != DBNull.Value) travelsource.dtTravelStartDate = travelsource.dtTravelStartDate.Add(tsToNext); if (travelsource.TravelStopDate != DBNull.Value) travelsource.dtTravelStopDate = travelsource.dtTravelStopDate.Add(tsToNext); } //TASKS //********************************************************** //Outside service would be here if copying a service workorder //********************************************************** }//foreach workorderitem loop #endregion reschedule pm //Ok, Source PM is now rescheduled, save it //case 1959 try catch block added to prevent infinite generation issue try { source = (Workorder)source.Save(); } catch (Exception exx) { dest.Delete(); dest.Save(); //crack the exception while (exx.InnerException != null) exx = exx.InnerException; Memo mwarn = Memo.NewItem(); mwarn.ToID = User.AdministratorID; //case 3826 if (User.CurrentUserType == UserTypes.Utility) { //Utility accounts should not be sending memos, it fucks up downstream //trying to view the memo, also it's confusing mwarn.FromID = User.AdministratorID; } else { mwarn.FromID = User.CurrentThreadUserID; } mwarn.Subject = "SYSTEM WARNING: Preventive Maintenance WO PROBLEM"; StringBuilder sb = new StringBuilder(); sb.AppendLine("This is an automated message sent on behalf of the current user from the \"NewServiceWorkorderFromPM\" module."); sb.AppendLine("This message concerns Preventive Maintenance workorder number " + source.WorkorderPreventiveMaintenance.PreventiveMaintenanceNumber.ToString()); sb.AppendLine("The Preventive Maintenance workorder had an error when trying to save it during generation of a service workorder."); sb.AppendLine("This kind of problem could result in loop which generates a very large number of identical service workorders."); sb.AppendLine("In order to prevent this the operation has been stopped and this message generated so you can fix the problem with the source PM workorder."); sb.AppendLine("See below for details and examine the PM workorder for problems or contact support@ayanova.com for help with the information in this message."); sb.AppendLine("Here are the details of the error preventing save:"); sb.AppendLine("================================="); sb.AppendLine("Exception saving source PM:"); sb.AppendLine(exx.Message); sb.AppendLine("================================="); string sSourceErr = source.GetBrokenRulesString(); if (!string.IsNullOrWhiteSpace(sSourceErr)) { sb.AppendLine("Broken business rules on PM object:"); sb.AppendLine(sSourceErr); sb.AppendLine("=============================="); } mwarn.Message = sb.ToString(); mwarn.Save(); throw new System.ApplicationException("Workorder->NewServiceWorkorderFromPM: Error during service workorder generation. Memo with details sent to Administrator account."); } //case 1630 //copy wikipage from pm to service workorder if (dest.CanWiki && source.HasWiki) { try { WikiPage wpSource = WikiPage.GetItem(new TypeAndID(RootObjectTypes.WorkorderPreventiveMaintenance, source.ID)); WikiPage wpDest = WikiPage.GetItem(new TypeAndID(RootObjectTypes.WorkorderService, dest.ID)); wpDest.SetContent(wpSource.GetContent()); wpDest.Save(); } catch { }; } return dest; } #endregion gen service wo from pm #region Copy workorder item from one workorder to another /// /// Copy workorder item and all it's children /// from current workorder to indicated destination workorder /// /// Destination workorder can not be closed and must be the same client /// /// If inventory is being tracked then all quantities from parts /// are copied over as reserved quantities and need to be re-selected on destination /// to control inventory / serial numbers etc /// /// Loans, Outside service, part requests and Expenses are NOT copied as they are /// situation specific. /// /// /// /// public static void CopyWorkorderItem(Guid ToWorkorderID, Guid SourceWorkorderID, Guid SourceWorkorderItemID) { //Do they have enough rights to do this? if (RightsToWorkorder(ToWorkorderID) < SecurityLevelTypes.ReadWrite) throw new System.Security.SecurityException( string.Format( LocalizedTextTable.GetLocalizedTextDirect("Error.Security.NotAuthorizedToCreate"), LocalizedTextTable.GetLocalizedTextDirect("O.Workorder"))); //Fetch the source workorder and verify it's got the source workorder item in it Workorder source = Workorder.GetItemNoMRU(SourceWorkorderID); if (!source.WorkorderItems.Contains(SourceWorkorderItemID)) DBUtil.ThrowFetchError("WorkorderItemID: " + SourceWorkorderItemID.ToString()); //Ok, so far so good, create the new one bool bUseInventory = AyaBizUtils.GlobalSettings.UseInventory; Workorder dest = Workorder.GetItemNoMRU(ToWorkorderID); if (dest.Closed == true || dest.ServiceCompleted == true) throw new System.ApplicationException ( string.Format ( LocalizedTextTable.GetLocalizedTextDirect("Error.Security.NotAuthorizedToChange"), LocalizedTextTable.GetLocalizedTextDirect("O.Workorder") ) ); //WORKORDERITEM WorkorderItem wisource = source.WorkorderItems[SourceWorkorderItemID]; WorkorderItem widest = dest.WorkorderItems.Add(dest); widest.Custom0 = wisource.Custom0; widest.Custom1 = wisource.Custom1; widest.Custom2 = wisource.Custom2; widest.Custom3 = wisource.Custom3; widest.Custom4 = wisource.Custom4; widest.Custom5 = wisource.Custom5; widest.Custom6 = wisource.Custom6; widest.Custom7 = wisource.Custom7; widest.Custom8 = wisource.Custom8; widest.Custom9 = wisource.Custom9; widest.PriorityID = wisource.PriorityID; widest.RequestDate = wisource.RequestDate; widest.Summary = wisource.Summary; widest.TechNotes = wisource.TechNotes; widest.TypeID = wisource.TypeID; widest.UnitID = wisource.UnitID; widest.WarrantyService = wisource.WarrantyService; widest.WorkorderItemUnitServiceTypeID = wisource.WorkorderItemUnitServiceTypeID; widest.WorkorderStatusID = wisource.WorkorderStatusID; //PARTS foreach (WorkorderItemPart partsource in wisource.Parts) { WorkorderItemPart partdest = widest.Parts.Add(widest); partdest.Cost = partsource.Cost; partdest.Description = partsource.Description; partdest.Discount = partsource.Discount; partdest.DiscountType = partsource.DiscountType; partdest.PartID = partsource.PartID; partdest.PartWarehouseID = partsource.PartWarehouseID; partdest.Price = partsource.Price; if (bUseInventory) { partdest.QuantityReserved = partsource.Quantity; partdest.Quantity = 0; } else partdest.Quantity = partsource.Quantity; partdest.TaxPartSaleID = partsource.TaxPartSaleID; } //********************************************************** //Part requests would be here if copying a service workorder //********************************************************** //SCHEDULED USERS foreach (WorkorderItemScheduledUser usersource in wisource.ScheduledUsers) { WorkorderItemScheduledUser userdest = widest.ScheduledUsers.Add(widest); userdest.EstimatedQuantity = usersource.EstimatedQuantity; userdest.ServiceRateID = usersource.ServiceRateID; userdest.StartDate = usersource.StartDate; userdest.StopDate = usersource.StopDate; userdest.UserID = usersource.UserID; } //LABOR foreach (WorkorderItemLabor laborsource in wisource.Labors) { WorkorderItemLabor labordest = widest.Labors.Add(widest); labordest.NoChargeQuantity = laborsource.NoChargeQuantity; labordest.ServiceDetails = laborsource.ServiceDetails; labordest.ServiceRateID = laborsource.ServiceRateID; labordest.ServiceRateQuantity = laborsource.ServiceRateQuantity; labordest.ServiceStartDate = laborsource.ServiceStartDate; labordest.ServiceStopDate = laborsource.ServiceStopDate; labordest.TaxRateSaleID = laborsource.TaxRateSaleID; labordest.UserID = laborsource.UserID; } //********************************************************** //Expenses would be here if copying a service workorder //********************************************************** //********************************************************** //Loans would be here if copying a service workorder //********************************************************** //TRAVEL foreach (WorkorderItemTravel travelsource in wisource.Travels) { WorkorderItemTravel traveldest = widest.Travels.Add(widest); traveldest.TravelDetails = travelsource.TravelDetails; traveldest.TravelRateID = travelsource.TravelRateID; traveldest.TravelRateQuantity = travelsource.TravelRateQuantity; traveldest.TravelStartDate = travelsource.TravelStartDate; traveldest.TravelStopDate = travelsource.TravelStopDate; traveldest.TaxRateSaleID = travelsource.TaxRateSaleID; traveldest.UserID = travelsource.UserID; traveldest.Distance = travelsource.Distance; traveldest.Notes = travelsource.Notes; traveldest.NoChargeQuantity = travelsource.NoChargeQuantity; } //TASKS foreach (WorkorderItemTask tasksource in wisource.Tasks) { WorkorderItemTask taskdest = widest.Tasks.Add(widest); taskdest.TaskGroupID = tasksource.TaskGroupID; taskdest.TaskID = tasksource.TaskID; } //********************************************************** //Outside service would be here if copying a service workorder //********************************************************** dest.Save(); } #endregion #region Date time calcs helpers //Takes an AyaNova day of week and returns //a System.DayOfWeek //Assumes that AyaDayOfWeek is NOT "AnyDay" internal static System.DayOfWeek AyaToSystemDayOfWeek(AyaDayOfWeek day) { switch (day) { case AyaDayOfWeek.Monday: return DayOfWeek.Monday; case AyaDayOfWeek.Tuesday: return DayOfWeek.Tuesday; case AyaDayOfWeek.Wednesday: return DayOfWeek.Wednesday; case AyaDayOfWeek.Thursday: return DayOfWeek.Thursday; case AyaDayOfWeek.Friday: return DayOfWeek.Friday; case AyaDayOfWeek.Saturday: return DayOfWeek.Saturday; case AyaDayOfWeek.Sunday: return DayOfWeek.Sunday; } throw new System.ArgumentOutOfRangeException("DayOfWeekConverter: AyaDayOfWeek.AnyDayOfWeek is not supported"); } internal static DateTime GetDateFromSpanAndUnit(DateTime StartDate, AyaUnitsOfTime unit, int multiple) { switch (unit) { case AyaUnitsOfTime.Seconds: return StartDate.AddSeconds(multiple); case AyaUnitsOfTime.Minutes: return StartDate.AddMinutes(multiple); case AyaUnitsOfTime.Hours: return StartDate.AddHours(multiple); case AyaUnitsOfTime.Days: return StartDate.AddDays(multiple); case AyaUnitsOfTime.Weeks: throw new System.NotSupportedException("GetDateFromSpanAndUnit: Weeks not supported"); case AyaUnitsOfTime.Months: return StartDate.AddMonths(multiple); case AyaUnitsOfTime.Years: return StartDate.AddYears(multiple); } //fail safe: return StartDate; } #endregion date time calcs helpers #region wotype <-> rootobject converters /// /// Converts enum value to corresponding enum value /// /// /// public static WorkorderTypes WorkorderTypeFromRootObjectType(RootObjectTypes rootobject) { switch (rootobject) { case RootObjectTypes.WorkorderService: return WorkorderTypes.Service; case RootObjectTypes.WorkorderQuote: return WorkorderTypes.Quote; case RootObjectTypes.WorkorderPreventiveMaintenance: return WorkorderTypes.PreventiveMaintenance; case RootObjectTypes.WorkorderServiceTemplate: return WorkorderTypes.TemplateService; case RootObjectTypes.WorkorderQuoteTemplate: return WorkorderTypes.TemplateQuote; case RootObjectTypes.WorkorderPreventiveMaintenanceTemplate: return WorkorderTypes.TemplatePreventiveMaintenance; default: return WorkorderTypes.Unknown; } } /// /// Converts a enum value to corresponding enum value /// /// /// public static RootObjectTypes RootObjectTypeFromWorkorderType(WorkorderTypes wotype) { switch (wotype) { case WorkorderTypes.Service: return RootObjectTypes.WorkorderService; case WorkorderTypes.Quote: return RootObjectTypes.WorkorderQuote; case WorkorderTypes.PreventiveMaintenance: return RootObjectTypes.WorkorderPreventiveMaintenance; case WorkorderTypes.TemplateService: return RootObjectTypes.WorkorderServiceTemplate; case WorkorderTypes.TemplateQuote: return RootObjectTypes.WorkorderQuoteTemplate; case WorkorderTypes.TemplatePreventiveMaintenance: return RootObjectTypes.WorkorderPreventiveMaintenanceTemplate; default: return RootObjectTypes.Nothing; } } #endregion converter #endregion static methods #region Shared Notification Message Processor internal static NotifyMessage GetNotificationMessage(NotifyMessageRequestData d) { //case 1555 bool bSourceIsQuote = (d.EventType == (int)WorkorderEvent.QuoteUpdated); if (bSourceIsQuote)//case 1555 { #region Quote workorder WorkorderQuoteDescriptionFetcher wdf = WorkorderQuoteDescriptionFetcher.GetItem(d.RootObjectID); string sEventDescription = ""; string sExtraInfo = ""; switch (d.EventType) { case (int)WorkorderEvent.QuoteUpdated: sEventDescription = LocalizedTextTable.GetLocalizedTextDirect("Workorder.Label.Event.QuoteUpdated", d.Language); bSourceIsQuote = true; break; } string sMessage = sEventDescription; string sSubject = sEventDescription; NotifyMessage nm = null; if (d.Format == NotifyDeliveryMessageFormats.Brief) { sMessage += " " + LocalizedTextTable.GetLocalizedTextDirect("WorkorderQuote.Label.QuoteNumber", d.Language) + " " + wdf.WorkorderNumber + " " + wdf.ClientName + " " + sExtraInfo; 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("WorkorderQuote.Label.QuoteNumber", d.Language) + " " + wdf.WorkorderNumber; sMessage += ": " + LocalizedTextTable.GetLocalizedTextDirect("WorkorderQuote.Label.QuoteNumber", d.Language) + " " + wdf.WorkorderNumber + "\r\n" + LocalizedTextTable.GetLocalizedTextDirect("O.Client", d.Language) + ": " + wdf.ClientName + "\r\n" + sExtraInfo; nm = new NotifyMessage(sSubject, sMessage); } return nm; #endregion quote workorder } else { #region Service workorder WorkorderDescriptionFetcher wdf = WorkorderDescriptionFetcher.GetItem(d.RootObjectID); //case 1415 SmartDate sTZCloseBy = wdf.CloseByDate; if (d.TimeZoneOffset != 0) { sTZCloseBy.Date = wdf.CloseByDate.Date.ToUniversalTime().AddHours(d.TimeZoneOffset); } string sEventDescription = ""; string sExtraInfo = ""; switch (d.EventType) { case (int)WorkorderEvent.Status: sEventDescription = LocalizedTextTable.GetLocalizedTextDirect("Workorder.Label.Event.Status", d.Language); sExtraInfo = LocalizedTextTable.GetLocalizedTextDirect("O.WorkorderStatus", d.Language) + ": " + NameFetcher.GetItem("aWorkorderStatus", "aName", d.GuidValue).RecordName; break; case (int)WorkorderEvent.CloseByDatePassed: sEventDescription = LocalizedTextTable.GetLocalizedTextDirect("Workorder.Label.Event.CloseByDatePassed", d.Language); sExtraInfo = LocalizedTextTable.GetLocalizedTextDirect("WorkorderService.Label.CloseByDate", d.Language) + ": " + sTZCloseBy.ToString(); break; //case 1555 case (int)WorkorderEvent.QuoteUpdated: sEventDescription = LocalizedTextTable.GetLocalizedTextDirect("Workorder.Label.Event.QuoteUpdated", d.Language); //sExtraInfo = LocalizedTextTable.GetLocalizedTextDirect("O.WorkorderStatus", d.Language) + ": " + NameFetcher.GetItem("aWorkorderStatus", "aName", d.GuidValue).RecordName; bSourceIsQuote = true; break; } string sMessage = sEventDescription; string sSubject = sEventDescription; NotifyMessage nm = null; if (d.Format == NotifyDeliveryMessageFormats.Brief) { sMessage += " " + LocalizedTextTable.GetLocalizedTextDirect("WorkorderService.Label.ServiceNumber", d.Language) + " " + wdf.WorkorderNumber + " " + wdf.ClientName + " " + sExtraInfo; 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("WorkorderService.Label.ServiceNumber", d.Language) + " " + wdf.WorkorderNumber + "\r\n" + LocalizedTextTable.GetLocalizedTextDirect("O.Client", d.Language) + ": " + wdf.ClientName + "\r\n" + sExtraInfo; nm = new NotifyMessage(sSubject, sMessage); } return nm; #endregion service workorder } } #endregion #region DAL DATA ACCESS #region Fetch //case 53 - need to know if workorder was new before it was saved //for new workorder client notification processing private bool bWasNew = false; /// /// protected override void DataPortal_Fetch(object Criteria) { //set to false to load items initially bReadOnly = false; Criteria crit = (Criteria)Criteria; SafeDataReader dr = null; Guid WorkorderIDToFetch = crit.ID; try { switch (crit.RootObjectType) { case RootObjectTypes.Workorder: ;//Do nothing, we already have the workorder id in crit.ID break; case RootObjectTypes.WorkorderItem: WorkorderIDToFetch = DBUtil.ToGuid(DBUtil.GetScalarFromSQLString( "SELECT TOP 1 aWorkorderItem.aWorkorderID " + "FROM aWorkorderItem WHERE (aWorkorderItem.aID = @ID)" , crit.ID)); break; case RootObjectTypes.WorkorderItemLabor: WorkorderIDToFetch = DBUtil.ToGuid(DBUtil.GetScalarFromSQLString( "SELECT TOP 1 aWorkorderItem.aWorkorderID " + "FROM aWorkorderItem INNER JOIN aWorkorderItemLabor " + "ON aWorkorderItem.aID = aWorkorderItemLabor.aWorkorderItemID " + "WHERE (aWorkorderItemLabor.aID " + "= @ID)" , crit.ID)); break; //Added: 2-Oct-2006 //to support search results display case RootObjectTypes.WorkorderItemMiscExpense: WorkorderIDToFetch = DBUtil.ToGuid(DBUtil.GetScalarFromSQLString( "SELECT TOP 1 aWorkorderItem.aWorkorderID " + "FROM aWorkorderItem INNER JOIN aWorkorderItemMiscExpense " + "ON aWorkorderItem.aID = aWorkorderItemMiscExpense.aWorkorderItemID " + "WHERE (aWorkorderItemMiscExpense.aID " + "= @ID)" , crit.ID)); break; case RootObjectTypes.WorkorderItemTravel: WorkorderIDToFetch = DBUtil.ToGuid(DBUtil.GetScalarFromSQLString( "SELECT TOP 1 aWorkorderItem.aWorkorderID " + "FROM aWorkorderItem INNER JOIN aWorkorderItemTravel " + "ON aWorkorderItem.aID = aWorkorderItemTravel.aWorkorderItemID " + "WHERE (aWorkorderItemTravel.aID " + "= @ID)" , crit.ID)); break; case RootObjectTypes.WorkorderItemScheduledUser: WorkorderIDToFetch = DBUtil.ToGuid(DBUtil.GetScalarFromSQLString( "SELECT TOP 1 aWorkorderItem.aWorkorderID " + "FROM aWorkorderItem INNER JOIN aWorkorderItemScheduledUser " + "ON aWorkorderItem.aID = aWorkorderItemScheduledUser.aWorkorderItemID " + "WHERE (aWorkorderItemScheduledUser.aID " + "= @ID)" , crit.ID)); break; case RootObjectTypes.WorkorderItemOutsideService: WorkorderIDToFetch = DBUtil.ToGuid(DBUtil.GetScalarFromSQLString( "SELECT TOP 1 aWorkorderItem.aWorkorderID " + "FROM aWorkorderItem INNER JOIN aWorkorderItemOutsideService " + "ON aWorkorderItem.aID = aWorkorderItemOutsideService.aWorkorderItemID " + "WHERE (aWorkorderItemOutsideService.aID " + "= @ID)" , crit.ID)); break; case RootObjectTypes.WorkorderItemPartRequest: WorkorderIDToFetch = DBUtil.ToGuid(DBUtil.GetScalarFromSQLString( "SELECT TOP 1 aWorkorderItem.aWorkorderID " + "FROM aWorkorderItem INNER JOIN aWorkorderItemPartRequest " + "ON aWorkorderItem.aID = aWorkorderItemPartRequest.aWorkorderItemID " + "WHERE (aWorkorderItemPartRequest.aID " + "= @ID)" , crit.ID)); break; case RootObjectTypes.WorkorderItemPart: WorkorderIDToFetch = DBUtil.ToGuid(DBUtil.GetScalarFromSQLString( "SELECT TOP 1 aWorkorderItem.aWorkorderID " + "FROM aWorkorderItem INNER JOIN aWorkorderItemPart " + "ON aWorkorderItem.aID = aWorkorderItemPart.aWorkorderItemID " + "WHERE (aWorkorderItemPart.aID " + "= @ID)" , crit.ID)); break; case RootObjectTypes.WorkorderPreventiveMaintenance: WorkorderIDToFetch = DBUtil.ToGuid(DBUtil.GetScalarFromSQLString( "SELECT aWorkorderPreventiveMaintenance.aWorkorderID " + "FROM aWorkorderPreventiveMaintenance " + "WHERE (aWorkorderPreventiveMaintenance.aID " + "= @ID)" , crit.ID)); break; case RootObjectTypes.WorkorderQuote: WorkorderIDToFetch = DBUtil.ToGuid(DBUtil.GetScalarFromSQLString( "SELECT aWorkorderQuote.aWorkorderID " + "FROM aWorkorderQuote " + "WHERE (aWorkorderQuote.aID " + "= @ID)" , crit.ID)); break; case RootObjectTypes.WorkorderService: WorkorderIDToFetch = DBUtil.ToGuid(DBUtil.GetScalarFromSQLString( "SELECT aWorkorderService.aWorkorderID " + "FROM aWorkorderService " + "WHERE (aWorkorderService.aID " + "= @ID)" , crit.ID)); break; case RootObjectTypes.WorkorderItemLoan: WorkorderIDToFetch = DBUtil.ToGuid(DBUtil.GetScalarFromSQLString( "SELECT TOP 1 aWorkorderItem.aWorkorderID " + "FROM aWorkorderItem INNER JOIN aWorkorderItemLoan " + "ON aWorkorderItem.aID = aWorkorderItemLoan.aWorkorderItemID " + "WHERE (aWorkorderItemLoan.aID " + "= @ID)" , crit.ID)); break; default: throw new System.NotSupportedException("GetWorkorderByDescendant(" + crit.RootObjectType.ToString() + ") not supported"); } crit.ID = WorkorderIDToFetch; //retrieve the workorder: dr = DBUtil.GetReaderFromSQLString("SELECT * FROM aWorkorder WHERE aID=@ID;", crit.ID); if (!dr.Read()) DBUtil.ThrowFetchError("Workorder ID: " + crit.ID.ToString()); //Workorder fields mClientID = dr.GetGuid("aClientID"); mProjectID = dr.GetGuid("aProjectID"); mInternalReferenceNumber = dr.GetString("aInternalReferenceNumber"); mCustomerReferenceNumber = dr.GetString("aCustomerReferenceNumber"); mOnsite = dr.GetBoolean("aOnsite"); mCustomerContactName = dr.GetString("aCustomerContactName"); //Case 58 mRegionID = dr.GetGuid("aRegionID"); mSummary = dr.GetString("aSummary"); //mTemplateID=dr.GetGuid("aTemplateID"); mFormLayoutID = dr.GetGuid("aFormLayoutID"); mWorkorderType = (WorkorderTypes)dr.GetInt16("aWorkorderType"); mRights = (SecurityLevelTypes)AyaBizUtils.Right(Workorder.RootObjectTypeFromWorkorderType(mWorkorderType)); //mTemplate=dr.GetBoolean("aTemplate"); mWorkorderCategoryID = dr.GetGuid("aWorkorderCategoryID"); mServiceCompleted = dr.GetBoolean("aServiceCompleted"); mClosed = dr.GetBoolean("aClosed"); mFromQuoteID = dr.GetGuid("aFromQuoteID"); mFromPMID = dr.GetGuid("aFromPMID"); mTemplateDescription = dr.GetString("aTemplateDescription"); mTemplateFreshPrice = dr.GetBoolean("ATEMPLATEFRESHPRICE");//case 3132 //Standard fields mID = dr.GetGuid("aID"); mCreated = DBUtil.ToLocal(dr.GetSmartDate("aCreated")); mModified = DBUtil.ToLocal(dr.GetSmartDate("aModified")); mCreator = dr.GetGuid("aCreator"); mModifier = dr.GetGuid("aModifier"); if (dr != null) dr.Close(); //Child objects... //PM if (this.mWorkorderType == WorkorderTypes.PreventiveMaintenance || this.mWorkorderType == WorkorderTypes.TemplatePreventiveMaintenance) { dr = DBUtil.GetReaderFromSQLString("SELECT * FROM aWorkorderPreventiveMaintenance WHERE aWorkorderID=@ID;", crit.ID); if (dr.Read())//single child objects need this mWorkorderPreventiveMaintenance = WorkorderPreventiveMaintenance.GetItem(dr); else { //double check there isn't a problem //ok, we *should* always have a pm for a //pm type workorder obviously something has gone wrong //so let's create one now mWorkorderPreventiveMaintenance = WorkorderPreventiveMaintenance.NewItem(this); } if (dr != null) dr.Close(); } //WorkorderService if (this.mWorkorderType == WorkorderTypes.Service || this.mWorkorderType == WorkorderTypes.TemplateService) { dr = DBUtil.GetReaderFromSQLString("SELECT * FROM aWorkorderService WHERE aWorkorderID=@ID;", crit.ID); if (dr.Read())//single child objects need this mService = WorkorderService.GetItem(dr); else { //double check there isn't a problem //ok, we *should* always have a workorderservice for a //service type workorder obviously something has gone wrong //so let's create one now mService = WorkorderService.NewItem(this); } if (dr != null) dr.Close(); } //WorkorderQuote if (this.mWorkorderType == WorkorderTypes.Quote || this.mWorkorderType == WorkorderTypes.TemplateQuote) { dr = DBUtil.GetReaderFromSQLString("SELECT * FROM aWorkorderQuote WHERE aWorkorderID=@ID;", crit.ID); if (dr.Read())//single child objects need this mQuote = WorkorderQuote.GetItem(dr); else { //double check there isn't a problem //ok, we *should* always have a WorkorderQuote for a //Quote type workorder obviously something has gone wrong //so let's create one now mQuote = WorkorderQuote.NewItem(this); } if (dr != null) dr.Close(); } //WorkorderItems collection dr = DBUtil.GetReaderFromSQLString("SELECT * FROM aWorkorderItem WHERE aWorkorderID=@ID;", crit.ID); //Child collection objects don't need to read first: they do it themselves mWorkorderItems = WorkorderItems.GetItems(dr, this); if (dr != null) dr.Close(); //Docs dr = DBUtil.GetReaderFromSQLString("SELECT * FROM AASSIGNEDDOC WHERE (aRootObjectID=@ID and aRootObjectType=9);", crit.ID); mDocs = AssignedDocs.GetItems(dr, RootObjectTypes.Workorder, this.RootObjectType); if (dr != null) dr.Close(); } finally { if (dr != null) dr.Close(); } MarkOld(); if (crit.TrackMRU) { switch (mWorkorderType) { case WorkorderTypes.Service: if (AyaBizUtils.AllowAutomaticMRUOnUpdate) AyaBizUtils.MRU.Add(RootObjectTypes.Workorder, mID); break; case WorkorderTypes.Quote: if (AyaBizUtils.AllowAutomaticMRUOnUpdate) AyaBizUtils.MRU.Add(RootObjectTypes.WorkorderQuote, WorkorderQuote.ID); break; case WorkorderTypes.PreventiveMaintenance: if (AyaBizUtils.AllowAutomaticMRUOnUpdate) AyaBizUtils.MRU.Add(RootObjectTypes.WorkorderPreventiveMaintenance, WorkorderPreventiveMaintenance.ID); break; case WorkorderTypes.TemplateService: if (AyaBizUtils.AllowAutomaticMRUOnUpdate) AyaBizUtils.MRU.Add(RootObjectTypes.WorkorderServiceTemplate, mID); break; case WorkorderTypes.TemplateQuote: if (AyaBizUtils.AllowAutomaticMRUOnUpdate) AyaBizUtils.MRU.Add(RootObjectTypes.WorkorderQuoteTemplate, WorkorderQuote.ID); break; case WorkorderTypes.TemplatePreventiveMaintenance: if (AyaBizUtils.AllowAutomaticMRUOnUpdate) AyaBizUtils.MRU.Add(RootObjectTypes.WorkorderPreventiveMaintenanceTemplate, WorkorderPreventiveMaintenance.ID); break; } } //Get access rights level bReadOnly = mRights < SecurityLevelTypes.ReadWrite; //If not already read only see if workorder is closed because a closed //workorder is *always* read only if (!bReadOnly) { if (mWorkorderType == WorkorderTypes.Service) { if (mClosed) { //case 986 //bReadOnly=true; //set all workorder items to read only status this.mWorkorderItems.SetReadOnly(true); return;//no need to continue because the following only //does the same thing anyway } } } //Check for service completed if (mWorkorderType == WorkorderTypes.Service) { if (mServiceCompleted) { //set all workorder items to read only status this.mWorkorderItems.SetReadOnly(true); } } } #endregion fetch #region Update /// /// Called by DataPortal to delete/add/update data into the database /// protected override void DataPortal_Update() { // If not a new record, check if record was modified //by another user since original retrieval: if (!IsNew) DBUtil.CheckSafeToUpdate(this.mModified.Date, this.mID, "aWorkorder"); #region Delete if (IsDeleted) { if (this.HasPartRequestsOnOrder) throw new System.ApplicationException ( string.Format ( LocalizedTextTable.GetLocalizedTextDirect("Error.Object.NotDeleteable"), LocalizedTextTable.GetLocalizedTextDirect("O.Workorder") ) + " when it has part requests on order"//case 3599 ); if (!IsNew) { //Delete pm, service, quote, woitems and workorder itself //case 3596 DBCommandWrapper cmDeleteFromLastServiceClient = DBUtil.GetCommandFromSQL("UPDATE ACLIENT SET ALASTWORKORDERID = null, ALASTSERVICEDATE = null WHERE ALASTWORKORDERID = @WORKORDERID"); cmDeleteFromLastServiceClient.AddInParameter("@WORKORDERID", DbType.Guid, this.mID); //case 3596 DBCommandWrapper cmDeleteFromLastServiceUnit = DBUtil.GetCommandFromSQL("UPDATE AUNIT SET ALASTWORKORDERID = null, ALASTSERVICEDATE = null WHERE ALASTWORKORDERID = @WORKORDERID"); cmDeleteFromLastServiceUnit.AddInParameter("@WORKORDERID", DbType.Guid, this.mID); DBCommandWrapper cmDeletePM = DBUtil.GetCommandFromSQL("DELETE FROM aWorkorderPreventiveMaintenance WHERE aWorkorderID = @ID;"); cmDeletePM.AddInParameter("@ID", DbType.Guid, this.mID); DBCommandWrapper cmDeleteService = DBUtil.GetCommandFromSQL("DELETE FROM aWorkorderService WHERE aWorkorderID = @ID;"); cmDeleteService.AddInParameter("@ID", DbType.Guid, this.mID); DBCommandWrapper cmDeleteQuote = DBUtil.GetCommandFromSQL("DELETE FROM aWorkorderQuote WHERE aWorkorderID = @ID;"); cmDeleteQuote.AddInParameter("@ID", DbType.Guid, this.mID); DBCommandWrapper cmDeleteWO = DBUtil.GetCommandFromSQL("DELETE FROM aWorkorder WHERE aID = @ID;"); cmDeleteWO.AddInParameter("@ID", DbType.Guid, this.mID); using (IDbConnection connection = DBUtil.DB.GetConnection()) { connection.Open(); //IDbTransaction transaction = connection.BeginTransaction(); //Changed this to a high isolation level transaction because //it can affect inventory etc IDbTransaction transaction = connection.BeginTransaction(System.Data.IsolationLevel.Serializable); try { //case 3596 DBUtil.DB.ExecuteNonQuery(cmDeleteFromLastServiceClient, transaction); DBUtil.DB.ExecuteNonQuery(cmDeleteFromLastServiceUnit, transaction); //This one method takes care of any and all workorder //items that are children of this workorder //It deletes all workorder item children and then all workorder items //attached to this workorder WorkorderItems.DeleteItems(this.mID, transaction); DBUtil.DB.ExecuteNonQuery(cmDeletePM, transaction); DBUtil.DB.ExecuteNonQuery(cmDeleteService, transaction); DBUtil.DB.ExecuteNonQuery(cmDeleteQuote, transaction); DBUtil.DB.ExecuteNonQuery(cmDeleteWO, transaction); DBUtil.RemoveKeywords(transaction, RootObjectTypes.Workorder, this.mID); DBUtil.RemoveDocs(transaction, RootObjectTypes.Workorder, this.mID); // Commit the transaction transaction.Commit(); } catch { // Rollback transaction transaction.Rollback(); throw; } finally { connection.Close(); } } //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 aWorkorder (aID, aClientID, aProjectID, " + "aInternalReferenceNumber, aCustomerReferenceNumber, " + "aOnsite, aCustomerContactName, aWorkorderType, " + "aFormLayoutID, aSummary, aTemplateDescription, " + "aWorkorderCategoryID, aCreated,aModified,aCreator,aModifier, " + "aClosed, aServiceCompleted, aFromQuoteID, aFromPMID, aRegionID, ATEMPLATEFRESHPRICE) VALUES (@ID,@ClientID, " + "@ProjectID,@InternalReferenceNumber,@CustomerReferenceNumber, " + "@Onsite,@CustomerContactName, " + "@WorkorderType,@FormLayoutID, " + "@Summary, @TemplateDescription, @WorkorderCategoryID, " + "@Created, @Modified,@CurrentUserID,@CurrentUserID, " + "@Closed,@ServiceCompleted, @FromQuoteID, @FromPMID, @RegionID, @TEMPLATEFRESHPRICE)" ); else cm = DBUtil.GetCommandFromSQL( "UPDATE aWorkorder SET aID=@ID, aClientID=@ClientID, " + "aProjectID=@ProjectID, aInternalReferenceNumber=@InternalReferenceNumber, " + "aCustomerReferenceNumber=@CustomerReferenceNumber, " + "aOnsite=@Onsite, aCustomerContactName=@CustomerContactName, " + "aWorkOrderType=@WorkOrderType, aFormLayoutID=@FormLayoutID, " + "aSummary=@Summary, aTemplateDescription=@TemplateDescription, aWorkorderCategoryID=@WorkorderCategoryID, " + " aModifier=@CurrentUserID, " + " aModified=@Modified, aClosed=@Closed, " + "aServiceCompleted=@ServiceCompleted, aFromQuoteID=@FromQuoteID, aFromPMID=@FromPMID, aRegionID=@RegionID, " + "ATEMPLATEFRESHPRICE=@TEMPLATEFRESHPRICE " + //case 3132 "WHERE aID=@ID" ); //Workorder fields cm.AddInParameter("@ID", DbType.Guid, mID); cm.AddInParameter("@ClientID", DbType.Guid, mClientID); cm.AddInParameter("@ProjectID", DbType.Guid, mProjectID); cm.AddInParameter("@InternalReferenceNumber", DbType.String, mInternalReferenceNumber); cm.AddInParameter("@CustomerReferenceNumber", DbType.String, mCustomerReferenceNumber); cm.AddInParameter("@Onsite", DbType.Boolean, mOnsite); cm.AddInParameter("@CustomerContactName", DbType.String, mCustomerContactName); //case 58 cm.AddInParameter("@RegionID", DbType.Guid, mRegionID); cm.AddInParameter("@Summary", DbType.String, mSummary); cm.AddInParameter("@TemplateDescription", DbType.String, mTemplateDescription); cm.AddInParameter("@FormLayoutID", DbType.Guid, mFormLayoutID); cm.AddInParameter("@WorkorderType", DbType.Int16, (int)mWorkorderType); cm.AddInParameter("@WorkorderCategoryID", DbType.Guid, mWorkorderCategoryID); cm.AddInParameter("@ServiceCompleted", DbType.Boolean, mServiceCompleted); cm.AddInParameter("@Closed", DbType.Boolean, mClosed); cm.AddInParameter("@FromQuoteID", DbType.Guid, mFromQuoteID); cm.AddInParameter("@FromPMID", DbType.Guid, mFromPMID); //case 3132 cm.AddInParameter("@TEMPLATEFRESHPRICE", DbType.Boolean, mTemplateFreshPrice); //Standard fields cm.AddInParameter("@CurrentUserID", DbType.Guid, CurrentUserID); cm.AddInParameter("@Created", DbType.DateTime, DBUtil.ToUTC(mCreated).DBValue); cm.AddInParameter("@Modified", DbType.DateTime, DBUtil.ToUTC(dtModified)); //Custom fields // cm.AddLargeStringInParameter("@Custom1", mCustom1); // cm.AddLargeStringInParameter("@Custom2", mCustom2); // cm.AddLargeStringInParameter("@Custom3", mCustom3); // cm.AddLargeStringInParameter("@Custom4", mCustom4); // cm.AddLargeStringInParameter("@Custom5", mCustom5); // cm.AddLargeStringInParameter("@Custom6", mCustom6); // cm.AddLargeStringInParameter("@Custom7", mCustom7); // cm.AddLargeStringInParameter("@Custom8", mCustom8); // cm.AddLargeStringInParameter("@Custom9", mCustom9); // cm.AddLargeStringInParameter("@Custom0", mCustom0); using (IDbConnection connection = DBUtil.DB.GetConnection()) { connection.Open(); //IDbTransaction transaction = connection.BeginTransaction(); //Changed to high isolation transaction because an update affects potentially inventory and //service bank objects IDbTransaction transaction = connection.BeginTransaction(System.Data.IsolationLevel.Serializable); try { DBUtil.DB.ExecuteNonQuery(cm, transaction); /* * Update child objects */ switch (this.WorkorderType) { case WorkorderTypes.PreventiveMaintenance: case WorkorderTypes.TemplatePreventiveMaintenance: mWorkorderPreventiveMaintenance.Update(this, transaction); break; case WorkorderTypes.Quote: case WorkorderTypes.TemplateQuote: mQuote.Update(this, transaction); break; case WorkorderTypes.Service: case WorkorderTypes.TemplateService: mService.Update(this, transaction); //Last service date / wo //only set this if closed //this prevents a situation where the workorder can not be deleted //because of the foreign key link to the client lastworkorderid field //because a closed workorder can not be deleted if (this.mClosed) {//unclose DBCommandWrapper cmLastServiceClient = DBUtil.GetCommandFromSQL( "UPDATE aClient SET aLastWorkorderID=@WorkorderID, " + "aLastServiceDate=@LastServiceDate " + "WHERE aID=@ClientID" ); cmLastServiceClient.AddInParameter("@ClientID", DbType.Guid, mClientID); cmLastServiceClient.AddInParameter("@WorkorderID", DbType.Guid, this.mID); cmLastServiceClient.AddInParameter("@LastServiceDate", DbType.DateTime, DBUtil.ToUTC(mService.sdServiceDate).DBValue); DBUtil.DB.ExecuteNonQuery(cmLastServiceClient, transaction); foreach (WorkorderItem wi in this.mWorkorderItems) { if (wi.UnitID != Guid.Empty) {//unclose DBCommandWrapper cmLastServiceUnit = DBUtil.GetCommandFromSQL( "UPDATE aUnit SET aLastWorkorderID=@WorkorderID, " + "aLastServiceDate=@LastServiceDate " + "WHERE aID=@UnitID" ); cmLastServiceUnit.AddInParameter("@UnitID", DbType.Guid, wi.UnitID); cmLastServiceUnit.AddInParameter("@WorkorderID", DbType.Guid, this.mID); cmLastServiceUnit.AddInParameter("@LastServiceDate", DbType.DateTime, DBUtil.ToUTC(mService.sdServiceDate).DBValue); DBUtil.DB.ExecuteNonQuery(cmLastServiceUnit, transaction); } } } break; } //WorkorderItems collection mWorkorderItems.Update(this, transaction); //Docs mDocs.Update(transaction); //Process keywords DBUtil.ProcessKeywords(transaction, this.mID, RootObjectTypes.Workorder, IsNew, AyaBizUtils.Break(false, mInternalReferenceNumber, mCustomerReferenceNumber, mCustomerContactName, mSummary, mTemplateDescription)); //case 53 bWasNew = IsNew; MarkOld();//db is now synched with object // Commit the transaction transaction.Commit(); } catch { // Rollback transaction transaction.Rollback(); throw; } finally { connection.Close(); } //Successful update so //change modification time to match this.mModified.Date = dtModified; switch (mWorkorderType) { case WorkorderTypes.Service: if (AyaBizUtils.AllowAutomaticMRUOnUpdate) AyaBizUtils.MRU.Add(RootObjectTypes.Workorder, mID); break; case WorkorderTypes.Quote: if (AyaBizUtils.AllowAutomaticMRUOnUpdate) AyaBizUtils.MRU.Add(RootObjectTypes.WorkorderQuote, WorkorderQuote.ID); break; case WorkorderTypes.PreventiveMaintenance: if (AyaBizUtils.AllowAutomaticMRUOnUpdate) AyaBizUtils.MRU.Add(RootObjectTypes.WorkorderPreventiveMaintenance, WorkorderPreventiveMaintenance.ID); break; case WorkorderTypes.TemplateService: if (AyaBizUtils.AllowAutomaticMRUOnUpdate) AyaBizUtils.MRU.Add(RootObjectTypes.WorkorderServiceTemplate, ID); break; case WorkorderTypes.TemplateQuote: if (AyaBizUtils.AllowAutomaticMRUOnUpdate) AyaBizUtils.MRU.Add(RootObjectTypes.WorkorderQuoteTemplate, WorkorderQuote.ID); break; case WorkorderTypes.TemplatePreventiveMaintenance: if (AyaBizUtils.AllowAutomaticMRUOnUpdate) AyaBizUtils.MRU.Add(RootObjectTypes.WorkorderPreventiveMaintenanceTemplate, WorkorderPreventiveMaintenance.ID); break; } if (this.Closed) ClientServiceRequest.CloseFlag(this.mID); #region Process events //Process events as necessary if (AyaBizUtils.GlobalSettings.UseNotification)//Case 510 { #region Service type workorder notification events if (mWorkorderType == WorkorderTypes.Service && this.mService != null) { //there are three types of events that might be of interest //Case 53 new event of interest - workorder created if (bWasNew) { ClientNotifyEvent.ProcessEvent(ClientNotifyEventType.NewWorkorder, mClientID, mService.WorkorderStatusID, mService.ServiceNumber.ToString(), mCustomerContactName, mCustomerReferenceNumber, "", mID, mSummary, ""); } //Has the status changed? if (mService.mStatusSignificant) { NotifyEvent.AddOrUpdateEvent(RootObjectTypes.Workorder, this.mID, (int)WorkorderEvent.Status, Guid.Empty, new SmartDate(), mService.WorkorderStatusID); ClientNotifyEvent.ProcessEvent(ClientNotifyEventType.WorkorderStatusSet, mClientID, mService.WorkorderStatusID, mService.ServiceNumber.ToString(), mCustomerContactName, mCustomerReferenceNumber, "", mID, mSummary, ""); //case 1879 - multiple events showing up on repeated save of same workorder edit session mService.mStatusSignificant = false; } //Has it been closed? if (Closed) { //Yes, so //remove close by events if present //This is ok even if it's passed and closed later //because they would have got the notice about it being passed //so in any case we want the event gone NotifyEvent.RemoveSpecificEventForObject(mID, (int)WorkorderEvent.CloseByDatePassed); //Workorder is closed adn we're in the upate method so clearly it was open and has now just been closed and saved //since a closed workorder can not be updated //case 53 //unclose ClientNotifyEvent.ProcessEvent(ClientNotifyEventType.WorkorderClosed, mClientID, mService.WorkorderStatusID, mService.ServiceNumber.ToString(), mCustomerContactName, mCustomerReferenceNumber, "", mID, mSummary, ""); ClientNotifyEvent.ProcessEvent(ClientNotifyEventType.WorkorderFollowUp, mClientID, mService.WorkorderStatusID, mService.ServiceNumber.ToString(), mCustomerContactName, mCustomerReferenceNumber, "", mID, mSummary, ""); } else { //Nope,so set the close by date event if significant (changed) if (mService.mCloseByDateSignificant) { //Check if user set it to empty, //in which case we don't want any event for this if (mService.sdCloseByDate.IsEmpty) NotifyEvent.RemoveSpecificEventForObject(mID, (int)WorkorderEvent.CloseByDatePassed); else NotifyEvent.AddOrUpdateEvent(RootObjectTypes.Workorder, this.mID, (int)WorkorderEvent.CloseByDatePassed, Guid.Empty, mService.sdCloseByDate, Guid.Empty); } } } #endregion service workorder notification processor #region Quote type workorder notification events if (mWorkorderType == WorkorderTypes.Quote && this.mQuote != null) { //Has the status changed? if (mQuote.mStatusSignificant) { ClientNotifyEvent.ProcessEvent(ClientNotifyEventType.QuoteStatusSet, mClientID, Guid.Empty, mQuote.QuoteNumber.ToString(), mCustomerContactName, mCustomerReferenceNumber, "", mID, mSummary, "", mQuote.QuoteStatus); } //case 1555 //User quote updated notification NotifyEvent.AddOrUpdateEvent(RootObjectTypes.Workorder, this.mID, (int)WorkorderEvent.QuoteUpdated); //case 2090 to be added here:? //notification when quote is approved X days after } #endregion Quote workorder notification processor } #endregion } #endregion } #endregion update #endregion #region Override IsValid / IsDirty //Override base class version if there are child objects /// /// /// public override bool IsValid { get { switch (this.WorkorderType) { case WorkorderTypes.PreventiveMaintenance: case WorkorderTypes.TemplatePreventiveMaintenance: return base.IsValid && mWorkorderPreventiveMaintenance.IsValid && mWorkorderItems.IsValid && mDocs.IsValid; case WorkorderTypes.Quote: case WorkorderTypes.TemplateQuote: return base.IsValid && mQuote.IsValid && mWorkorderItems.IsValid && mDocs.IsValid; case WorkorderTypes.Service: case WorkorderTypes.TemplateService: return base.IsValid && mService.IsValid && mWorkorderItems.IsValid && mDocs.IsValid; } return false; } } /// /// /// public override bool IsDirty { get { switch (this.WorkorderType) { case WorkorderTypes.PreventiveMaintenance: case WorkorderTypes.TemplatePreventiveMaintenance: return base.IsDirty || mWorkorderPreventiveMaintenance.IsDirty || mWorkorderItems.IsDirty || mDocs.IsDirty; case WorkorderTypes.Quote: case WorkorderTypes.TemplateQuote: return base.IsDirty || mQuote.IsDirty || mWorkorderItems.IsDirty || mDocs.IsDirty; case WorkorderTypes.Service: case WorkorderTypes.TemplateService: return base.IsDirty || mService.IsDirty || mWorkorderItems.IsDirty || mDocs.IsDirty; } return false; } } #endregion #region criteria /// /// Criteria for identifying existing object /// [Serializable] private class Criteria { public bool TrackMRU; public Guid ID; public RootObjectTypes RootObjectType; public Criteria(RootObjectTypes _RootObjectType, Guid _ID, bool _TrackMRU) { ID = _ID; RootObjectType = _RootObjectType; TrackMRU = _TrackMRU; } } #endregion #region Move WorkorderItem #pragma warning disable 1591 /// /// Move a workorder item to a new workorder /// [Serializable, System.ComponentModel.Browsable(false)] public class WorkorderItemMover//DO_NOT_OBFUSCATE { Guid _ToWorkorderID; Guid _FromWorkorderID; Guid _WorkorderItemID; /// /// /// /// /// /// public WorkorderItemMover(Guid FromWorkorderID, Guid ToWorkorderID, Guid WorkorderItemID) { _FromWorkorderID = FromWorkorderID; _ToWorkorderID = ToWorkorderID; _WorkorderItemID = WorkorderItemID; } public static void Move(Guid FromWorkorderID, Guid ToWorkorderID, Guid WorkorderItemID) { DataPortal.Update(new WorkorderItemMover(FromWorkorderID, ToWorkorderID, WorkorderItemID)); } public void DataPortal_Update() { DBCommandWrapper cm = null; cm = DBUtil.GetCommandFromSQL( "UPDATE aWorkorderItem SET aWorkorderID=@ToWorkorderID " + "WHERE aWorkorderID=@FromWorkorderID AND aID=@WorkorderItemID" ); cm.AddInParameter("@FromWorkorderID", DbType.Guid, _FromWorkorderID); cm.AddInParameter("@ToWorkorderID", DbType.Guid, _ToWorkorderID); cm.AddInParameter("@WorkorderItemID", DbType.Guid, _WorkorderItemID); DBUtil.DB.ExecuteNonQuery(cm); } } #endregion move workorder item #region Re-open workorder /// /// Re-open a closed work order /// /// Removes all User notification events for the workorder /// /// Will not remove client notifications if pending because /// they do not store the workorder ID, only an email message so /// there is a possibility they will get sent out about a closed workorder /// *after* the work order was reopened. /// [Serializable, System.ComponentModel.Browsable(false)] public class WorkorderReopener//DO_NOT_OBFUSCATE { Guid _WorkorderID; public WorkorderReopener(Guid WorkorderID) { _WorkorderID = WorkorderID; } public static void Open(Guid WorkorderID) { DataPortal.Update(new WorkorderReopener(WorkorderID)); } public void DataPortal_Update() { DBCommandWrapper cm = null; //reopen workorder cm = DBUtil.GetCommandFromSQL( "UPDATE aWorkorder SET aClosed=@FALSE " + "WHERE aWorkorder.AID=@WorkorderID " ); cm.AddInParameter("@WorkorderID", DbType.Guid, _WorkorderID); cm.AddInParameter("@FALSE", DbType.Boolean, false); DBUtil.DB.ExecuteNonQuery(cm); //change client last workorder and service date if //it was set to this workorder cm = DBUtil.GetCommandFromSQL( "UPDATE aClient SET aLastWorkorderID=NULL, " + "aLastServiceDate=NULL " + "WHERE aLastWorkorderID=@WorkorderID" ); cm.AddInParameter("@WorkorderID", DbType.Guid, _WorkorderID); DBUtil.DB.ExecuteNonQuery(cm); //change unit last workorder and service date if it was set to this workorder cm = DBUtil.GetCommandFromSQL( "UPDATE aUnit SET aLastWorkorderID=NULL, " + "aLastServiceDate=NULL " + "WHERE aLastWorkorderID=@WorkorderID" ); cm.AddInParameter("@WorkorderID", DbType.Guid, _WorkorderID); DBUtil.DB.ExecuteNonQuery(cm); NotifyEvent.RemoveAllEventsForObject(_WorkorderID); } } #endregion reopen workorder #pragma warning restore 1591 }//end Workorder #region Notification events /// /// /// public enum WorkorderEvent : int { /// /// Status changed on service workorder /// [Description("LT:Workorder.Label.Event.Status")] Status = 1, //CloseByDatePassed *is* a dated event, but it's not user selectable //so that's why the enumeration value is 2 instead of 256. /// /// Close by date passed on service workorder /// [Description("LT:Workorder.Label.Event.CloseByDatePassed")] CloseByDatePassed = 2, /// /// Quote updated event /// [Description("LT:Workorder.Label.Event.QuoteUpdated")] QuoteUpdated = 3 } #endregion }//end namespace GZTW.AyaNova.BLL