Files
ayanova7/source/bizobjects/AyaLib/GZTW.AyaNova.BLL/WorkorderItemPart.cs
2018-06-29 19:47:36 +00:00

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