1249 lines
36 KiB
C#
1249 lines
36 KiB
C#
///////////////////////////////////////////////////////////
|
|
// WorkorderItemPart.cs
|
|
// Implementation of Class WorkorderItemPart
|
|
// CSLA type: Editable Child
|
|
// Created on: 07-Jun-2004 8:41:49 AM
|
|
// Object design: Joyce
|
|
// Coded: John 21-July-2004
|
|
///////////////////////////////////////////////////////////
|
|
|
|
using System;
|
|
using System.Data;
|
|
using CSLA.Data;
|
|
using GZTW.Data;
|
|
using CSLA;
|
|
using System.Threading;
|
|
using CSLA.Security;
|
|
|
|
namespace GZTW.AyaNova.BLL {
|
|
/// <summary>
|
|
/// Part object for <see cref="WorkorderItem"/> object's <see cref="WorkorderItemParts"/> collection
|
|
/// </summary>
|
|
[Serializable]
|
|
public class WorkorderItemPart : BusinessBase {
|
|
|
|
#region Attributes
|
|
|
|
private bool bReadOnly;
|
|
private Guid mID;
|
|
private SmartDate mCreated;
|
|
private SmartDate mModified;
|
|
private Guid mCreator;
|
|
private Guid mModifier;
|
|
private Guid mWorkorderItemID;
|
|
|
|
private Guid mPartID;
|
|
/// <summary>
|
|
/// If user using inventory, can select from pre-entered list of serial numbers, or
|
|
/// can enter in manually here or use for what have U
|
|
/// </summary>
|
|
private string mDescription="";
|
|
|
|
//part serial record id if using AyaNova inventory
|
|
private Guid mPartSerialID=Guid.Empty;
|
|
|
|
/// <summary>
|
|
/// If Part is serialized, quantity must always be 1
|
|
/// </summary>
|
|
private decimal mQuantity;
|
|
/// <summary>
|
|
/// Default taken from part inventory - not editable by user
|
|
/// </summary>
|
|
private decimal mCost;
|
|
/// <summary>
|
|
/// Default taken from part inventory, but can be edited by user
|
|
/// </summary>
|
|
private decimal mPrice;
|
|
|
|
/// <summary>
|
|
/// Percentage discount to be applied to the WorkorderItemPart When set discount
|
|
/// reason is also set indicating why the discount was given
|
|
/// </summary>
|
|
private decimal mDiscount;
|
|
/// <summary>
|
|
/// If discount is entered or is obtained from Contract, than type occurs. Can be
|
|
/// null if no discount
|
|
/// </summary>
|
|
private WorkorderItemPartDiscountTypes mDiscountType;
|
|
|
|
|
|
/// <summary>
|
|
/// Warehouse GUID that part was reserved from, or taken out of inventory from, as
|
|
/// well as when specifiy ToBeOrdered, PO knows it is needed for a specific
|
|
/// warehouse
|
|
/// </summary>
|
|
private Guid mPartWarehouseID;
|
|
|
|
private bool mUsed;
|
|
private bool mHasAffectedInventory;
|
|
|
|
|
|
private Guid mTaxPartSaleID;
|
|
|
|
//Used when reserved for a quote or a PM
|
|
private decimal mQuantityReserved;
|
|
|
|
//Type of workorder
|
|
//used to flag whether to track serial numbers
|
|
//etc
|
|
internal WorkorderTypes mWorkorderType;
|
|
|
|
|
|
#endregion
|
|
|
|
#region Constructor
|
|
|
|
/// <summary>
|
|
/// Private constructor to prevent direct instantiation
|
|
/// </summary>
|
|
private WorkorderItemPart()
|
|
{
|
|
//Set to read / write initially so that properties
|
|
//can be set
|
|
bReadOnly=false;
|
|
|
|
//Child object
|
|
MarkAsChild();
|
|
|
|
//New ID
|
|
mID = Guid.NewGuid();
|
|
|
|
//Default warehouse
|
|
mPartWarehouseID=PartWarehouse.DefaultWarehouseID;
|
|
|
|
//Set record history to defaults
|
|
mCreated = new SmartDate(DBUtil.CurrentWorkingDateTime);
|
|
mModified=new SmartDate();
|
|
mCreator=Guid.Empty;
|
|
mModifier=Guid.Empty;
|
|
|
|
mUsed=false;
|
|
mHasAffectedInventory=false;
|
|
|
|
mTaxPartSaleID=AyaBizUtils.GlobalSettings.TaxPartSaleID;
|
|
|
|
|
|
|
|
}
|
|
|
|
#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>
|
|
/// Guid ID of parent <see cref="WorkorderItem"/> object
|
|
/// </summary>
|
|
public Guid WorkorderItemID
|
|
{
|
|
get
|
|
{
|
|
return mWorkorderItemID;
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// <see cref="PartWarehouse"/> GUID that part was reserved from, or taken out of inventory from, as
|
|
/// well as when specifiy ToBeOrdered, PO knows it is needed for a specific
|
|
/// warehouse
|
|
/// </summary>
|
|
public Guid PartWarehouseID
|
|
{
|
|
get
|
|
{
|
|
return mPartWarehouseID;
|
|
}
|
|
set
|
|
{
|
|
if(bReadOnly)
|
|
ThrowSetError();
|
|
else
|
|
{
|
|
if(mPartWarehouseID!=value)
|
|
{
|
|
mPartWarehouseID = value;
|
|
MarkDirty();
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sales <see cref="TaxCode"/> ID for parts
|
|
/// </summary>
|
|
public Guid TaxPartSaleID
|
|
{
|
|
get
|
|
{
|
|
return mTaxPartSaleID;
|
|
}
|
|
set
|
|
{
|
|
if(bReadOnly)
|
|
ThrowSetError();
|
|
else
|
|
{
|
|
if(mTaxPartSaleID!=value)
|
|
{
|
|
mTaxPartSaleID = value;
|
|
MarkDirty();
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// ID of <see cref="Part"/>
|
|
/// </summary>
|
|
public Guid PartID
|
|
{
|
|
get
|
|
{
|
|
return mPartID;
|
|
}
|
|
set
|
|
{
|
|
if(bReadOnly)
|
|
ThrowSetError();
|
|
else
|
|
{
|
|
if(mPartID!=value || value==Guid.Empty)//allow guid.empty so that broken rule can Process from NewItem
|
|
{
|
|
mPartID = value;
|
|
|
|
|
|
//Added: 02-August-2006 cost was not getting set prior to this
|
|
PartPickList ppl = null;
|
|
if (mPartID != Guid.Empty)
|
|
{
|
|
ppl = PartPickList.GetOnePart(mPartID);
|
|
mCost = ppl[0].Cost;
|
|
}
|
|
|
|
if (mPartID != Guid.Empty && AyaBizUtils.GlobalSettings.UseInventory && mWorkorderType == WorkorderTypes.Service && this.mQuantity != 0)
|
|
{
|
|
|
|
if (ppl[0].TrackSerialNumber)
|
|
BrokenRules.Assert("SerialNumberRequired", "Error.Object.RequiredFieldEmpty,WorkorderItemPart.Label.PartSerialID", "PartSerialID", mPartSerialID == Guid.Empty);
|
|
else
|
|
//unbreak serial number rule just in case it's broken, but user switched
|
|
//to a non-serialized part
|
|
BrokenRules.Assert("SerialNumberRequired", "Error.Object.RequiredFieldEmpty,WorkorderItemPart.Label.PartSerialID", "PartSerialID", false);
|
|
}
|
|
else
|
|
//unbreak serial number rule just in case it's broken, but user switched
|
|
//to a non-serialized part
|
|
BrokenRules.Assert("SerialNumberRequired","Error.Object.RequiredFieldEmpty,WorkorderItemPart.Label.PartSerialID","PartSerialID",false);
|
|
|
|
//A part is required
|
|
//if(!webMode)
|
|
BrokenRules.Assert("PartRequired","Error.Object.RequiredFieldEmpty,WorkorderItemPart.Label.PartID","PartID",value==Guid.Empty);
|
|
MarkDirty();
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// If using AyaNova inventory, this is the ID of the serial number record for this
|
|
/// part
|
|
/// </summary>
|
|
public Guid PartSerialID
|
|
{
|
|
get
|
|
{
|
|
return mPartSerialID;
|
|
}
|
|
set
|
|
{
|
|
if(bReadOnly)
|
|
ThrowSetError();
|
|
else
|
|
{
|
|
if(mPartSerialID!=value)
|
|
{
|
|
mPartSerialID = value;
|
|
if(mPartSerialID!=Guid.Empty)
|
|
BrokenRules.Assert("SerialNumberRequired","Error.Object.RequiredFieldEmpty,WorkorderItemPart.Label.PartSerialID","PartSerialID",false);
|
|
|
|
//Case 854 user shouldn't be able to set serialized item to anything other than 1
|
|
if (mPartSerialID != Guid.Empty) Quantity = 1;
|
|
|
|
MarkDirty();
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
///If not using inventory can store serial number here
|
|
///Stores serials by default when non inventory or
|
|
///for items imported
|
|
/// </summary>
|
|
public string Description
|
|
{
|
|
get
|
|
{
|
|
return mDescription;
|
|
}
|
|
set
|
|
{
|
|
if(bReadOnly)
|
|
ThrowSetError();
|
|
else
|
|
{
|
|
if(mDescription!=value)
|
|
{
|
|
mDescription = value;
|
|
MarkDirty();
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Default taken from part inventory
|
|
/// </summary>
|
|
public decimal Cost
|
|
{
|
|
get
|
|
{
|
|
return mCost;
|
|
}
|
|
set
|
|
{
|
|
if(bReadOnly)
|
|
ThrowSetError();
|
|
else
|
|
{
|
|
if(mCost!=value)
|
|
{
|
|
mCost = value;
|
|
MarkDirty();
|
|
//todo: a rule to stop it being read write except on import??
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Default taken from part inventory, but can be edited by user
|
|
/// </summary>
|
|
public decimal Price
|
|
{
|
|
get
|
|
{
|
|
return mPrice;
|
|
}
|
|
set
|
|
{
|
|
if(bReadOnly)
|
|
ThrowSetError();
|
|
else
|
|
{
|
|
if(mPrice!=value)
|
|
{
|
|
mPrice = value;
|
|
MarkDirty();
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// This is a forcible price override that can be
|
|
/// used on a read only workorder item part through
|
|
/// the developers API only, it's not exposed in the user
|
|
/// interface.
|
|
///
|
|
/// It's intention is to allow fine tuning of prices
|
|
/// if they do not match a 3rd party integration application
|
|
/// such as accounting software before invoicing.
|
|
/// </summary>
|
|
[System.ComponentModel.Browsable(false)]
|
|
public decimal PriceOverride
|
|
{
|
|
set
|
|
{
|
|
|
|
if(mPrice!=value)
|
|
{
|
|
mPrice = value;
|
|
MarkDirty();
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// If Part is serialized, quantity must always be 1
|
|
/// </summary>
|
|
public decimal Quantity
|
|
{
|
|
get
|
|
{
|
|
return mQuantity;
|
|
}
|
|
set
|
|
{
|
|
if(bReadOnly)
|
|
ThrowSetError();
|
|
else
|
|
{
|
|
if(mQuantity!=value)
|
|
{
|
|
mQuantity = value;
|
|
|
|
//Case 854 user shouldn't be able to set serialized item to anything other than 1
|
|
if (mPartSerialID != Guid.Empty) mQuantity = 1;
|
|
|
|
if(mPartID!=Guid.Empty && AyaBizUtils.GlobalSettings.UseInventory && mWorkorderType==WorkorderTypes.Service && this.mQuantity!=0)
|
|
{
|
|
PartPickList ppl=PartPickList.GetOnePart(mPartID);
|
|
if(ppl[0].TrackSerialNumber)
|
|
BrokenRules.Assert("SerialNumberRequired","Error.Object.RequiredFieldEmpty,WorkorderItemPart.Label.PartSerialID","PartSerialID",mPartSerialID==Guid.Empty);
|
|
else
|
|
//unbreak serial number rule just in case it's broken, but user switched
|
|
//to a non-serialized part
|
|
BrokenRules.Assert("SerialNumberRequired","Error.Object.RequiredFieldEmpty,WorkorderItemPart.Label.PartSerialID","PartSerialID",false);
|
|
|
|
|
|
}
|
|
else
|
|
//unbreak serial number rule just in case it's broken, but user switched
|
|
//to a non-serialized part
|
|
BrokenRules.Assert("SerialNumberRequired","Error.Object.RequiredFieldEmpty,WorkorderItemPart.Label.PartSerialID","PartSerialID",false);
|
|
|
|
MarkDirty();
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reserved quantity
|
|
///
|
|
/// Set internally by a Quote or PreventiveMaintenance
|
|
/// workorder when they are converted to a service workorder
|
|
/// and the global setting UseInventory is true.
|
|
///
|
|
/// Since serial numbers and inventory quantities are not known
|
|
/// at the time of the quote creation or PM creation this serves
|
|
/// as an alternate quantity field.
|
|
///
|
|
/// This is used to indicate to the user the quantity that
|
|
/// was selected on the quote or pm so they can enter the
|
|
/// actual quantity on the service workorder, select serial numbers
|
|
/// be advised of inventory that is out of stock etc
|
|
///
|
|
/// </summary>
|
|
public decimal QuantityReserved
|
|
{
|
|
get
|
|
{
|
|
return mQuantityReserved;
|
|
}
|
|
set
|
|
{
|
|
if(bReadOnly)
|
|
ThrowSetError();
|
|
else
|
|
{
|
|
if(mQuantityReserved!=value)
|
|
{
|
|
mQuantityReserved = value;
|
|
MarkDirty();
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// <see cref="WorkorderItemPartDiscountTypes"/>
|
|
/// This item may be deprecated and unused
|
|
/// </summary>
|
|
public WorkorderItemPartDiscountTypes DiscountType
|
|
{
|
|
get
|
|
{
|
|
return mDiscountType;
|
|
}
|
|
set
|
|
{
|
|
if(bReadOnly)
|
|
ThrowSetError();
|
|
else
|
|
{
|
|
if(mDiscountType!=value)
|
|
{
|
|
mDiscountType = value;
|
|
MarkDirty();
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Percentage discount to be applied to the WorkorderItemPart When set discount
|
|
/// reason is also set indicating why the discount was given
|
|
/// </summary>
|
|
public decimal Discount
|
|
{
|
|
get
|
|
{
|
|
return mDiscount;
|
|
}
|
|
set
|
|
{
|
|
if(bReadOnly)
|
|
ThrowSetError();
|
|
else
|
|
{
|
|
if(mDiscount!=value)
|
|
{
|
|
mDiscount = value;
|
|
MarkDirty();
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Called by parent collection object
|
|
/// when called in turn by workorder object that is read only due to
|
|
/// security or closed or service completed
|
|
/// </summary>
|
|
/// <param name="RO">Either true or the rights allowed for the current user</param>
|
|
public void SetReadOnly(bool RO)
|
|
{
|
|
bReadOnly=RO;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// True = Part has been consumed
|
|
/// False = Part is only "suggested", not actually consumed yet
|
|
/// </summary>
|
|
public bool Used
|
|
{
|
|
get
|
|
{
|
|
return mUsed;
|
|
}
|
|
set
|
|
{
|
|
if(bReadOnly)
|
|
ThrowSetError();
|
|
else
|
|
{
|
|
if(mUsed!=value)
|
|
{
|
|
mUsed = value;
|
|
|
|
//case 3184
|
|
BrokenRules.Assert("PartRequired", "Error.Object.RequiredFieldEmpty,WorkorderItemPart.Label.PartID", "PartID", mPartID == Guid.Empty);
|
|
|
|
MarkDirty();
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// True = Part has been removed from inventory
|
|
/// False = Part has not yet affected inventory
|
|
/// </summary>
|
|
public bool HasAffectedInventory
|
|
{
|
|
get
|
|
{
|
|
return mHasAffectedInventory;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Indicates a record will be created in a web server
|
|
/// and may not have a valid part ID initially
|
|
/// so business rule regarding requirement for valid part ID should be
|
|
/// relaxed temporarily
|
|
/// </summary>
|
|
[System.ComponentModel.Browsable(false)]
|
|
public bool webMode
|
|
{
|
|
set
|
|
{
|
|
//unbreak rule
|
|
if(value==true)
|
|
BrokenRules.Assert("PartRequired","Error.Object.RequiredFieldEmpty,WorkorderItemPart.Label.PartID","PartID",false);
|
|
}
|
|
}
|
|
|
|
|
|
/// <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.WorkorderItemPart")
|
|
)
|
|
);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region System.object overrides
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public override string ToString()
|
|
{
|
|
return "WorkorderItemPart" + mID.ToString();
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="obj"></param>
|
|
/// <returns></returns>
|
|
public override bool Equals(Object obj)
|
|
{
|
|
if ( obj == null || GetType ( ) != obj.GetType ( ) ) return false;
|
|
WorkorderItemPart c=(WorkorderItemPart)obj;
|
|
return mID==c.mID;
|
|
}
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public override int GetHashCode()
|
|
{
|
|
return ("WorkorderItemPart"+mID).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)
|
|
{
|
|
//case 1387
|
|
if (Workorder.RightsToWorkorder(WorkorderIDFetcher.GetWorkorderByRelative(RootObjectTypes.WorkorderItemPart, ID)) < SecurityLevelTypes.ReadOnly)
|
|
return new SearchResult();
|
|
|
|
|
|
SearchResult sr=new SearchResult();
|
|
|
|
|
|
|
|
System.Text.StringBuilder sb = new System.Text.StringBuilder();
|
|
SafeDataReader dr = null;
|
|
try
|
|
{
|
|
|
|
//Case 88 removed
|
|
//"SELECT aID, aCreator, aModifier, aCreated, aModified, aDescription " +
|
|
//"FROM aWorkorderItemPart WHERE (aID = @ID)"
|
|
dr=DBUtil.GetReaderFromSQLString(
|
|
"SELECT AWORKORDERITEMPART.aID, AWORKORDERITEMPART.aCreator, " +
|
|
" AWORKORDERITEMPART.aModifier, AWORKORDERITEMPART.aCreated, " +
|
|
" AWORKORDERITEMPART.aModified, AWORKORDERITEMPART.aDescription, " +
|
|
"AWORKORDERSERVICE.ASERVICENUMBER, " +
|
|
" AWORKORDERQUOTE.AQUOTENUMBER, AWORKORDERPREVENTIVEMAINTENANCE.APREVENTIVEMAINTENANCENUMBER, " +
|
|
" ACLIENT.ANAME AS ACLIENTNAME, aClient.aRegionID AS ACLIENTREGION, AWORKORDER.aWorkorderType " +
|
|
"FROM AWORKORDERITEMPART INNER JOIN AWORKORDERITEM " +
|
|
"ON AWORKORDERITEMPART.AWORKORDERITEMID = AWORKORDERITEM.AID " +
|
|
"LEFT OUTER " +
|
|
"JOIN AWORKORDER ON AWORKORDERITEM.AWORKORDERID = " +
|
|
"AWORKORDER.AID LEFT OUTER JOIN ACLIENT ON AWORKORDER.ACLIENTID " +
|
|
"= ACLIENT.AID LEFT OUTER JOIN AWORKORDERPREVENTIVEMAINTENANCE " +
|
|
"ON AWORKORDER.AID = " +
|
|
"AWORKORDERPREVENTIVEMAINTENANCE.AWORKORDERID LEFT OUTER JOIN " +
|
|
"AWORKORDERQUOTE ON AWORKORDER.AID = AWORKORDERQUOTE.AWORKORDERID " +
|
|
"LEFT OUTER JOIN AWORKORDERSERVICE " +
|
|
"ON AWORKORDER.AID = AWORKORDERSERVICE.AWORKORDERID " +
|
|
"WHERE (AWORKORDERITEMPART.aID = @ID)"
|
|
|
|
,ID);
|
|
|
|
if(!dr.Read())
|
|
return new SearchResult();//DBUtil.ThrowFetchError("SearchResult for WorkorderItemPartID: " + ID.ToString());
|
|
|
|
if (!AyaBizUtils.InYourRegion(dr.GetGuid("ACLIENTREGION"))) return new SearchResult();//case 58
|
|
|
|
//Case 88 parse out workorder type and prepare description field accordingly
|
|
|
|
WorkorderTypes workorderType = (WorkorderTypes)dr.GetInt16("aWorkorderType");
|
|
switch (workorderType)
|
|
{
|
|
case WorkorderTypes.Service:
|
|
sr.Description = LocalizedTextTable.GetLocalizedTextDirect("O.WorkorderService") + " " + dr.GetInt32("aServiceNumber").ToString() + " " + dr.GetString("ACLIENTNAME");
|
|
break;
|
|
case WorkorderTypes.Quote:
|
|
sr.Description = LocalizedTextTable.GetLocalizedTextDirect("O.WorkorderQuote") + " " + dr.GetInt32("AQUOTENUMBER").ToString() + " " + dr.GetString("ACLIENTNAME");
|
|
break;
|
|
case WorkorderTypes.PreventiveMaintenance:
|
|
sr.Description = LocalizedTextTable.GetLocalizedTextDirect("O.WorkorderPreventiveMaintenance") + " " + dr.GetInt32("APREVENTIVEMAINTENANCENUMBER").ToString() + " " + dr.GetString("ACLIENTNAME");
|
|
break;
|
|
}
|
|
|
|
sb.Append(dr.GetString("aDescription"));
|
|
|
|
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.WorkorderItemPart;
|
|
|
|
return sr;
|
|
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Static methods
|
|
|
|
|
|
/// <summary>
|
|
/// New item
|
|
/// </summary>
|
|
/// <param name="obj"></param>
|
|
/// <returns></returns>
|
|
internal static WorkorderItemPart NewItem(WorkorderItem obj)
|
|
{
|
|
|
|
//case 1387
|
|
if (AyaBizUtils.IsGenerator || ((obj.mHeaderRights > SecurityLevelTypes.ReadOnly) &&
|
|
(AyaBizUtils.Right("Object.WorkorderItemPart") > (int)SecurityLevelTypes.ReadOnly)))
|
|
{
|
|
WorkorderItemPart child = new WorkorderItemPart();
|
|
child.mWorkorderItemID=obj.ID;
|
|
child.mWorkorderType=obj.mWorkorderType;
|
|
child.PartID=Guid.Empty;
|
|
return child;
|
|
}
|
|
else
|
|
throw new System.Security.SecurityException(
|
|
string.Format(
|
|
LocalizedTextTable.GetLocalizedTextDirect("Error.Security.NotAuthorizedToCreate"),
|
|
LocalizedTextTable.GetLocalizedTextDirect("O.WorkorderItemPart")));
|
|
|
|
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get Item
|
|
/// </summary>
|
|
internal static WorkorderItemPart GetItem(SafeDataReader dr, WorkorderTypes type, WorkorderItem obj)
|
|
{
|
|
//case 1387
|
|
if ((obj.mHeaderRights > SecurityLevelTypes.NoAccess) &&
|
|
(AyaBizUtils.Right("Object.WorkorderItemPart") > (int)SecurityLevelTypes.NoAccess))
|
|
{
|
|
WorkorderItemPart child = new WorkorderItemPart();
|
|
child.mWorkorderType=type;
|
|
child.Fetch(dr);
|
|
return child;
|
|
}
|
|
else
|
|
throw new System.Security.SecurityException(
|
|
string.Format(
|
|
LocalizedTextTable.GetLocalizedTextDirect("Error.Security.NotAuthorizedToRetrieve"),
|
|
LocalizedTextTable.GetLocalizedTextDirect("O.WorkorderItemPart")));
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
#region DAL DATA ACCESS
|
|
|
|
#region Fetch
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="dr"></param>
|
|
protected void Fetch(SafeDataReader dr)
|
|
{
|
|
|
|
//Standard fields
|
|
mCreated=DBUtil.ToLocal(dr.GetSmartDate("aCreated"));
|
|
mModified=DBUtil.ToLocal(dr.GetSmartDate("aModified"));
|
|
mCreator=dr.GetGuid("aCreator");
|
|
mModifier=dr.GetGuid("aModifier");
|
|
mID=dr.GetGuid("aID");
|
|
|
|
//WorkorderItemPart fields
|
|
mWorkorderItemID=dr.GetGuid("aWorkorderItemID");
|
|
mCost=dr.GetDecimal("aCost");
|
|
mDiscount=dr.GetDecimal("aDiscount");
|
|
mDiscountType=(WorkorderItemPartDiscountTypes)dr.GetInt16("aDiscountType");
|
|
mPartID=dr.GetGuid("aPartID");
|
|
|
|
mPartWarehouseID=dr.GetGuid("aPartWarehouseID");
|
|
mPrice=dr.GetDecimal("aPrice");
|
|
mQuantity=dr.GetDecimal("aQuantity");
|
|
mDescription=dr.GetString("aDescription");
|
|
|
|
mPartSerialID=dr.GetGuid("aPartSerialID");
|
|
|
|
mUsed=dr.GetBoolean("aUsed");
|
|
|
|
mHasAffectedInventory=dr.GetBoolean("aHasAffectedInventory");
|
|
mTaxPartSaleID=dr.GetGuid("aTaxPartSaleID");
|
|
mQuantityReserved=dr.GetDecimal("aQuantityReserved");
|
|
|
|
//Get access rights level
|
|
bReadOnly=AyaBizUtils.Right("Object.WorkorderItemPart")<(int)SecurityLevelTypes.ReadWrite;
|
|
|
|
//Once a part has affected inventory it's read only
|
|
if(mHasAffectedInventory) bReadOnly=true;
|
|
|
|
MarkOld();
|
|
|
|
}
|
|
#endregion fetch
|
|
|
|
#region Add / Update
|
|
|
|
/// <summary>
|
|
/// Update child
|
|
/// </summary>
|
|
/// <param name="obj"></param>
|
|
/// <param name="tr"></param>
|
|
internal void Update(WorkorderItem obj,IDbTransaction tr)
|
|
{
|
|
//No need to update if there is nothing changed
|
|
if(!this.IsDirty) return;
|
|
|
|
// If not a new record, check if record was modified
|
|
//by another user since original retrieval:
|
|
if(!IsNew)
|
|
DBUtil.CheckSafeToUpdateInsideTransaction(this.mModified.Date, this.mID, "aWorkorderItemPart", tr);//case 1960
|
|
|
|
#region Delete
|
|
if(IsDeleted)
|
|
{
|
|
if(!IsNew)
|
|
{
|
|
//Added: 30-Sept-2006
|
|
//was corrupting inventory by restoring quantity to inventory
|
|
//regardless of whether had affected inventory in the first place
|
|
if (this.mHasAffectedInventory && this.mWorkorderType == WorkorderTypes.Service)
|
|
InventoryUpdate(this.mID,this.mPartSerialID,this.mPartID,-this.Quantity,this.mPartWarehouseID,tr);
|
|
|
|
DeleteItem(this.mID,false,tr);
|
|
//reset critical fields
|
|
bReadOnly=false;//Rights? If it's just deleted then the user has full rights anyway
|
|
this.mHasAffectedInventory=false;
|
|
this.mUsed=false;
|
|
|
|
}
|
|
MarkNew();
|
|
return;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Add / Update
|
|
//get modification time temporarily, if update succeeds then
|
|
//set to this time
|
|
System.DateTime dtModified = DBUtil.CurrentWorkingDateTime;
|
|
|
|
//Changed: 15-march-2006 - added this so that inventory could be updated
|
|
//after this workorder item part record is saved because it needs to exist before
|
|
//serialized inventory can be updated
|
|
bool UpdateInventory=false;
|
|
|
|
DBCommandWrapper cm = null;
|
|
if(IsNew)//Add or update?
|
|
{
|
|
//Inventory affected?
|
|
if(this.mUsed)
|
|
{
|
|
//Since this is a new part and marked used it must affect inventory so update inventory accordingly
|
|
UpdateInventory=true;
|
|
|
|
//Changed: 15-march-2006, this is throwing an exception because the workorderitempart has
|
|
//not yet been saved so the referential integrity is screwed up, moved below saving of woipt.
|
|
this.mHasAffectedInventory=true;
|
|
}
|
|
|
|
cm=DBUtil.GetCommandFromSQL(
|
|
"INSERT INTO aWorkorderItemPart (aWorkorderItemID, aID, " +
|
|
"aDescription, aPartSerialID, aPartID, aQuantity, " +
|
|
"aCost, aPrice, aDiscount, aDiscountType, " +
|
|
"aPartWarehouseID, aCreated,aModified,aCreator,aModifier, " +
|
|
"aUsed, aHasAffectedInventory, aTaxPartSaleID, aQuantityReserved) VALUES (@WorkorderItemID, " +
|
|
"@ID,@Description,@PartSerialID,@PartID,@Quantity, " +
|
|
"@Cost, @Price,@Discount,@DiscountType, " +
|
|
"@PartWarehouseID,@Created,@Modified,@CurrentUserID,@CurrentUserID, " +
|
|
"@Used,@HasAffectedInventory,@TaxPartSaleID,@QuantityReserved)"
|
|
);
|
|
}
|
|
else
|
|
{
|
|
//--If the part is marked used and hasn't previously affected inventory then
|
|
//--update inventory now
|
|
if(this.mUsed && this.mHasAffectedInventory==false)
|
|
{
|
|
UpdateInventory=true;
|
|
this.mHasAffectedInventory=true;
|
|
}
|
|
cm=DBUtil.GetCommandFromSQL(
|
|
"UPDATE aWorkorderItemPart SET aWorkorderItemID=@WorkorderItemID, " +
|
|
"aID=@ID, aDescription=@Description, " +
|
|
"aPartSerialID=@PartSerialID, aPartID=@PartID, " +
|
|
"aQuantity=@Quantity, aCost=@Cost, aPrice=@Price, " +
|
|
"aDiscount=@Discount, " +
|
|
"aDiscountType=@DiscountType, aPartWarehouseID=@PartWarehouseID, " +
|
|
"aModifier=@CurrentUserID, " +
|
|
"aModified=@Modified, aUsed=@Used, aHasAffectedInventory=@HasAffectedInventory, " +
|
|
"aTaxPartSaleID=@TaxPartSaleID, aQuantityReserved=@QuantityReserved " +
|
|
"WHERE aID=@ID"
|
|
);
|
|
}
|
|
|
|
//WorkorderitemPart specific
|
|
cm.AddInParameter("@ID",DbType.Guid,mID);
|
|
cm.AddInParameter("@WorkorderItemID",DbType.Guid,mWorkorderItemID);
|
|
cm.AddInParameter("@Discount",DbType.Decimal,mDiscount);
|
|
cm.AddInParameter("@Cost",DbType.Decimal,mCost);
|
|
cm.AddInParameter("@DiscountType",DbType.Int16,(int)mDiscountType);
|
|
cm.AddInParameter("@PartID",DbType.Guid,mPartID);
|
|
cm.AddInParameter("@PartWarehouseID",DbType.Guid,mPartWarehouseID);
|
|
cm.AddInParameter("@Price",DbType.Decimal,mPrice);
|
|
cm.AddInParameter("@Quantity",DbType.Decimal,mQuantity);
|
|
cm.AddInParameter("@Description",DbType.String,mDescription);
|
|
cm.AddInParameter("@PartSerialID",DbType.Guid,mPartSerialID);
|
|
cm.AddInParameter("@Used",DbType.Boolean,mUsed);
|
|
cm.AddInParameter("@HasAffectedInventory",DbType.Boolean,mHasAffectedInventory);
|
|
cm.AddInParameter("@TaxPartSaleID",DbType.Guid,mTaxPartSaleID);
|
|
cm.AddInParameter("@QuantityReserved",DbType.Decimal,mQuantityReserved);
|
|
|
|
|
|
//standard parameters
|
|
cm.AddInParameter("@CurrentUserID",DbType.Guid, CurrentUserID);
|
|
cm.AddInParameter("@Created",DbType.DateTime, DBUtil.ToUTC(mCreated.Date));
|
|
cm.AddInParameter("@Modified",DbType.DateTime, DBUtil.ToUTC(dtModified));
|
|
|
|
|
|
DBUtil.DB.ExecuteNonQuery(cm, tr);
|
|
|
|
//Added: 30-Sept-2006
|
|
//was corrupting inventory by restoring quantity to inventory
|
|
//when workorderitempart was deleted from quote or pm
|
|
//not just service as it should
|
|
if (this.mWorkorderType == WorkorderTypes.Service)
|
|
{
|
|
//Changed: 15-march-2006 see above
|
|
//Inventory update
|
|
if (UpdateInventory)
|
|
InventoryUpdate(this.mID, this.mPartSerialID, this.mPartID, this.mQuantity, this.mPartWarehouseID, tr);
|
|
}
|
|
//Process keywords
|
|
DBUtil.ProcessKeywords(tr,this.mID,RootObjectTypes.WorkorderItemPart,IsNew,AyaBizUtils.Break(false,mDescription));
|
|
|
|
MarkOld();//db is now synched with object
|
|
|
|
//Successful update so
|
|
//change modification time to match
|
|
this.mModified.Date=dtModified;
|
|
//if inventory was affected then this is now a read only record
|
|
if(this.mHasAffectedInventory==true)
|
|
this.bReadOnly=true;
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
#endregion add/update
|
|
|
|
#region DeleteItem
|
|
/// <summary>
|
|
/// This handles deleting a part record and updating inventory accordingly
|
|
/// It's called internally here and also by the collection
|
|
/// </summary>
|
|
/// <param name="WorkorderItemPartID"></param>
|
|
/// <param name="bHasAffectedInventory"></param>
|
|
/// <param name="transaction"></param>
|
|
internal static void DeleteItem(Guid WorkorderItemPartID,bool bHasAffectedInventory,IDbTransaction transaction)
|
|
{
|
|
|
|
|
|
//The following will only ever be true if called from the collection's deleteitems method
|
|
//because the delete in the DAL update code for this object
|
|
//will pre-handle updating inventory before calling this
|
|
if(bHasAffectedInventory)
|
|
{
|
|
SafeDataReader dr = null;
|
|
dr=DBUtil.GetReaderFromSQLString(
|
|
"SELECT aPartID, aQuantity, aPartWarehouseID, aPartSerialID FROM aWorkorderItemPart WHERE aID=@ID"
|
|
,WorkorderItemPartID);
|
|
if(!dr.Read())
|
|
DBUtil.ThrowFetchError("WorkorderItemPart ID: " + WorkorderItemPartID.ToString() + " @ WorkorderItemPart:DeleteItem");
|
|
|
|
Guid gpartserial=dr.GetGuid("aPartSerialID");
|
|
Guid gpart=dr.GetGuid("aPartID");
|
|
Guid gwarehouse=dr.GetGuid("aPartWarehouseID");
|
|
decimal dquantity=-dr.GetDecimal("aQuantity");
|
|
dr.Close();
|
|
|
|
InventoryUpdate(WorkorderItemPartID,gpartserial,gpart,dquantity,gwarehouse,transaction);
|
|
}
|
|
|
|
//Delete workorderitempart
|
|
DBCommandWrapper cmDelete = DBUtil.GetCommandFromSQL("DELETE FROM aWorkorderItemPart WHERE aID=@ID;");
|
|
cmDelete.AddInParameter("@ID",DbType.Guid,WorkorderItemPartID);
|
|
DBUtil.DB.ExecuteNonQuery(cmDelete, transaction);
|
|
|
|
DBUtil.RemoveKeywords(transaction,RootObjectTypes.WorkorderItemPart,WorkorderItemPartID);
|
|
|
|
|
|
|
|
}
|
|
#endregion
|
|
|
|
#region Inventory update
|
|
|
|
/// <summary>
|
|
/// Update inventory and serials as a result of part being added / removed
|
|
/// from a workorderitem
|
|
/// </summary>
|
|
/// <param name="workorderItemPartID"></param>
|
|
/// <param name="partSerialID"></param>
|
|
/// <param name="partID"></param>
|
|
/// <param name="quantity"></param>
|
|
/// <param name="partWarehouseID"></param>
|
|
/// <param name="transaction"></param>
|
|
internal static void InventoryUpdate( Guid workorderItemPartID,Guid partSerialID,Guid partID,
|
|
decimal quantity, Guid partWarehouseID, IDbTransaction transaction)
|
|
{
|
|
//BUGBUG: This should never do it if it's a Quote or a PM
|
|
//it should also never happen if it's a service workorder
|
|
//but the part was never removed from inventory.
|
|
|
|
//Added: 30-Sept-2006
|
|
//was corrupting inventory by restoring quantity to inventory
|
|
//when workorderitempart was deleted from quote or pm
|
|
//not just service as it should
|
|
|
|
//Get workorder type, bail if it's not a service workorder
|
|
object o=DBUtil.GetScalarFromSQLString(
|
|
"SELECT " +
|
|
" AWORKORDER.AWORKORDERTYPE " +
|
|
"FROM " +
|
|
" AWORKORDERITEM " +
|
|
" INNER JOIN AWORKORDER ON (AWORKORDERITEM.AWORKORDERID = AWORKORDER.AID) " +
|
|
" INNER JOIN AWORKORDERITEMPART ON (AWORKORDERITEM.AID = AWORKORDERITEMPART.AWORKORDERITEMID) " +
|
|
" WHERE aworkorderitempart.aid=@ID ", workorderItemPartID, transaction);
|
|
if (o == null || o == System.DBNull.Value) return;
|
|
Int16 n = (Int16)o;
|
|
WorkorderTypes wotype = (WorkorderTypes)n;
|
|
if (wotype != WorkorderTypes.Service)
|
|
return;
|
|
|
|
//Added: 30-Sept-2006 just because
|
|
if (!AyaBizUtils.GlobalSettings.UseInventory) return;
|
|
|
|
|
|
//Get current quantity on hand for this item
|
|
decimal newQuantity=PartByWarehouseInventoryValuesFetcher.GetItem(partID,partWarehouseID,transaction).QuantityOnHand;
|
|
|
|
|
|
//adjust...
|
|
newQuantity=newQuantity-quantity;
|
|
|
|
//Update...
|
|
DBCommandWrapper cm = null;
|
|
cm = DBUtil.GetCommandFromSQL(
|
|
"UPDATE aPartByWarehouseInventory SET aQuantityOnHand=@NewQuantity, " +
|
|
"aModifier=@CurrentUserID, aModified=@Modified " +
|
|
"WHERE (aPartID = @PartID) AND (aPartWarehouseID " +
|
|
"= @PartWarehouseID)"
|
|
);
|
|
cm.AddInParameter("@PartID",DbType.Guid,partID);
|
|
cm.AddInParameter("@PartWarehouseID",DbType.Guid,partWarehouseID);
|
|
cm.AddInParameter("@CurrentUserID",DbType.Guid, User.CurrentThreadUserID);
|
|
cm.AddInParameter("@Modified", DbType.DateTime, DBUtil.ToUTC(DBUtil.CurrentWorkingDateTime));
|
|
cm.AddInParameter("@NewQuantity",DbType.Decimal,newQuantity);
|
|
DBUtil.DB.ExecuteNonQuery(cm, transaction);
|
|
|
|
//Are serial numbers affected?
|
|
if(partSerialID==Guid.Empty)
|
|
return;//nope, done
|
|
|
|
//Update the serial numbers
|
|
|
|
DBCommandWrapper cmSerial = null;
|
|
cmSerial=DBUtil.GetCommandFromSQL(
|
|
"UPDATE aPartSerial SET aDateConsumed=@DateConsumed, " +
|
|
"aWorkorderItemPartID=@WorkorderItemPartID, AAVAILABLE=@Available, " +
|
|
"aModifier=@CurrentUserID, aModified=@Modified " +
|
|
"WHERE aPartSerial.aID=@PartSerialID"
|
|
);
|
|
|
|
//standard params
|
|
cmSerial.AddInParameter("@PartSerialID",DbType.Guid,partSerialID);
|
|
cmSerial.AddInParameter("@CurrentUserID",DbType.Guid, User.CurrentThreadUserID);
|
|
cmSerial.AddInParameter("@Modified",DbType.DateTime, DBUtil.ToUTC(DBUtil.CurrentWorkingDateTime));
|
|
|
|
//Specific params for putting back in or removing
|
|
if(quantity==-1)//serialized items can only be a quantity of 1 or negative 1 here
|
|
{
|
|
SmartDate mt=new SmartDate();
|
|
System.Diagnostics.Debug.Assert(mt.IsEmpty,"WorkorderItemPart:InventoryUpdate - DATE NOT EMPTY (it should be)");
|
|
|
|
//replacing
|
|
cmSerial.AddInParameter("@WorkorderItemPartID",DbType.Guid,Guid.Empty);
|
|
cmSerial.AddInParameter("@Available",DbType.Decimal,1);
|
|
cmSerial.AddInParameter("@DateConsumed",DbType.DateTime,mt.DBValue);
|
|
|
|
}
|
|
else
|
|
{
|
|
//removing
|
|
cmSerial.AddInParameter("@WorkorderItemPartID",DbType.Guid,workorderItemPartID);
|
|
cmSerial.AddInParameter("@Available",DbType.Decimal,0);
|
|
cmSerial.AddInParameter("@DateConsumed", DbType.DateTime, DBUtil.ToUTC(DBUtil.CurrentWorkingDateTime));
|
|
|
|
}
|
|
DBUtil.DB.ExecuteNonQuery(cmSerial, transaction);
|
|
|
|
|
|
|
|
}
|
|
#endregion inventory update
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
}//end WorkorderItemPart
|
|
|
|
}//end namespace GZTW.AyaNova.BLL |