/////////////////////////////////////////////////////////// // 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 { /// /// Part object for object's collection /// [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; /// /// 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 /// private string mDescription=""; //part serial record id if using AyaNova inventory private Guid mPartSerialID=Guid.Empty; /// /// If Part is serialized, quantity must always be 1 /// private decimal mQuantity; /// /// Default taken from part inventory - not editable by user /// private decimal mCost; /// /// Default taken from part inventory, but can be edited by user /// private decimal mPrice; /// /// Percentage discount to be applied to the WorkorderItemPart When set discount /// reason is also set indicating why the discount was given /// private decimal mDiscount; /// /// If discount is entered or is obtained from Contract, than type occurs. Can be /// null if no discount /// private WorkorderItemPartDiscountTypes mDiscountType; /// /// 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 /// 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 /// /// Private constructor to prevent direct instantiation /// 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 /// /// Get internal id number Read only property because it's set internally, not /// externally /// public Guid ID { get { return mID; } } /// /// Get created date /// /// /// public string Created { get { return mCreated.ToString(); } } /// /// Get modified date /// /// /// public string Modified { get { return mModified.ToString(); } } /// /// Get user record ID of person who created this record /// /// /// public Guid Creator { get { return mCreator; } } /// /// Get user ID of person who modified this record /// /// /// public Guid Modifier { get { return mModifier; } } /// /// Guid ID of parent object /// public Guid WorkorderItemID { get { return mWorkorderItemID; } } /// /// 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 /// public Guid PartWarehouseID { get { return mPartWarehouseID; } set { if(bReadOnly) ThrowSetError(); else { if(mPartWarehouseID!=value) { mPartWarehouseID = value; MarkDirty(); } } } } /// /// Sales ID for parts /// public Guid TaxPartSaleID { get { return mTaxPartSaleID; } set { if(bReadOnly) ThrowSetError(); else { if(mTaxPartSaleID!=value) { mTaxPartSaleID = value; MarkDirty(); } } } } /// /// ID of /// 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(); } } } } /// /// If using AyaNova inventory, this is the ID of the serial number record for this /// part /// 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(); } } } } /// ///If not using inventory can store serial number here ///Stores serials by default when non inventory or ///for items imported /// public string Description { get { return mDescription; } set { if(bReadOnly) ThrowSetError(); else { if(mDescription!=value) { mDescription = value; MarkDirty(); } } } } /// /// Default taken from part inventory /// 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?? } } } } /// /// Default taken from part inventory, but can be edited by user /// public decimal Price { get { return mPrice; } set { if(bReadOnly) ThrowSetError(); else { if(mPrice!=value) { mPrice = value; MarkDirty(); } } } } /// /// 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. /// [System.ComponentModel.Browsable(false)] public decimal PriceOverride { set { if(mPrice!=value) { mPrice = value; MarkDirty(); } } } /// /// If Part is serialized, quantity must always be 1 /// 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(); } } } } /// /// 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 /// /// public decimal QuantityReserved { get { return mQuantityReserved; } set { if(bReadOnly) ThrowSetError(); else { if(mQuantityReserved!=value) { mQuantityReserved = value; MarkDirty(); } } } } /// /// /// This item may be deprecated and unused /// public WorkorderItemPartDiscountTypes DiscountType { get { return mDiscountType; } set { if(bReadOnly) ThrowSetError(); else { if(mDiscountType!=value) { mDiscountType = value; MarkDirty(); } } } } /// /// Percentage discount to be applied to the WorkorderItemPart When set discount /// reason is also set indicating why the discount was given /// public decimal Discount { get { return mDiscount; } set { if(bReadOnly) ThrowSetError(); else { if(mDiscount!=value) { mDiscount = value; MarkDirty(); } } } } /// /// Called by parent collection object /// when called in turn by workorder object that is read only due to /// security or closed or service completed /// /// Either true or the rights allowed for the current user public void SetReadOnly(bool RO) { bReadOnly=RO; } /// /// True = Part has been consumed /// False = Part is only "suggested", not actually consumed yet /// 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(); } } } } /// /// True = Part has been removed from inventory /// False = Part has not yet affected inventory /// public bool HasAffectedInventory { get { return mHasAffectedInventory; } } /// /// 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 /// [System.ComponentModel.Browsable(false)] public bool webMode { set { //unbreak rule if(value==true) BrokenRules.Assert("PartRequired","Error.Object.RequiredFieldEmpty,WorkorderItemPart.Label.PartID","PartID",false); } } /// /// Throw an error when a read only user /// tries to set a property /// (this should normally never be called unless someone is using the developer api since the UI /// should prevent it from happening initially) /// private void ThrowSetError() { throw new System.Security.SecurityException ( string.Format ( LocalizedTextTable.GetLocalizedTextDirect("Error.Security.NotAuthorizedToChange"), LocalizedTextTable.GetLocalizedTextDirect("O.WorkorderItemPart") ) ); } #endregion #region System.object overrides /// /// /// /// public override string ToString() { return "WorkorderItemPart" + mID.ToString(); } /// /// /// /// /// public override bool Equals(Object obj) { if ( obj == null || GetType ( ) != obj.GetType ( ) ) return false; WorkorderItemPart c=(WorkorderItemPart)obj; return mID==c.mID; } /// /// /// /// public override int GetHashCode() { return ("WorkorderItemPart"+mID).GetHashCode(); } #endregion #region Searching /// /// Returns a search result object based on search terms /// for the ID specified /// /// /// /// public static SearchResult GetSearchResult(Guid ID, string[]searchTerms) { //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 /// /// New item /// /// /// 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"))); } /// /// Get Item /// 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 /// /// /// /// 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 /// /// Update child /// /// /// 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 /// /// This handles deleting a part record and updating inventory accordingly /// It's called internally here and also by the collection /// /// /// /// 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 /// /// Update inventory and serials as a result of part being added / removed /// from a workorderitem /// /// /// /// /// /// /// 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