/////////////////////////////////////////////////////////// // WorkorderItemPartRequest.cs // Implementation of Class WorkorderItemPartRequest // CSLA type: Editable Child // Created on: 21-Feb-2005 // Object design: John // Coded: John 21-Feb-2005 /////////////////////////////////////////////////////////// using System; using System.Data; using CSLA.Data; using GZTW.Data; using CSLA; using System.Threading; using CSLA.Security; using System.ComponentModel; namespace GZTW.AyaNova.BLL { /// /// Part request object for object's collection /// [Serializable] public class WorkorderItemPartRequest : 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; /// /// /// private decimal mQuantity = 0; /// /// ID of purchase order item if part is OnOrder /// private Guid mPurchaseOrderItemID; /// /// Warehouse GUID /// private Guid mPartWarehouseID; private decimal mReceived = 0; //Read only helper fields private SmartDate mOrderedDate = new SmartDate(); private SmartDate mExpectedReceiveDate = new SmartDate(); private int mPONumber = 0; //case 227 private GridNameValueCellItem mPO = null; #endregion #region Constructor /// /// Private constructor to prevent direct instantiation /// private WorkorderItemPartRequest() { //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; mPurchaseOrderItemID = Guid.Empty; //Set record history to defaults mCreated = new SmartDate(DBUtil.CurrentWorkingDateTime); mModified = new SmartDate(); mCreator = Guid.Empty; mModifier = Guid.Empty; mOrderedDate = new SmartDate(); mExpectedReceiveDate = new SmartDate(); mPONumber = 0; } #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; } set {//TODO: Shouldn't this be read only? //if so, this change will need to be made //all over the place for Editable Child objects //with parent ID values if (bReadOnly) ThrowSetError(); else { if (mWorkorderItemID != value) { mWorkorderItemID = value; MarkDirty(); } } } } /// /// GUID /// public Guid PartWarehouseID { get { return mPartWarehouseID; } set { if (bReadOnly) ThrowSetError(); else { if (mPartWarehouseID != value) { mPartWarehouseID = value; MarkDirty(); } } } } /// /// ID of if part is OnOrder /// public Guid PurchaseOrderItemID { get { return mPurchaseOrderItemID; } set { if (bReadOnly) ThrowSetError(); else { if (mPurchaseOrderItemID != value) { mPurchaseOrderItemID = value; MarkDirty(); } } } } /// /// Flag to indicate if this WorkorderItemPartRequest /// is on order. /// (has a purchase order item ID and has less received than the quantity /// requested) /// public bool OnOrder { get { //changed: 28-March-2006 from received <> quantity to //received not less than quantity because people //are finding a way to accidentally order more than required which //was causing it to be stuck on order because 2 received is more than //1 ordered if (mPurchaseOrderItemID == Guid.Empty) return false; if (this.mReceived < this.mQuantity) return true; return false; //return mPurchaseOrderItemID!=Guid.Empty && !(this.mReceived < this.mQuantity); } } /// /// Flag to indicate if this WorkorderItemPartRequest /// has not yet been ordered /// (has a quantity but no purchase order item ID) /// public bool Unordered//new for case 885 { get { if (mQuantity > 0 && mPurchaseOrderItemID == Guid.Empty) return true; return false; } } /// /// ID /// public Guid PartID { get { return mPartID; } set { if (bReadOnly) ThrowSetError(); else { if (mPartID != value) { mPartID = value; MarkDirty(); } } } } /// /// Quantity of parts requested /// public decimal Quantity { get { return mQuantity; } set { if (bReadOnly) ThrowSetError(); else { if (mQuantity != value) { mQuantity = value; MarkDirty(); } } } } /// /// Quantity of parts received to date against this request /// public decimal Received { get { return mReceived; } } /// /// 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; } //read only UI helper fields /// /// Read only UI helper field /// public object OrderedDate { get { return mOrderedDate.DBValue; } } /// /// Read only UI helper field /// public object ExpectedReceiveDate { get { return mExpectedReceiveDate.DBValue; } } /// /// Read only UI helper field /// public int PONumber { get { return mPONumber; } } //case 227 /// /// Read only UI helper field /// public GridNameValueCellItem PO { get { return mPO; } } //case 1975 /// /// Read only UI helper field /// public bool isDeletable { get { //first do we have the rights? if (!(AyaBizUtils.Right("Object.WorkorderItemPart") > (int)SecurityLevelTypes.ReadWrite)) return false;//not enough rights no point checking further //Does it have a po? if (mPurchaseOrderItemID != Guid.Empty) { //has it been fully received? if (mReceived < mQuantity) return false; //yup, deleteable return true; } else { //we have the rights and there isn't a PO so go ahead return true; } } } /// /// 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.WorkorderItemPartRequest") ) ); } #endregion #region System.object overrides /// /// /// /// public override string ToString() { return "WorkorderItemPartRequest" + mID.ToString(); } /// /// /// /// /// public override bool Equals(Object obj) { if (obj == null || GetType() != obj.GetType()) return false; WorkorderItemPartRequest c = (WorkorderItemPartRequest)obj; return mID == c.mID; } /// /// /// /// public override int GetHashCode() { return ("WorkorderItemPartRequest" + mID).GetHashCode(); } #endregion #region Static methods /// /// Check for existance of a particular part request object /// /// /// public static bool Exists(Guid WorkorderItemPartRequestID) { return WorkorderItemPartRequestExistanceChecker.RequestExists(WorkorderItemPartRequestID); } /// /// New item /// /// /// internal static WorkorderItemPartRequest NewItem(WorkorderItem obj) { if ((obj.mHeaderRights > SecurityLevelTypes.ReadOnly) && (AyaBizUtils.Right("Object.WorkorderItemPart") > (int)SecurityLevelTypes.ReadOnly)) { WorkorderItemPartRequest child = new WorkorderItemPartRequest(); child.mWorkorderItemID = obj.ID; return child; } else throw new System.Security.SecurityException( string.Format( LocalizedTextTable.GetLocalizedTextDirect("Error.Security.NotAuthorizedToCreate"), LocalizedTextTable.GetLocalizedTextDirect("O.WorkorderItemPartRequest"))); } /// /// Get Item /// /// /// /// internal static WorkorderItemPartRequest GetItem(SafeDataReader dr, WorkorderItem obj) { //case 1387 if ((obj.mHeaderRights > SecurityLevelTypes.NoAccess) && (AyaBizUtils.Right("Object.WorkorderItemPart") > (int)SecurityLevelTypes.NoAccess)) { WorkorderItemPartRequest child = new WorkorderItemPartRequest(); child.Fetch(dr); return child; } else throw new System.Security.SecurityException( string.Format( LocalizedTextTable.GetLocalizedTextDirect("Error.Security.NotAuthorizedToRetrieve"), LocalizedTextTable.GetLocalizedTextDirect("O.WorkorderItemPartRequest"))); } /// /// Called by PurchaseOrderReceipt when parts are received against a request /// this method ensures that the request record get's updated accordingly /// notification is sent if subscribed to and finally creates a part record for the workorder /// item ready for the tech /// /// /// /// internal static void ProcessPartsReceived(Guid WorkorderItemPartRequestID, decimal QuantityReceived, IDbTransaction tr) { ReceivePartsProcessor.Receive(WorkorderItemPartRequestID, QuantityReceived, tr); } #endregion #region Shared Notification Message Processor internal static NotifyMessage GetNotificationMessage(NotifyMessageRequestData d) { //string d.Language=User.GetUserLanguage(MessageForUserID); WorkorderItemPartRequestNotificationDescriptionFetcher df = WorkorderItemPartRequestNotificationDescriptionFetcher.GetItem(d.RootObjectID); string sEventDescription = ""; string sExtraInfo = ""; sEventDescription = LocalizedTextTable.GetLocalizedTextDirect("WorkorderItemPartRequest.Label.Event.PartsReceived", d.Language); sExtraInfo = LocalizedTextTable.GetLocalizedTextDirect("O.Part", d.Language) + ": " + df.PartName + df.Received.ToString() + "/" + df.Requested.ToString(); string sMessage = sEventDescription; string sSubject = sEventDescription; NotifyMessage nm = null; if (d.Format == NotifyDeliveryMessageFormats.Brief) { sMessage += " " + LocalizedTextTable.GetLocalizedTextDirect("WorkorderService.Label.ServiceNumber", d.Language) + " " + df.WorkorderNumber + " " + df.ClientName + " " + sExtraInfo; if (d.MaxCharacters > 0 && sMessage.Length > d.MaxCharacters) nm = new NotifyMessage("", sMessage.Substring(0, d.MaxCharacters)); else nm = new NotifyMessage("", sMessage); } else { sSubject += ": " + LocalizedTextTable.GetLocalizedTextDirect("WorkorderService.Label.ServiceNumber", d.Language) + " " + df.WorkorderNumber; sMessage += ": " + LocalizedTextTable.GetLocalizedTextDirect("WorkorderService.Label.ServiceNumber", d.Language) + " " + df.WorkorderNumber + "\r\n" + LocalizedTextTable.GetLocalizedTextDirect("O.Client", d.Language) + ": " + df.ClientName + "\r\n" + sExtraInfo; nm = new NotifyMessage(sSubject, sMessage); } return nm; } #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"); //WorkorderItemPartRequest fields mWorkorderItemID = dr.GetGuid("aWorkorderItemID"); mPartID = dr.GetGuid("aPartID"); mPartWarehouseID = dr.GetGuid("aPartWarehouseID"); mPurchaseOrderItemID = dr.GetGuid("aPurchaseOrderItemID"); mQuantity = dr.GetDecimal("aQuantity"); mReceived = dr.GetDecimal("aReceived"); mOrderedDate = DBUtil.ToLocal(dr.GetSmartDate("aOrderedDate")); mExpectedReceiveDate = DBUtil.ToLocal(dr.GetSmartDate("aExpectedReceiveDate")); mPONumber = dr.GetInt32("aPONumber"); //case 227 mPO = new GridNameValueCellItem(dr.GetGuid("APURCHASEORDERID"), mPONumber.ToString(), RootObjectTypes.PurchaseOrder); //Get access rights level bReadOnly = AyaBizUtils.Right("Object.WorkorderItemPart") < (int)SecurityLevelTypes.ReadWrite; MarkOld(); } #endregion #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, "aWorkorderItemPartRequest", tr);//case 1960 #region Delete if (IsDeleted) { //If there are still outstanding parts on order this can't be removed if (this.mPurchaseOrderItemID != Guid.Empty && this.mReceived < this.mQuantity) { throw new System.ApplicationException (LocalizedTextTable.GetLocalizedTextDirect("WorkorderItemPartRequest.Error.NotDeleteableOnOrder")); } if (!IsNew) { if (this.mPurchaseOrderItemID != Guid.Empty) { //Case 396 - remove the link to the part request //before it's deleted //this code added to handle deleting a part request for //an item that has been fully received already, something the //other code around here did not do as it was only concerned with unreceived but on order //items etc DBCommandWrapper cmz = DBUtil.GetCommandFromSQL( "UPDATE APURCHASEORDERITEM SET AWORKORDERITEMPARTREQUESTID=null " + "WHERE AWORKORDERITEMPARTREQUESTID=@ID;"); cmz.AddInParameter("@ID", DbType.Guid, this.mID); DBUtil.DB.ExecuteNonQuery(cmz, tr); } //Added: 17-Nov-2006 case 157 //added code to delete any purchase order items in existance for this workorder item part request //this is safe to do outright because if we have made it to this point it's already confirmed there //is nothing on order for this part request in the code immediately above here DBCommandWrapper cmDeletepo = DBUtil.GetCommandFromSQL("DELETE FROM APURCHASEORDERITEM WHERE APURCHASEORDERITEM.AWORKORDERITEMPARTREQUESTID=@ID;"); cmDeletepo.AddInParameter("@ID", DbType.Guid, this.mID); DBUtil.DB.ExecuteNonQuery(cmDeletepo, tr); DBCommandWrapper cmDelete = DBUtil.GetCommandFromSQL("DELETE FROM aWorkorderItemPartRequest WHERE aID=@ID;"); cmDelete.AddInParameter("@ID", DbType.Guid, this.mID); DBUtil.DB.ExecuteNonQuery(cmDelete, tr); } MarkNew(); return; } #endregion #region Add / Update //get modification time temporarily, if update succeeds then //set to this time System.DateTime dtModified = DBUtil.CurrentWorkingDateTime; DBCommandWrapper cm = null; if (IsNew)//Add or update? cm = DBUtil.GetCommandFromSQL( "INSERT INTO aWorkorderItemPartRequest (aWorkorderItemID, " + "aID, aPartID, aQuantity, aReceived, aPurchaseOrderItemID, " + "aPartWarehouseID, aCreated, aModified,aCreator,aModifier) VALUES (@WorkorderItemID, " + "@ID,@PartID,@Quantity, @Received, @PurchaseOrderItemID, " + "@PartWarehouseID,@Created,@Modified,@CurrentUserID,@CurrentUserID)" ); else cm = DBUtil.GetCommandFromSQL( "UPDATE aWorkorderItemPartRequest SET aWorkorderItemID=@WorkorderItemID, " + "aID=@ID, aPartID=@PartID, aQuantity=@Quantity, aReceived=@Received, " + "aPurchaseOrderItemID=@PurchaseOrderItemID, " + "aPartWarehouseID=@PartWarehouseID, aModifier=@CurrentUserID, " + "aModified=@Modified WHERE aID=@ID" ); //WorkorderItemPartRequest specific cm.AddInParameter("@ID", DbType.Guid, mID); cm.AddInParameter("@WorkorderItemID", DbType.Guid, mWorkorderItemID); cm.AddInParameter("@PartID", DbType.Guid, mPartID); cm.AddInParameter("@PartWarehouseID", DbType.Guid, mPartWarehouseID); cm.AddInParameter("@PurchaseOrderItemID", DbType.Guid, mPurchaseOrderItemID); cm.AddInParameter("@Quantity", DbType.Decimal, mQuantity); cm.AddInParameter("@Received", DbType.Decimal, mReceived); //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); MarkOld();//db is now synched with object //Successful update so //change modification time to match this.mModified.Date = dtModified; #endregion } #endregion #endregion #region Inventory receipt Processing #pragma warning disable 1591 /// /// Handle receipt of inventory that fulfills /// request /// [Serializable, System.ComponentModel.Browsable(false)] public class ReceivePartsProcessor//DO_NOT_OBFUSCATE { Guid _WorkorderItemPartRequestID; decimal _QuantityReceived; IDbTransaction _tr; public ReceivePartsProcessor(Guid WorkorderItemPartRequestID, decimal QuantityReceived, IDbTransaction tr) { _WorkorderItemPartRequestID = WorkorderItemPartRequestID; _QuantityReceived = QuantityReceived; _tr = tr; } public static void Receive(Guid WorkorderItemPartRequestID, decimal QuantityReceived, IDbTransaction tr) { DataPortal.Update(new ReceivePartsProcessor(WorkorderItemPartRequestID, QuantityReceived, tr)); } public void DataPortal_Update() { #region Update the request record //Get current balance, requestorid and workorderitem ID for Processing SafeDataReader dr = DBUtil.GetReaderFromSQLString( "SELECT aQuantity, aReceived, aWorkorderItemID, aCreator " + "FROM aWorkorderItemPartRequest WHERE aID=@ID", _WorkorderItemPartRequestID, _tr ); if (!dr.Read()) DBUtil.ThrowFetchError("ReceivePartsProcessor.Update fetching part request balances for receiving. WorkorderItemPartRequestID: " + _WorkorderItemPartRequestID.ToString()); decimal NewReceivedQuantity = dr.GetDecimal("aReceived"); NewReceivedQuantity += _QuantityReceived; decimal Ordered = dr.GetDecimal("aQuantity"); Guid WorkorderItemID = dr.GetGuid("aWorkorderItemID"); Guid RequestorID = dr.GetGuid("aCreator"); dr.Close(); //Update the current received value DBCommandWrapper cmUpdateRequest = DBUtil.GetCommandFromSQL( "UPDATE aWorkorderItemPartRequest SET aReceived=@Received, " + "aModifier=@CurrentUserID, " + "aModified=@Modified WHERE aID=@ID" ); //WorkorderItemPartRequest specific cmUpdateRequest.AddInParameter("@ID", DbType.Guid, _WorkorderItemPartRequestID); cmUpdateRequest.AddInParameter("@Received", DbType.Decimal, NewReceivedQuantity); //standard parameters cmUpdateRequest.AddInParameter("@CurrentUserID", DbType.Guid, User.CurrentThreadUserID); cmUpdateRequest.AddInParameter("@Modified", DbType.DateTime, DBUtil.ToUTC(DBUtil.CurrentWorkingDateTime)); DBUtil.DB.ExecuteNonQuery(cmUpdateRequest, _tr); #endregion #region Process Notification //Process events as necessary if (AyaBizUtils.GlobalSettings.UseNotification)//Case 510 { //Notify requestor NotifyEvent.AddOrUpdateEvent(RootObjectTypes.WorkorderItemPartRequest, _WorkorderItemPartRequestID, (int)WorkorderItemPartRequestEvent.PartsReceived, RequestorID, new SmartDate(), Guid.Empty); //case 787 //get list of scheduled users on workorder item //and process a notification for each one of them in addition //to the requestor ID dr = DBUtil.GetReaderFromSQLString( "SELECT AUSERID FROM AWORKORDERITEMSCHEDULEDUSER WHERE AWORKORDERITEMID = @ID", WorkorderItemID); System.Collections.ArrayList al = new System.Collections.ArrayList(); Guid g = Guid.Empty; while (dr.Read()) { g = dr.GetGuid("AUSERID"); if (!al.Contains(g) && g != Guid.Empty) al.Add(g); } dr.Close(); foreach (object o in al) { NotifyEvent.AddOrUpdateEvent(RootObjectTypes.WorkorderItemPartRequest, _WorkorderItemPartRequestID, (int)WorkorderItemPartRequestEvent.PartsReceived, (Guid)o, new SmartDate(), Guid.Empty); } } #endregion } } #pragma warning restore 1591 #endregion Inventory receipt Processing }//end WorkorderItemPartRequest #region Notification events #pragma warning disable 1591 public enum WorkorderItemPartRequestEvent : int { [Description("LT:WorkorderItemPartRequest.Label.Event.PartsReceived")] PartsReceived = 1 } #pragma warning restore 1591 #endregion }//end namespace GZTW.AyaNova.BLL