Files
ayanova7/source/bizobjects/AyaLib/GZTW.AyaNova.BLL/Workorder.cs
2020-10-14 19:42:32 +00:00

5725 lines
222 KiB
C#

///////////////////////////////////////////////////////////
// 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
{
/// <summary>
/// Workorder object - the heart of AyaNova.
/// This is the parent object of all forms of workorders including quotes, pm, service and template forms.
/// </summary>
[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
/// <summary>
/// Private constructor to prevent direct instantiation
/// </summary>
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
/// <summary>
/// Get internal id number Read only property because it's set internally, not
/// externally
/// </summary>
public Guid ID
{
get
{
return mID;
}
}
/// <summary>
/// Get created date
///
///
/// </summary>
public string Created
{
get
{
return mCreated.ToString();
}
}
/// <summary>
/// Get modified date
///
///
/// </summary>
public string Modified
{
get
{
return mModified.ToString();
}
}
/// <summary>
/// Get user record ID of person who created this record
///
///
/// </summary>
public Guid Creator
{
get
{
return mCreator;
}
}
/// <summary>
/// Get user ID of person who modified this record
///
///
/// </summary>
public Guid Modifier
{
get
{
return mModifier;
}
}
/// <summary>
/// <see cref="AssignedDoc"/> object collection assigned to this workorder
/// </summary>
public AssignedDocs Docs
{
get
{
return mDocs;
}
}
/// <summary>
/// Category of workorder
/// </summary>
public Guid WorkorderCategoryID
{
get
{
return mWorkorderCategoryID;
}
set
{
if (bReadOnly)
ThrowSetError();
else
{
if (mWorkorderCategoryID != value)
{
mWorkorderCategoryID = value;
MarkDirty();
}
}
}
}
/// <summary>
/// Client this work order applies to
/// </summary>
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();
}
}
}
}
/// <summary>
/// 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.
/// </summary>
public string Summary
{
get
{
return mSummary;
}
set
{
if (bReadOnly)
ThrowSetError();
else
{
if (mSummary != value)
{
mSummary = value;
MarkDirty();
}
}
}
}
/// <summary>
/// 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
/// </summary>
public Guid FormLayoutID
{
get
{
return mFormLayoutID;
}
set
{
if (bReadOnly)
ThrowSetError();
else
{
if (mFormLayoutID != value)
{
mFormLayoutID = value;
MarkDirty();
}
}
}
}
/// <summary>
/// GUID of project selected
/// </summary>
public Guid ProjectID
{
get
{
return mProjectID;
}
set
{
if (bReadOnly)
ThrowSetError();
else
{
if (mProjectID != value)
{
mProjectID = value;
MarkDirty();
}
}
}
}
/// <summary>
/// In addition to Workorder number - may have letters in it, therefore used in
/// addition to numerial wo number
/// </summary>
public string InternalReferenceNumber
{
get
{
return mInternalReferenceNumber;
}
set
{
if (bReadOnly)
ThrowSetError();
else
{
if (mInternalReferenceNumber != value)
{
mInternalReferenceNumber = value;
MarkDirty();
}
}
}
}
/// <summary>
/// Client's reference number
/// </summary>
public string CustomerReferenceNumber
{
get
{
return mCustomerReferenceNumber;
}
set
{
if (bReadOnly)
ThrowSetError();
else
{
if (mCustomerReferenceNumber != value)
{
mCustomerReferenceNumber = value;
MarkDirty();
}
}
}
}
/// <summary>
/// Onsite indicates at client site
/// Default is true
/// Can be set in regional settings
/// </summary>
public bool Onsite
{
get
{
return mOnsite;
}
set
{
if (bReadOnly)
ThrowSetError();
else
{
if (mOnsite != value)
{
mOnsite = value;
MarkDirty();
}
}
}
}
/// <summary>
/// Takes as default name in client contact list when client first selected, but
/// can be edited by user
/// </summary>
public string CustomerContactName
{
get
{
return mCustomerContactName;
}
set
{
if (bReadOnly)
ThrowSetError();
else
{
if (mCustomerContactName != value)
{
mCustomerContactName = value;
MarkDirty();
}
}
}
}
/// <summary>
/// Determines if a workorder is a template, a quote, a PM item, a workorder for a
/// client or an internal workorder
/// </summary>
public WorkorderTypes WorkorderType
{
get
{
return mWorkorderType;
}
set
{
if (bReadOnly)
ThrowSetError();
else
{
if (mWorkorderType != value)
{
mWorkorderType = value;
MarkDirty();
}
}
}
}
/// <summary>
///
/// Brief description of the purpose of the workorder template as a whole
/// displays on many reports and in various grids.
///
/// </summary>
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();
}
}
}
}
/// <summary>
/// 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
/// </summary>
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
/// <summary>
/// If not a WorkorderPreventiveMaintenance, is null
/// If a WorkorderPreventiveMaintenance contains the WorkorderPreventiveMaintenance child object
/// </summary>
public WorkorderPreventiveMaintenance WorkorderPreventiveMaintenance
{
get
{
return mWorkorderPreventiveMaintenance;
}
}
/// <summary>
/// If not a WorkorderService, is null
/// If a WorkorderService contains the WorkorderService child object
/// </summary>
public WorkorderService WorkorderService
{
get
{
return mService;
}
}
/// <summary>
/// Workorder items collection
/// </summary>
public WorkorderItems WorkorderItems
{
get
{
return mWorkorderItems;
}
}
/// <summary>
/// If not a quote, is null
/// If a quote, contains the WorkorderQuote child object
/// </summary>
public WorkorderQuote WorkorderQuote
{
get
{
return mQuote;
}
}
//*************** CONTRACT / SERVICEBANK RELATED CODE **************************
/// <summary>
/// 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
/// </summary>
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;
}
/// <summary>
/// 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
/// </summary>
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;
/// <summary>
/// Returns Contract that is most specific
/// or null if no contract
/// </summary>
/// <returns></returns>
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
/// <summary>
/// Returns ID only of Contract that is most specific to
/// this workorder or empty Guid if no Contract applies at all
/// </summary>
/// <returns></returns>
public Guid ContractIDResolved()
{
Contract c = ContractResolved();
if (c == null)
return Guid.Empty;
else
return c.ID;
}
//******************************************************************************
/// <summary>
/// Mirror of global object's UseInventory setting
/// </summary>
public bool UseInventory
{
get
{
return mUseInventory;
}
}
/// <summary>
/// Move workorderItem from current workorder to another
/// (Requires full rights and not a closed or read only workorder)
/// </summary>
/// <param name="ToWorkorderID"></param>
/// <param name="WorkorderItemID"></param>
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?
}
}
/// <summary>
/// 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
/// </summary>
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);
}
}
}
}
}
/// <summary>
/// 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.
/// </summary>
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
/// <summary>
/// If a template setting to true will result in the prices being updated to current in the generated order
/// </summary>
public bool TemplateFreshPrice
{
get
{
return mTemplateFreshPrice;
}
set
{
if (bReadOnly)
ThrowSetError();
else
{
if (mTemplateFreshPrice != value)
{
mTemplateFreshPrice = value;
MarkDirty();
}
}
}
}
/// <summary>
/// False if any outstanding parts (not set to "Used in service")
/// True if all parts are set to used in service.
/// </summary>
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;
}
}
/// <summary>
/// Sets all parts to used = true on entire workorder
/// </summary>
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;
}
}
}
/// <summary>
/// Create a labor object from a scheduled user object to save entry time
/// </summary>
/// <param name="SourceWorkorderItemID"></param>
/// <param name="SourceWorkorderItemScheduledUserID"></param>
/// <returns></returns>
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;
}
/// <summary>
/// Find the workorder item ID that contains the object passed in
/// </summary>
/// <param name="DescendantObjectType">Type of workorder item descendant object</param>
/// <param name="DescendantID">ID of descendant of workorder item</param>
/// <returns></returns>
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;
}
/// <summary>
/// ID of quote that created this workorder
/// Set internally when the Quote workorder generates a service
/// workorder.
/// </summary>
public Guid FromQuoteID
{
get
{
return mFromQuoteID;
}
}
/// <summary>
/// ID of PreventiveMaintenance that created this workorder
/// Set internally when the PM workorder generates a service
/// workorder.
/// </summary>
public Guid FromPMID
{
get
{
return mFromPMID;
}
}
/// <summary>
/// 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.
/// </summary>
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;
}
}
/// <summary>
/// True means there are loan items not yet returned
///
///
/// </summary>
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;
}
}
/// <summary>
/// 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
/// </summary>
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
/// <summary>
/// True means there are WorkorderItemPartRequest items
/// not yet ordered or received
///
/// Note: if GlobalSettings.UseInventory is false this will always return false
///
/// </summary>
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
/// <summary>
/// Returns true if the serial number record is selected
/// anywhere in the workorder item parts collections
/// </summary>
/// <param name="PartSerialID">ID of PartSerial record</param>
/// <returns></returns>
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
/// <summary>
/// A List of Guid's of labor rates selected
/// anywhere in this work order.
///
/// </summary>
/// <returns></returns>
public System.Collections.Generic.List<Guid> ListOfLaborRatesSelected()
{
System.Collections.Generic.List<Guid> l = new System.Collections.Generic.List<Guid>();
//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
/// <summary>
/// A List of Guid's of units selected
/// anywhere in this work order.
///
/// </summary>
/// <returns></returns>
public System.Collections.Generic.List<Guid> ListOfUnitsSelected()
{
System.Collections.Generic.List<Guid> l = new System.Collections.Generic.List<Guid>();
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
/// <summary>
/// A List of Guid's of labor users selected
/// anywhere in this work order.
///
/// </summary>
/// <returns></returns>
public System.Collections.Generic.List<Guid> ListOfLaborUsersSelected()
{
System.Collections.Generic.List<Guid> l = new System.Collections.Generic.List<Guid>();
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
/// <summary>
/// A List of Guid's of travel user id's selected
/// anywhere in this work order.
///
/// </summary>
/// <returns></returns>
public System.Collections.Generic.List<Guid> ListOfTravelUsersSelected()
{
System.Collections.Generic.List<Guid> l = new System.Collections.Generic.List<Guid>();
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
/// <summary>
/// A List of Guid's of travel rates selected
/// anywhere in this work order.
///
/// </summary>
/// <returns></returns>
public System.Collections.Generic.List<Guid> ListOfTravelRatesSelected()
{
System.Collections.Generic.List<Guid> l = new System.Collections.Generic.List<Guid>();
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
/// <summary>
/// A List of Guid's of parts selected
/// anywhere in this work order.
///
/// </summary>
/// <returns></returns>
public System.Collections.Generic.List<Guid> ListOfPartsSelected()
{
System.Collections.Generic.List<Guid> l = new System.Collections.Generic.List<Guid>();
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
/// <summary>
/// A List of Guid's of Part Warehouses selected
/// anywhere in this work order.
///
/// </summary>
/// <returns></returns>
public System.Collections.Generic.List<Guid> ListOfPartWarehousesSelected()
{
System.Collections.Generic.List<Guid> l = new System.Collections.Generic.List<Guid>();
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
/// <summary>
/// A List of Guid's of Scheduleable users selected
/// anywhere in this work order.
///
/// </summary>
/// <returns></returns>
public System.Collections.Generic.List<Guid> ListOfScheduledUsersSelected()
{
System.Collections.Generic.List<Guid> l = new System.Collections.Generic.List<Guid>();
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
/// <summary>
/// A List of Guid's of Scheduleable users suggested labor rates selected
/// anywhere in this work order.
///
/// </summary>
/// <returns></returns>
public System.Collections.Generic.List<Guid> ListOfScheduledUsersLaborRatesSelected()
{
System.Collections.Generic.List<Guid> l = new System.Collections.Generic.List<Guid>();
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
/// <summary>
/// A List of Guid's of Misc expense users selected
/// anywhere in this work order.
///
/// </summary>
/// <returns></returns>
public System.Collections.Generic.List<Guid> ListOfMiscExpenseUsersSelected()
{
System.Collections.Generic.List<Guid> l = new System.Collections.Generic.List<Guid>();
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
/// <summary>
/// A List of Guid's of Loan items selected
/// anywhere in this work order.
///
/// </summary>
/// <returns></returns>
public System.Collections.Generic.List<Guid> ListOfLoanItemsSelected()
{
System.Collections.Generic.List<Guid> l = new System.Collections.Generic.List<Guid>();
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
/// <summary>
/// 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
/// </summary>
/// <param name="excludeID">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</param>
/// <returns></returns>
public System.Collections.Generic.List<Guid> ListOfSerialNumbersSelected(Guid excludeID)
{
System.Collections.Generic.List<Guid> l = new System.Collections.Generic.List<Guid>();
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
/// <summary>
/// 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
/// </summary>
/// <returns></returns>
public System.Collections.Generic.List<Guid> ListOfWorkorderItemStatusSelected()
{
System.Collections.Generic.List<Guid> l = new System.Collections.Generic.List<Guid>();
foreach (WorkorderItem wi in this.WorkorderItems)
{
if (!l.Contains(wi.WorkorderStatusID))
l.Add(wi.WorkorderStatusID);
}
return l;
}
//case 1121
/// <summary>
/// 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
/// </summary>
/// <returns></returns>
public System.Collections.Generic.List<Guid> ListOfWorkorderItemPrioritiesSelected()
{
System.Collections.Generic.List<Guid> l = new System.Collections.Generic.List<Guid>();
foreach (WorkorderItem wi in this.WorkorderItems)
{
if (!l.Contains(wi.PriorityID))
l.Add(wi.PriorityID);
}
return l;
}
//case 1121
/// <summary>
/// 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
/// </summary>
/// <returns></returns>
public System.Collections.Generic.List<Guid> ListOfWorkorderItemTypesSelected()
{
System.Collections.Generic.List<Guid> l = new System.Collections.Generic.List<Guid>();
foreach (WorkorderItem wi in this.WorkorderItems)
{
if (!l.Contains(wi.TypeID))
l.Add(wi.TypeID);
}
return l;
}
//Case 360 tax codes
/// <summary>
/// A List of Guid's of tax codes selected
/// anywhere in this work order.
///
/// </summary>
/// <returns></returns>
public System.Collections.Generic.List<Guid> ListOfTaxCodesSelected()
{
System.Collections.Generic.List<Guid> l = new System.Collections.Generic.List<Guid>();
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
/// <summary>
/// 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
/// </summary>
public bool IsEditable
{
get
{
if (Rights < SecurityLevelTypes.ReadWrite) return false;
if (Closed) return false;
if (WorkorderType == WorkorderTypes.Service && ServiceCompleted) return false;
return true;
}
}
/// <summary>
/// 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
/// </summary>
public bool IsServiceCompletedEditable
{
get
{
if (Rights < SecurityLevelTypes.ReadWrite) return false;
if (Closed) return false;
return true;
}
}
/// <summary>
/// Quick check if workorder item is editable or not
/// First checks if workorder is editable, if yes then checks rights
/// to WorkorderItem object
/// </summary>
public bool IsWorkorderItemEditable//case 1562
{
get
{
if (!IsEditable) return false;
if (AyaBizUtils.Right(RootObjectTypes.WorkorderItem) < (int)SecurityLevelTypes.ReadWrite) return false;
return true;
}
}
/// <summary>
/// Quick check if workorder item is deletable or not
/// First checks if workorder is editable, if yes then checks rights
/// to WorkorderItem object
/// </summary>
public bool IsWorkorderItemDeletable//case 1562
{
get
{
if (!IsEditable) return false;
if (AyaBizUtils.Right(RootObjectTypes.WorkorderItem) < (int)SecurityLevelTypes.ReadWriteDelete) return false;
return true;
}
}
/// <summary>
/// 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.)
/// </summary>
public bool IsWorkorderItemChildEditable(RootObjectTypes WorkorderItemChildObjectType)//case 1562
{
if (!IsWorkorderItemEditable) return false;
if (AyaBizUtils.Right(WorkorderItemChildObjectType) < (int)SecurityLevelTypes.ReadWrite) return false;
return true;
}
/// <summary>
/// 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.)
/// </summary>
public bool IsWorkorderItemChildDeletable(RootObjectTypes WorkorderItemChildObjectType)//case 1562
{
if (!IsWorkorderItemEditable) return false;
if (AyaBizUtils.Right(WorkorderItemChildObjectType) < (int)SecurityLevelTypes.ReadWriteDelete) return false;
return true;
}
/// <summary>
/// Quick check if workorder item child is viewable or not
/// </summary>
public bool IsWorkorderItemChildViewable(RootObjectTypes WorkorderItemChildObjectType)//case 1975
{
return (AyaBizUtils.Right(WorkorderItemChildObjectType) > (int)SecurityLevelTypes.NoAccess);
}
/// <summary>
/// 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)
/// </summary>
public SecurityLevelTypes WorkorderItemChildEffectiveRights(RootObjectTypes WorkorderItemChildObjectType)//case 1975
{
if (!IsWorkorderItemEditable) return SecurityLevelTypes.ReadOnly;
return (SecurityLevelTypes)AyaBizUtils.Right(WorkorderItemChildObjectType);
}
/// <summary>
/// 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)
/// </summary>
public bool IsInvoiceNumberEditable
{
get
{
if (Rights < SecurityLevelTypes.ReadWrite) return false;
if (Closed) return false;
if (!ServiceCompleted) return false;
return true;
}
}
/// <summary>
/// Confirms if workorder status can be changed or not
/// </summary>
public bool IsWorkorderStatusEditable
{
get
{
if (Rights < SecurityLevelTypes.ReadWrite) return false;
if (Closed) return false;
return true;
}
}
/// <summary>
/// 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)
/// </summary>
public bool IsSignable
{
get
{
if (Rights < SecurityLevelTypes.ReadWrite) return false;
if (Closed) return false;
if (!ServiceCompleted) return false;
return true;
}
}
/// <summary>
/// Returns true if workorder type is WorkorderTypes.Service
/// </summary>
public bool IsServiceWorkorder
{
get
{
return (WorkorderType == WorkorderTypes.Service);
}
}
/// <summary>
/// Returns true if workorder type is WorkorderTypes.TemplateService
/// </summary>
public bool IsServiceTemplateWorkorder
{
get
{
return (WorkorderType == WorkorderTypes.TemplateService);
}
}
/// <summary>
/// Returns true if workorder type is WorkorderTypes.TemplateQuote
/// </summary>
public bool IsQuoteTemplateWorkorder
{
get
{
return (WorkorderType == WorkorderTypes.TemplateQuote);
}
}
/// <summary>
/// Returns true if workorder type is WorkorderTypes.TemplatePreventiveMaintenance
/// </summary>
public bool IsPreventiveMaintenanceTemplateWorkorder
{
get
{
return (WorkorderType == WorkorderTypes.TemplatePreventiveMaintenance);
}
}
/// <summary>
/// Returns true if workorder type is WorkorderTypes.Service
/// </summary>
public bool IsTemplate
{
get
{
if (WorkorderType == WorkorderTypes.TemplateService ||
WorkorderType == WorkorderTypes.TemplateQuote ||
WorkorderType == WorkorderTypes.TemplatePreventiveMaintenance
) return true;
return false;
}
}
/// <summary>
/// Returns true if sufficient rights and workorder is not closed
/// or service completed
/// </summary>
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;
}
}
/// <summary>
/// Returns true if sufficient rights to save workorder and workorder is not closed
///
/// </summary>
public bool IsSaveAllowed
{
get
{
if (Closed) return false;
if (Rights < SecurityLevelTypes.ReadWrite) return false;
return true;
}
}
/// <summary>
/// Returns true if sufficient rights to
/// change close by date
/// (Object.WorkorderService.CloseByDate)
/// and workorder is editable
///
/// </summary>
public bool IsCloseByDateAllowed
{
get
{
if (!IsEditable) return false;
if (AyaBizUtils.Right("Object.WorkorderService.CloseByDate") < (int)SecurityLevelTypes.ReadWrite) return false;
return true;
}
}
/// <summary>
/// Returns true if sufficient rights to
/// outside service fields
/// (Object.WorkorderItemOutsideService)
/// and workorder is editable
///
/// </summary>
public bool IsOutsideServiceAllowed
{
get
{
if (!IsEditable) return false;
if (AyaBizUtils.Right("Object.WorkorderItemOutsideService") < (int)SecurityLevelTypes.ReadWrite) return false;
return true;
}
}
/// <summary>
/// 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.
/// </summary>
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;
}
}
/// <summary>
/// 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.
/// </summary>
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
/// <summary>
/// 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)
/// </summary>
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();
}
}
/// <summary>
/// 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)
/// </summary>
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();
}
}
/// <summary>
/// Name and address to display on work order form
/// or template type name if it's a template
/// </summary>
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();
}
}
}
/// <summary>
/// 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)
/// </summary>
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);
}
}
}
/// <summary>
/// Flag - indicates if current user can open the wiki page for this object
/// See <see cref="WikiPage.ShowWikiLink(RootObjectTypes, Guid)"/> method for details
///
/// This is cached for the lifetime of this object
/// </summary>
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;
/// <summary>
/// Flag - indicates if this object has a wikipage or not
///
/// </summary>
public bool HasWiki//case 1630
{
get
{
return WikiPageExistanceChecker.WikiPageExists(mID);
}
}
//case 941
/// <summary>
/// Returns the general RootObjectType associated with this workorder's workorder type
/// </summary>
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
/// <summary>
/// Generate a unit for the current workorder's client
/// from specified WorkorderItemPartID for current work order
/// </summary>
/// <returns>A new unit ready to edit</returns>
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
/// <summary>
/// Check to see if current thread user has more than read only rights to Object.Unit
/// </summary>
public bool CanGenerateUnit
{
get
{
return (AyaBizUtils.Right("Object.Unit") > (int)SecurityLevelTypes.ReadOnly);
}
}
//case 1387
/// <summary>
/// Current user's rights to this service workorder / quote / pm / template
/// </summary>
public SecurityLevelTypes Rights
{
get
{
return mRights;
}
}
/// <summary>
/// Read only UI convenience method to get the unique visible ID number presented to the user
/// regardless of type (quote, service, pm, template)
/// </summary>
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();
}
}
}
/// <summary>
/// Read only UI convenience method to get the name of the client
/// </summary>
public string uiDisplayclientName
{
get
{
return NameFetcher.GetItem(RootObjectTypes.Client, mClientID, true).RecordName;
}
}
//case 1975
/// <summary>
/// Read only UI convenience method to get the status of the workorder regardless of type
/// (quote, service, pm)
/// </summary>
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();
}
}
}
/// <summary>
/// Read only UI convenience property
/// true if client for this workorder has popup notes
/// </summary>
public bool uiHasPopupNotes
{
get
{
//insurance
if (mClientID == Guid.Empty) return false;
return (!string.IsNullOrWhiteSpace(ClientPopUpNotesFetcher.GetNotes(mClientID)));
}
}
/// <summary>
/// Read only UI convenience method to get popup notes for this workorder's client
/// </summary>
public string uiPopupNotes
{
get
{
//insurance
if (mClientID == Guid.Empty) return string.Empty;
return ClientPopUpNotesFetcher.GetNotes(mClientID);
}
}
/// <summary>
/// Read only UI convenience method to get this workorder's client object
/// </summary>
public Client uiClient
{
get
{
//insurance
if (mClientID == Guid.Empty) return null;
return Client.GetItemNoMRU(mClientID);
}
}
/// <summary>
/// Read only UI convenience property
/// true if there is a contract in effect for this workorder
/// </summary>
public bool uiHasContract
{
get
{
return ContractResolved() != null;
}
}
/// <summary>
/// Read only UI convenienece property
/// Resolves rights based on users security level as well as
/// workorder closed / service completed status
/// </summary>
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;
}
}
/// <summary>
/// Read only UI convenience property
/// true if this workorder can have a signature
/// </summary>
public bool uiCanViewSignaturePanel
{
get
{
if (mWorkorderType != WorkorderTypes.Service) return false;
return true;
}
}
//case 1975
/// <summary>
/// Report key to use for summary reports for this workorder type
/// </summary>
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
/// <summary>
/// Report key to use for detailed reports for this workorder type
/// </summary>
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;
}
}
}
/// <summary>
/// Read only UI convenience property
/// true if this workorder can be signed
/// </summary>
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;
}
}
/// <summary>
/// Read only UI convenience property
/// true if this workorder has a signature
/// </summary>
public bool uiHasSignature
{
get
{
if (mWorkorderType != WorkorderTypes.Service) return false;
return mService.Signature.HasSignature;
}
}
/// <summary>
/// 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)
/// </summary>
private void ThrowSetError()
{
throw new System.Security.SecurityException
(
string.Format
(
LocalizedTextTable.GetLocalizedTextDirect("Error.Security.NotAuthorizedToChange"),
LocalizedTextTable.GetLocalizedTextDirect("O.Workorder")
)
);
}
#endregion
#region System.object overrides
/// <summary>
///
/// </summary>
/// <returns></returns>
public override string ToString()
{
return "WO Header" + mID.ToString();
}
/// <summary>
///
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public override bool Equals(Object obj)
{
if (obj == null || GetType() != obj.GetType()) return false;
Workorder c = (Workorder)obj;
return mID == c.mID;
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public override int GetHashCode()
{
return ("WO Header" + mID.ToString()).GetHashCode();
}
#endregion
#region Searching
/// <summary>
/// Returns a search result object based on search terms
/// for the ID specified
/// </summary>
/// <param name="ID"></param>
/// <param name="searchTerms"></param>
/// <returns></returns>
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
/// <summary>
/// Generate a new workorder / quote / pm from
/// supplied template and client ID
/// </summary>
/// <param name="TemplateID">REquired</param>
/// <param name="ClientID">Required</param>
/// <returns></returns>
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);
}
/// <summary>
/// Create a new workorder overload to accept a root object type rather than a <see cref="WorkorderTypes"/> enum
/// </summary>
/// <param name="rootObjectType">Must be a valid workorder type of RootObject, i.e. quote, pm, service</param>
/// <returns>New workorder</returns>
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);
}
/// <summary>
/// Create new Workorder
/// </summary>
/// <returns>Workorder</returns>
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
/// <summary>
/// Fetch existing Workorder, track MRU
/// </summary>
/// <returns>Workorder</returns>
/// <param name="_ID">Workorder Guid</param>
public static Workorder GetItem(Guid _ID)
{
return GetItemMRU(_ID, true);
}
/// <summary>
/// Fetch existing Workorder, don't track in MRU list
/// </summary>
/// <returns>Workorder</returns>
/// <param name="_ID">Workorder Guid</param>
public static Workorder GetItemNoMRU(Guid _ID)
{
return GetItemMRU(_ID, false);
}
/// <summary>
/// Determines current user's rights to specific workorder object
/// be it a quote or service workorder or pm or template etc.
/// </summary>
/// <param name="_ID"></param>
/// <returns></returns>
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;
}
/// <summary>
/// Get item optionally track MRU
/// See <see cref="UserMRU"/>
/// </summary>
/// <param name="_ID"></param>
/// <param name="TrackMRU"></param>
/// <returns></returns>
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")));
}
/// <summary>
/// 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)
/// </summary>
/// <returns>Workorder</returns>
/// <param name="RootObject">Related object type i.e.</param>
/// <param name="_ID">Related object from a workorder hiearchy (child/grandchild etc) Guid</param>
/// <example>
/// Fetching a work order when you only know the workorderitempart object's ID
/// <code>
/// Workorder w = Workorder.GetWorkorderByRelative(RootObjectTypes.WorkorderItemPart, WorkorderItemPartID);
/// </code>
/// </example>
public static Workorder GetWorkorderByRelative(RootObjectTypes RootObject, Guid _ID)
{
return GetWorkorderByRelativeMRU(RootObject, _ID, true);
}
/// <summary>
/// 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)
/// </summary>
/// <returns>Workorder</returns>
/// <param name="RootObject">Related object type i.e.</param>
/// <param name="_ID">Related object from a workorder hiearchy (child/grandchild etc) Guid</param>
/// <example>
/// Fetching a work order when you only know the workorderitempart object's ID
/// <code>
/// Workorder w = Workorder.GetWorkorderByRelative(RootObjectTypes.WorkorderItemPart, WorkorderItemPartID);
/// </code>
/// </example>
public static Workorder GetWorkorderByRelativeNoMRU(RootObjectTypes RootObject, Guid _ID)
{
return GetWorkorderByRelativeMRU(RootObject, _ID, false);
}
/// <summary>
/// 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)
/// </summary>
/// <returns>Workorder</returns>
/// <param name="RootObject">Related object type i.e.</param>
/// <param name="_ID">Related object from a workorder hiearchy (child/grandchild etc) Guid</param>
/// <param name="TrackMRU">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</param>
/// <example>
/// Fetching a work order when you only know the workorderitempart object's ID
/// <code>
/// Workorder w = Workorder.GetWorkorderByRelative(RootObjectTypes.WorkorderItemPart, WorkorderItemPartID);
/// </code>
/// </example>
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")));
}
/// <summary>
/// Retrieve internal ID from Workorder Number and type
/// </summary>
/// <param name="WorkorderNumber">Service number, Quote number or Preventive maintenance number</param>
/// <param name="Type">Type of workorder (service, quote, pm)</param>
/// <returns>Guid of workorder in database or Guid.Empty if not found or input string invalid</returns>
/// <seealso cref="WorkorderTypes">
/// See WorkorderTypes enum </seealso>
public static Guid GetIDFromNumber(string WorkorderNumber, WorkorderTypes Type)
{
return WorkorderInternalIDFetcher.GetItem(WorkorderNumber, Type);
}
//case 1477
/// <summary>
/// Given a workorder's child or grandchild ID returns
/// that object
/// </summary>
/// <typeparam name="T">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).</typeparam>
/// <param name="ID">Unique GUID ID of descendant object</param>
/// <returns>The related object</returns>
/// <example>
/// Example usage - populating an asp.net combo box with saved grid filters
/// <code>
/// WorkorderItemScheduledUser wis = Workorder.GetDescendant&lt;WorkorderItemScheduledUser&gt;(MyWoItemSchedUserObjectID);
///</code>
/// </example>
public static T GetDescendant<T>(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
/// <summary>
/// Reopen closed Workorder
/// has no effect on already open work orders
/// </summary>
/// <param name="_ID">Workorder GUID</param>
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
/// <summary>
/// Generate a work order from a template
/// </summary>
/// <param name="t"></param>
/// <param name="dest"></param>
/// <returns></returns>
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
/// <summary>
/// Generates a service workorder from a Quote type Workorder
/// </summary>
/// <param name="SourceWorkorderID">ID of Quote</param>
/// <returns>A new service workorder</returns>
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
/// <summary>
/// Generates a service workorder from a PM type Workorder
/// </summary>
/// <param name="SourceWorkorderID">ID of PM</param>
/// <returns>A new service workorder</returns>
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
/// <summary>
/// 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.
/// </summary>
/// <param name="ToWorkorderID"></param>
/// <param name="SourceWorkorderID"></param>
/// <param name="SourceWorkorderItemID"></param>
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
/// <summary>
/// Converts <see cref="RootObjectTypes"/> enum value to corresponding <see cref="WorkorderTypes"/> enum value
/// </summary>
/// <param name="rootobject"></param>
/// <returns></returns>
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;
}
}
/// <summary>
/// Converts a <see cref="WorkorderTypes"/> enum value to corresponding <see cref="RootObjectTypes"/> enum value
/// </summary>
/// <param name="wotype"></param>
/// <returns></returns>
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;
///
/// <param name="Criteria"></param>
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
/// <summary>
/// Called by DataPortal to delete/add/update data into the database
/// </summary>
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
/// <summary>
///
/// </summary>
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;
}
}
/// <summary>
///
/// </summary>
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
/// <summary>
/// Criteria for identifying existing object
/// </summary>
[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
/// <summary>
/// Move a workorder item to a new workorder
/// </summary>
[Serializable, System.ComponentModel.Browsable(false)]
public class WorkorderItemMover//DO_NOT_OBFUSCATE
{
Guid _ToWorkorderID;
Guid _FromWorkorderID;
Guid _WorkorderItemID;
/// <summary>
///
/// </summary>
/// <param name="FromWorkorderID"></param>
/// <param name="ToWorkorderID"></param>
/// <param name="WorkorderItemID"></param>
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
/// <summary>
/// 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.
/// </summary>
[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
/// <summary>
///
/// </summary>
public enum WorkorderEvent : int
{
/// <summary>
/// Status changed on service workorder
/// </summary>
[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.
/// <summary>
/// Close by date passed on service workorder
/// </summary>
[Description("LT:Workorder.Label.Event.CloseByDatePassed")]
CloseByDatePassed = 2,
/// <summary>
/// Quote updated event
/// </summary>
[Description("LT:Workorder.Label.Event.QuoteUpdated")]
QuoteUpdated = 3
}
#endregion
}//end namespace GZTW.AyaNova.BLL