/////////////////////////////////////////////////////////// // PurchaseOrder.cs // Implementation of Class PurchaseOrder // CSLA type: Editable Root // Created on: 07-Jun-2004 8:41:31 AM // Object design: Joyce // Coded: John 28-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 { /// /// Purchase order object representing an order for parts /// [Serializable] public class PurchaseOrder : BusinessBase { #region Attributes private bool bReadOnly; private Guid mID; private SmartDate mCreated; private SmartDate mModified; private Guid mCreator; private Guid mModifier; private string mNotes=""; private int mPONumber=0; private string mReferenceNumber=""; private SmartDate mOrderedDate; private SmartDate mExpectedReceiveDate; private string mVendorMemo=""; //private decimal mFreight; //private decimal mAdditionalCharges; private Guid mDropShipToClientID; private Guid mVendorID; private PurchaseOrderItems mOrderItems; //private bool mClosed; private PurchaseOrderStatus mStatus; //Custom fields private string mCustom1=""; private string mCustom2=""; private string mCustom3=""; private string mCustom4=""; private string mCustom5=""; private string mCustom6=""; private string mCustom7=""; private string mCustom8=""; private string mCustom9=""; private string mCustom0=""; //Keep track of status when first created or opened this time around //so that we know when the status has changed from not ordered to ordered //and can therefore update the inventory etc private PurchaseOrderStatus mPreviousStatus; //case 49 private Guid mProjectID; #endregion #region Constructor /// /// Private constructor to prevent direct instantiation /// private PurchaseOrder() { //Set to read / write initially so that properties //can be set bReadOnly=false; //New ID mID = Guid.NewGuid(); mStatus=PurchaseOrderStatus.OpenNotYetOrdered; mPreviousStatus=PurchaseOrderStatus.OpenNotYetOrdered; mOrderItems=PurchaseOrderItems.NewItems(); mOrderedDate = new SmartDate(DBUtil.CurrentWorkingDateTime); mExpectedReceiveDate=new SmartDate(); //mActualReceiveDate=new SmartDate(); //Set record history to defaults mCreated = new SmartDate(DBUtil.CurrentWorkingDateTime); mModified=new SmartDate(); mCreator=Guid.Empty; mModifier=Guid.Empty; //Pre-break the vendorID rule VendorID=Guid.NewGuid(); VendorID=Guid.Empty; } #endregion #region Business properties /// /// Purchase order items child collection /// public PurchaseOrderItems OrderItems { get { return mOrderItems; } } /// /// 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; } } /// /// Notes about PurchaseOrder /// public string Notes { get { return mNotes; } set { if(bReadOnly) ThrowSetError(); else { if(mNotes!=value) { mNotes = value; MarkDirty(); } } } } /// /// Status of purchase order /// Any status change is valid /// with the following exceptions: /// If a P.O. status is currently: /// ClosedFullReceived - can not be changed to anything /// Any status beyond OpenNotYetOrdered can not be /// changed back to OpenNotYetOrdered. I.E. once a P.O. is /// OnOrder of some kind it can not be taken back to OpenNotYetOrdered /// This ensures Purchase orders follow standard business practices for inventory control. /// public PurchaseOrderStatus Status { get { return mStatus; } set { if(bReadOnly || this.mStatus==PurchaseOrderStatus.ClosedFullReceived || (mStatus>PurchaseOrderStatus.OpenNotYetOrdered && value==PurchaseOrderStatus.OpenNotYetOrdered)) ThrowSetError(); else { if(mStatus!=value) { mStatus = value; MarkDirty(); //Lock down the items collection if the p.o. //has progressed beyond opennotyetordered if(mStatus>PurchaseOrderStatus.OpenNotYetOrdered) this.mOrderItems.SetAllItemsReadOnly(); } } } } /// /// Notes that may be displayed or printied on po when sent to vendor /// public string VendorMemo { get { return mVendorMemo; } set { if(bReadOnly || this.mStatus > PurchaseOrderStatus.OpenOrdered) ThrowSetError(); else { if(mVendorMemo!=value) { mVendorMemo = value; MarkDirty(); } } } } /// /// Expected date of receiving /// public object ExpectedReceiveDate { get { return mExpectedReceiveDate.DBValue; } set { if(bReadOnly || this.mStatus > PurchaseOrderStatus.OpenOrdered) ThrowSetError(); else { if (!AyaBizUtils.SmartDateEquals(mExpectedReceiveDate, value)) //Case 298 { mExpectedReceiveDate.DBValue = value; BrokenRules.Assert("ExpectedReceiveDateRequired", "Error.Object.RequiredFieldEmpty,PurchaseOrder.Label.ExpectedReceiveDate", "ExpectedReceiveDate",mExpectedReceiveDate.IsEmpty); MarkDirty(); } } } } /// /// Internal version giving access to smartdate object /// internal SmartDate sdExpectedReceiveDate {get{return mExpectedReceiveDate;}} /// /// Date PO was ordered. Defaults to date created, but may be edited /// public object OrderedDate { get { return mOrderedDate.DBValue; } set { if(bReadOnly || this.mStatus > PurchaseOrderStatus.OpenNotYetOrdered) ThrowSetError(); else { if (!AyaBizUtils.SmartDateEquals(mOrderedDate, value)) //Case 298 { mOrderedDate.DBValue = value; BrokenRules.Assert("OrderedDateRequired", "Error.Object.RequiredFieldEmpty,PurchaseOrder.Label.OrderedDate", "OrderedDate",mOrderedDate.IsEmpty); MarkDirty(); } } } } /// /// Internal version giving access to smartdate object /// internal SmartDate sdOrderedDate {get{return mOrderedDate;}} /// /// Readonly as generated by AyaNova itself /// /// public int PONumber { get { return mPONumber; } } /// /// Additional reference number for the PO to cooinside with PONumber /// public string ReferenceNumber { get { return mReferenceNumber; } set { if(bReadOnly || this.mStatus > PurchaseOrderStatus.OpenOrdered) ThrowSetError(); else { if(mReferenceNumber!=value) { mReferenceNumber = value; MarkDirty(); } } } } /// /// If a drop shipment to a client this is the client /// If Guid.Empty then it's a regular order /// public Guid DropShipToClientID { get { return mDropShipToClientID; } set { if(bReadOnly || this.mStatus > PurchaseOrderStatus.OpenOrdered ) ThrowSetError(); else { if(mDropShipToClientID!=value) { mDropShipToClientID = value; MarkDirty(); } } } } /// /// True if a client was selected to drop ship to /// (read only convenience flag) /// public bool IsDropShip//Case 447 { get { return !mDropShipToClientID.Equals(Guid.Empty); } } /// /// ID of the for this PO /// public Guid VendorID { get { return mVendorID; } set { if(bReadOnly || this.mOrderItems.Count>0) ThrowSetError(); else { if(mVendorID!=value) { mVendorID = value; BrokenRules.Assert("VendorIDRequired", "Error.Object.RequiredFieldEmpty,PurchaseOrder.Label.VendorID", "VendorID",mVendorID==Guid.Empty); MarkDirty(); } } } } #region CUSTOM FIELDS /// /// Custom1 /// public string Custom1 { get { return mCustom1; } set { if(bReadOnly) ThrowSetError(); else { if(mCustom1!=value) { mCustom1 = value; BrokenRules.Assert("Custom1Length", "Error.Object.FieldLengthExceeded500,PurchaseOrder.Label.Custom1","Custom1",value.Length>500); MarkDirty(); } } } } /// /// Custom2 /// public string Custom2 { get { return mCustom2; } set { if(bReadOnly) ThrowSetError(); else { if(mCustom2!=value) { mCustom2 = value; BrokenRules.Assert("Custom2Length", "Error.Object.FieldLengthExceeded500,PurchaseOrder.Label.Custom2","Custom2",value.Length>500); MarkDirty(); } } } } /// /// Custom3 /// public string Custom3 { get { return mCustom3; } set { if(bReadOnly) ThrowSetError(); else { if(mCustom3!=value) { mCustom3 = value; BrokenRules.Assert("Custom3Length", "Error.Object.FieldLengthExceeded500,PurchaseOrder.Label.Custom3","Custom3",value.Length>500); MarkDirty(); } } } } /// /// Custom4 /// public string Custom4 { get { return mCustom4; } set { if(bReadOnly) ThrowSetError(); else { if(mCustom4!=value) { mCustom4 = value; BrokenRules.Assert("Custom4Length", "Error.Object.FieldLengthExceeded500,PurchaseOrder.Label.Custom4","Custom4",value.Length>500); MarkDirty(); } } } } /// /// Custom5 /// public string Custom5 { get { return mCustom5; } set { if(bReadOnly) ThrowSetError(); else { if(mCustom5!=value) { mCustom5 = value; BrokenRules.Assert("Custom5Length", "Error.Object.FieldLengthExceeded500,PurchaseOrder.Label.Custom5","Custom5",value.Length>500); MarkDirty(); } } } } /// /// Custom6 /// public string Custom6 { get { return mCustom6; } set { if(bReadOnly) ThrowSetError(); else { if(mCustom6!=value) { mCustom6 = value; BrokenRules.Assert("Custom6Length", "Error.Object.FieldLengthExceeded500,PurchaseOrder.Label.Custom6","Custom6",value.Length>500); MarkDirty(); } } } } /// /// Custom7 /// public string Custom7 { get { return mCustom7; } set { if(bReadOnly) ThrowSetError(); else { if(mCustom7!=value) { mCustom7 = value; BrokenRules.Assert("Custom7Length", "Error.Object.FieldLengthExceeded500,PurchaseOrder.Label.Custom7","Custom7",value.Length>500); MarkDirty(); } } } } /// /// Custom8 /// public string Custom8 { get { return mCustom8; } set { if(bReadOnly) ThrowSetError(); else { if(mCustom8!=value) { mCustom8 = value; BrokenRules.Assert("Custom8Length", "Error.Object.FieldLengthExceeded500,PurchaseOrder.Label.Custom8","Custom8",value.Length>500); MarkDirty(); } } } } /// /// Custom9 /// public string Custom9 { get { return mCustom9; } set { if(bReadOnly) ThrowSetError(); else { if(mCustom9!=value) { mCustom9 = value; BrokenRules.Assert("Custom9Length", "Error.Object.FieldLengthExceeded500,PurchaseOrder.Label.Custom9","Custom9",value.Length>500); MarkDirty(); } } } } /// /// Custom0 /// public string Custom0 { get { return mCustom0; } set { if(bReadOnly) ThrowSetError(); else { if(mCustom0!=value) { mCustom0 = value; BrokenRules.Assert("Custom0Length", "Error.Object.FieldLengthExceeded500,PurchaseOrder.Label.Custom0","Custom0",value.Length>500); MarkDirty(); } } } } #endregion //case 29 /// /// A List of Guid's of parts selected /// anywhere in this purchase order. /// /// /// public System.Collections.Generic.List ListOfPartsSelected() { System.Collections.Generic.List l = new System.Collections.Generic.List(); foreach (PurchaseOrderItem i in this.OrderItems) { if (!l.Contains(i.PartID)) l.Add(i.PartID); } return l; } //case 49 /// /// Project to attribute to this purchase order /// public Guid ProjectID { get { return mProjectID; } set { if (bReadOnly ) ThrowSetError(); else { if (mProjectID != value) { mProjectID = value; MarkDirty(); } } } } /// /// True if user has edit rights /// public bool HasEditRights//Case 412 { get { return AyaBizUtils.Right("Object.PurchaseOrder") > (int)SecurityLevelTypes.ReadOnly; } } /// /// 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.PurchaseOrder") ) ); } #endregion #region System.object overrides /// /// /// /// public override string ToString() { return "PurchaseOrder" + mID.ToString(); } /// /// /// /// /// public override bool Equals(Object obj) { if ( obj == null || GetType ( ) != obj.GetType ( ) ) return false; PurchaseOrder c=(PurchaseOrder)obj; return mID==c.mID; } /// /// /// /// public override int GetHashCode() { return ("PurchaseOrder"+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) { if(AyaBizUtils.Right("Object.PurchaseOrder")<(int)SecurityLevelTypes.ReadOnly) return new SearchResult(); SearchResult sr=new SearchResult(); System.Text.StringBuilder sb = new System.Text.StringBuilder(); SafeDataReader dr = null; try { dr=DBUtil.GetReaderFromSQLString( "SELECT aPurchaseOrder.aCreated, aPurchaseOrder.aModified, " + "aPurchaseOrder.aCreator, " + " aPurchaseOrder.aModifier, aVendor.aName, " + " aPurchaseOrder.aReferenceNumber, aPurchaseOrder.aNotes, " + " aPurchaseOrder.aCustom1, aPurchaseOrder.aCustom2, " + " aPurchaseOrder.aCustom3, aPurchaseOrder.aCustom4, " + " aPurchaseOrder.aCustom5, " + " aPurchaseOrder.aCustom6, aPurchaseOrder.aCustom7, " + " aPurchaseOrder.aCustom8, aPurchaseOrder.aCustom9, " + " aPurchaseOrder.aCustom0 FROM aPurchaseOrder " + "LEFT OUTER JOIN aVendor ON aPurchaseOrder.aVendorID " + "= aVendor.aID WHERE (aPurchaseOrder.aID " + "= @ID)" ,ID); if(!dr.Read()) return new SearchResult();//DBUtil.ThrowFetchError("SearchResult for PurchaseOrderID: " + ID.ToString()); //slightly re-arranged following 10/3/2014 to include the ref number in the description sb.Append(dr.GetString("aName")); sb.Append(" "); sb.Append(dr.GetString("aReferenceNumber")); sr.Description = sb.ToString(); sb.Append(" "); sb.Append(dr.GetString("aNotes")); sb.Append(" "); sb.Append(dr.GetString("aCustom0")); sb.Append(" "); sb.Append(dr.GetString("aCustom1")); sb.Append(" "); sb.Append(dr.GetString("aCustom2")); sb.Append(" "); sb.Append(dr.GetString("aCustom3")); sb.Append(" "); sb.Append(dr.GetString("aCustom4")); sb.Append(" "); sb.Append(dr.GetString("aCustom5")); sb.Append(" "); sb.Append(dr.GetString("aCustom6")); sb.Append(" "); sb.Append(dr.GetString("aCustom7")); sb.Append(" "); sb.Append(dr.GetString("aCustom8")); sb.Append(" "); sb.Append(dr.GetString("aCustom9")); 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.PurchaseOrder; return sr; } #endregion #region Static methods /// /// Create new PurchaseOrder /// /// PurchaseOrder public static PurchaseOrder NewItem() { PurchaseOrder c; if(AyaBizUtils.Right("Object.PurchaseOrder")>(int)SecurityLevelTypes.ReadOnly) { c = new PurchaseOrder(); return c; } else throw new System.Security.SecurityException( string.Format( LocalizedTextTable.GetLocalizedTextDirect("Error.Security.NotAuthorizedToCreate"), LocalizedTextTable.GetLocalizedTextDirect("O.PurchaseOrder"))); } /// /// Fetch existing PurchaseOrder /// /// PurchaseOrder /// PurchaseOrder Guid public static PurchaseOrder GetItem(Guid _ID) { if (_ID == AyaBizUtils.NewObjectGuid) return NewItem(); if(AyaBizUtils.Right("Object.PurchaseOrder")>(int)SecurityLevelTypes.NoAccess) return (PurchaseOrder)DataPortal.Fetch(new Criteria(_ID)); else throw new System.Security.SecurityException( string.Format( LocalizedTextTable.GetLocalizedTextDirect("Error.Security.NotAuthorizedToRetrieve"), LocalizedTextTable.GetLocalizedTextDirect("O.PurchaseOrder"))); } /// /// Delete PurchaseOrder /// /// PurchaseOrder GUID public static void DeleteItem(Guid _ID) { if(AyaBizUtils.Right("Object.PurchaseOrder")>(int)SecurityLevelTypes.ReadWrite) DataPortal.Delete(new Criteria(_ID)); else throw new System.Security.SecurityException( string.Format( LocalizedTextTable.GetLocalizedTextDirect("Error.Security.NotAuthorizedToDelete"), LocalizedTextTable.GetLocalizedTextDirect("O.PurchaseOrder"))); } /// /// /// /// public static void SetVisibleIDNumber(int newID) { VisibleIDNumber.SetVisibleIDNumber(newID); } #endregion #region DAL DATA ACCESS #region Fetch /// /// protected override void DataPortal_Fetch(object Criteria) { //set to false to load items initially bReadOnly=false; Criteria crit = (Criteria)Criteria; SafeDataReader dr = null; try { dr=DBUtil.GetReaderFromSQLString("SELECT * FROM aPurchaseOrder WHERE aID=@ID;",crit.ID); if(!dr.Read()) DBUtil.ThrowFetchError("PurchaseOrder ID: " + crit.ID.ToString()); //Standard fields mID=dr.GetGuid("aID"); mCreated=DBUtil.ToLocal(dr.GetSmartDate("aCreated")); mModified=DBUtil.ToLocal(dr.GetSmartDate("aModified")); mCreator=dr.GetGuid("aCreator"); mModifier=dr.GetGuid("aModifier"); //Custom fields mCustom1=dr.GetString("aCustom1"); mCustom2=dr.GetString("aCustom2"); mCustom3=dr.GetString("aCustom3"); mCustom4=dr.GetString("aCustom4"); mCustom5=dr.GetString("aCustom5"); mCustom6=dr.GetString("aCustom6"); mCustom7=dr.GetString("aCustom7"); mCustom8=dr.GetString("aCustom8"); mCustom9=dr.GetString("aCustom9"); mCustom0=dr.GetString("aCustom0"); //PurchaseOrder fields mNotes=dr.GetString("aNotes"); mPONumber=dr.GetInt32("aPONumber"); mReferenceNumber=dr.GetString("aReferenceNumber"); mOrderedDate=DBUtil.ToLocal(dr.GetSmartDate("aOrderedDate")); mExpectedReceiveDate=DBUtil.ToLocal(dr.GetSmartDate("aExpectedReceiveDate")); mVendorMemo=dr.GetString("aVendorMemo"); mDropShipToClientID=dr.GetGuid("aDropShipToClientID"); //Unbreak vendorID rule: VendorID=dr.GetGuid("aVendorID"); mProjectID = dr.GetGuid("aProjectID");//case 49 mStatus=(PurchaseOrderStatus)dr.GetInt16("aStatus"); //used when saving to Process inventory changes if applicable status //change mPreviousStatus=mStatus; if(dr!=null) dr.Close(); //Fetch child collection dr=DBUtil.GetReaderFromSQLString( "SELECT aPurchaseOrderItem.*, aPart.aPartNumber, " + " aPart.aManufacturerNumber, aPart.aWholesalerNumber, " + " aPart.AALTERNATIVEWHOLESALERNUMBER, " + " aPart.aCost AS aPARTCOST, aVendor.aName " + "AS aMANUFACTURERNAME, aWorkorderService.aServiceNumber " + "FROM " + "APURCHASEORDERITEM " + " LEFT OUTER JOIN APART ON (APURCHASEORDERITEM.APARTID=APART.AID) " + " LEFT OUTER JOIN AVENDOR ON (APART.AMANUFACTURERID=AVENDOR.AID) " + " LEFT OUTER JOIN AWORKORDERITEMPARTREQUEST ON (AWORKORDERITEMPARTREQUEST.AID=APURCHASEORDERITEM.AWORKORDERITEMPARTREQUESTID) " + " LEFT OUTER JOIN AWORKORDERITEM ON (AWORKORDERITEMPARTREQUEST.AWORKORDERITEMID=AWORKORDERITEM.AID) " + " LEFT OUTER JOIN AWORKORDERSERVICE ON (AWORKORDERITEM.AWORKORDERID=AWORKORDERSERVICE.AWORKORDERID) " + "WHERE (aPurchaseOrderItem.aPurchaseOrderID " + "= @ID)" ,crit.ID); mOrderItems=PurchaseOrderItems.GetItems(dr); if(dr!=null) dr.Close(); } finally { if(dr!=null) dr.Close(); } MarkOld(); //Get access rights level bReadOnly=AyaBizUtils.Right("Object.PurchaseOrder")<(int)SecurityLevelTypes.ReadWrite; //Lock down the children? if(bReadOnly || this.mStatus>PurchaseOrderStatus.OpenNotYetOrdered) mOrderItems.SetAllItemsReadOnly(); } #endregion fetch #region Update /// /// Called by DataPortal to delete/add/update data into the database /// protected override void DataPortal_Update() { // If not a new record, check if record was modified //by another user since original retrieval: if(!IsNew) DBUtil.CheckSafeToUpdate(this.mModified.Date,this.mID,"aPurchaseOrder"); #region Delete (but only if not ordered yet) if(IsDeleted) { if(mStatus>PurchaseOrderStatus.OpenNotYetOrdered) throw new System.ApplicationException ( LocalizedTextTable.GetLocalizedTextDirect("PurchaseOrder.Label.Error.Locked") ); if(!IsNew) { //Delete object and child objects DBCommandWrapper cmDelete = DBUtil.GetCommandFromSQL("DELETE FROM aPurchaseOrder WHERE aID = @ID;"); cmDelete.AddInParameter("@ID",DbType.Guid,this.mID); //Delete all child items DBCommandWrapper cmDeleteItems = DBUtil.GetCommandFromSQL("DELETE FROM aPurchaseOrderItem WHERE aPurchaseOrderID=@ID;"); cmDeleteItems.AddInParameter("@ID",DbType.Guid,this.mID); using (IDbConnection connection = DBUtil.DB.GetConnection()) { connection.Open(); IDbTransaction transaction = connection.BeginTransaction(); try { DBUtil.DB.ExecuteNonQuery(cmDeleteItems, transaction); DBUtil.DB.ExecuteNonQuery(cmDelete, transaction); DBUtil.RemoveKeywords(transaction,RootObjectTypes.PurchaseOrder,this.mID); //case 480 DBUtil.RemoveDocs(transaction, RootObjectTypes.PurchaseOrder, this.mID); // Commit the transaction transaction.Commit(); } catch { // Rollback transaction transaction.Rollback(); throw; } finally { connection.Close(); } } //----------------------------- } MarkNew(); return; } #endregion #region Add / Update (But only partially if already ordered) //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 aPurchaseOrder (aVendorMemo, aDropShipToClientID, " + "aID, aReferenceNumber, aVendorID, aOrderedDate, " + "aExpectedReceiveDate, aStatus, aNotes, aCreated,aModified,aCreator, " + "aModifier, aCustom1, aCustom2, aCustom3, " + "aCustom4, aCustom5, aCustom6, aCustom7, aCustom8, " + "aCustom9, aCustom0, aProjectID) VALUES (@VendorMemo,@DropShipToClientID, " + "@ID,@ReferenceNumber,@VendorID,@OrderedDate, " + "@ExpectedReceiveDate,@Status,@Notes,@Created, @Modified, @CurrentUserID, " + "@CurrentUserID, @Custom1,@Custom2,@Custom3, " + "@Custom4,@Custom5,@Custom6,@Custom7,@Custom8,@Custom9, " + "@Custom0, @ProjectID)"//case 49 ); else cm=DBUtil.GetCommandFromSQL( "UPDATE aPurchaseOrder SET aVendorMemo=@VendorMemo, " + "aDropShipToClientID=@DropShipToClientID, aID=@ID, " + "aReferenceNumber=@ReferenceNumber, aVendorID=@VendorID, " + "aOrderedDate=@OrderedDate, aExpectedReceiveDate=@ExpectedReceiveDate, " + "aStatus=@Status, " + "aNotes=@Notes, aModifier=@CurrentUserID, aModified=@Modified, " + "aCustom1=@Custom1, aCustom2=@Custom2, " + "aCustom3=@Custom3, aCustom4=@Custom4, aCustom5=@Custom5, " + "aCustom6=@Custom6, aCustom7=@Custom7, " + "aCustom8=@Custom8, aCustom9=@Custom9, aCustom0=@Custom0, aProjectID=@ProjectID " +//case 49 "WHERE aID=@ID" ); cm.AddInParameter("@ID",DbType.Guid,mID); cm.AddLargeStringInParameter("@Notes", mNotes); cm.AddInParameter("@ReferenceNumber",DbType.String,mReferenceNumber); cm.AddInParameter("@OrderedDate",DbType.DateTime,DBUtil.ToUTC(mOrderedDate).DBValue); cm.AddInParameter("@ExpectedReceiveDate",DbType.DateTime,DBUtil.ToUTC(mExpectedReceiveDate).DBValue); cm.AddInParameter("@VendorMemo",DbType.String,mVendorMemo); cm.AddInParameter("@DropShipToClientID",DbType.Guid,mDropShipToClientID); cm.AddInParameter("@VendorID",DbType.Guid,mVendorID); cm.AddInParameter("@Status",DbType.Int16,(int)mStatus); cm.AddInParameter("@ProjectID", DbType.Guid, mProjectID);//case 49 //Standard fields cm.AddInParameter("@CurrentUserID",DbType.Guid, CurrentUserID); cm.AddInParameter("@Created",DbType.DateTime, DBUtil.ToUTC(mCreated).DBValue); cm.AddInParameter("@Modified",DbType.DateTime, DBUtil.ToUTC(dtModified)); //Custom fields cm.AddLargeStringInParameter("@Custom1", mCustom1); cm.AddLargeStringInParameter("@Custom2", mCustom2); cm.AddLargeStringInParameter("@Custom3", mCustom3); cm.AddLargeStringInParameter("@Custom4", mCustom4); cm.AddLargeStringInParameter("@Custom5", mCustom5); cm.AddLargeStringInParameter("@Custom6", mCustom6); cm.AddLargeStringInParameter("@Custom7", mCustom7); cm.AddLargeStringInParameter("@Custom8", mCustom8); cm.AddLargeStringInParameter("@Custom9", mCustom9); cm.AddLargeStringInParameter("@Custom0", mCustom0); using (IDbConnection connection = DBUtil.DB.GetConnection()) { connection.Open(); //Affects inventory so a serializable isolation level required for //the transaction IDbTransaction transaction = connection.BeginTransaction(System.Data.IsolationLevel.Serializable); bool bGetIdentity=IsNew; try { DBUtil.DB.ExecuteNonQuery(cm, transaction); //Update items if they are updateable mOrderItems.Update(this, transaction); //Status changed update affected external objects special handling #region Status change from not ordered to ordered Inventory and other object updates if (this.mStatus>PurchaseOrderStatus.OpenNotYetOrdered && mPreviousStatus == PurchaseOrderStatus.OpenNotYetOrdered) { //Update inventory affected items foreach(PurchaseOrderItem poi in mOrderItems) { //get the current inventory values for later updating PartByWarehouseInventoryValuesFetcher invent= PartByWarehouseInventoryValuesFetcher.GetItem( poi.PartID,poi.PartWarehouseID,transaction ); //is it a workorder item part request //initiated po item? if(poi.WorkorderItemPartRequestID!=Guid.Empty) //Yes { #region Update part request DBCommandWrapper cmUpdateRequest =DBUtil.GetCommandFromSQL( "UPDATE aWorkorderItemPartRequest SET aPurchaseOrderItemID=@PurchaseOrderItemID, " + "aModifier=@CurrentUserID, aModified=@Modified WHERE aID=@ID" ); //WorkorderItemPartRequest specific cmUpdateRequest.AddInParameter("@ID",DbType.Guid,poi.WorkorderItemPartRequestID); cmUpdateRequest.AddInParameter("@PurchaseOrderItemID",DbType.Guid,poi.ID); //standard parameters cmUpdateRequest.AddInParameter("@CurrentUserID",DbType.Guid, CurrentUserID); cmUpdateRequest.AddInParameter("@Modified",DbType.DateTime, DBUtil.ToUTC(dtModified)); DBUtil.DB.ExecuteNonQuery(cmUpdateRequest, transaction); #endregion #region Update inventory quantity on order committed (because it's committed to a workorderitempartrequest) //Update... DBCommandWrapper cmUpdateInventoryCommitted = null; cmUpdateInventoryCommitted = DBUtil.GetCommandFromSQL( "UPDATE aPartByWarehouseInventory SET aQtyOnOrderCommitted=@NewQuantity, " + "aModifier=@CurrentUserID, aModified=@Modified " + "WHERE (aPartID = @PartID) AND (aPartWarehouseID " + "= @PartWarehouseID)" ); cmUpdateInventoryCommitted.AddInParameter("@PartID",DbType.Guid,poi.PartID); cmUpdateInventoryCommitted.AddInParameter("@PartWarehouseID",DbType.Guid,poi.PartWarehouseID); cmUpdateInventoryCommitted.AddInParameter("@CurrentUserID",DbType.Guid, CurrentUserID); cmUpdateInventoryCommitted.AddInParameter("@Modified",DbType.DateTime, DBUtil.ToUTC(dtModified)); cmUpdateInventoryCommitted.AddInParameter("@NewQuantity",DbType.Decimal,invent.QtyOnOrderCommitted+poi.QuantityOrdered); DBUtil.DB.ExecuteNonQuery(cmUpdateInventoryCommitted, transaction); #endregion } else {//No, just a regular order for more stock #region Update inventory quantity on order //Update... DBCommandWrapper cmUpdateInventoryOnOrder = null; cmUpdateInventoryOnOrder = DBUtil.GetCommandFromSQL( "UPDATE aPartByWarehouseInventory SET aQuantityOnOrder=@NewQuantity, " + "aModifier=@CurrentUserID, aModified=@Modified " + "WHERE (aPartID = @PartID) AND (aPartWarehouseID " + "= @PartWarehouseID)" ); cmUpdateInventoryOnOrder.AddInParameter("@PartID",DbType.Guid,poi.PartID); cmUpdateInventoryOnOrder.AddInParameter("@PartWarehouseID",DbType.Guid,poi.PartWarehouseID); cmUpdateInventoryOnOrder.AddInParameter("@CurrentUserID",DbType.Guid, CurrentUserID); cmUpdateInventoryOnOrder.AddInParameter("@Modified",DbType.DateTime, DBUtil.ToUTC(dtModified)); cmUpdateInventoryOnOrder.AddInParameter("@NewQuantity",DbType.Decimal,invent.QuantityOnOrder+poi.QuantityOrdered); DBUtil.DB.ExecuteNonQuery(cmUpdateInventoryOnOrder, transaction); #endregion } } } #endregion status change from not ordered to ordered #region case 564 - Status change to closed but not fully received handle incomplete orders System.Collections.Generic.List poItemsToDeleteList = new System.Collections.Generic.List(); //case 3588 more foot-shooting prevention code required if (this.IsNew && this.mStatus > PurchaseOrderStatus.OpenPartialReceived && mPreviousStatus == PurchaseOrderStatus.OpenNotYetOrdered) { //Ok, so the block of code immediately below prior to this case is only running when the po was saved otherwise the //mPreviousStatus is openNotYetOrdered which causes the code block to not execute but we want it to execute //so the solution is to change the mPreviousStatus to OpenOrdered in order to trigger the code block //It won't update the db that way as it's mpreviousstatus doesn't get saved anwyhere it's only for control through this DataPortal_update anyway mPreviousStatus = PurchaseOrderStatus.OpenOrdered; } //case 3738 if user doesn't reload this object previousstatus is out of whack and following block won't run so set on successful commit below //case 564 if (this.mStatus > PurchaseOrderStatus.OpenPartialReceived && mPreviousStatus > PurchaseOrderStatus.OpenNotYetOrdered && mPreviousStatus < PurchaseOrderStatus.ClosedPartialReceived) //i.e. was on order b4 and not closed in any way and now closed in some way { //case 3739 bool bOrderItemsNeedToBeSavedAgain = false; //normally items are read only at this point because of status so need to change //temporarily bool bOrderItemsWasReadOnly = mOrderItems.IsLocked; if(bOrderItemsWasReadOnly) mOrderItems.SetAllItemsWrite(); //Update inventory affected items foreach (PurchaseOrderItem poi in mOrderItems) { //is this poitem incomplete? if (poi.QuantityOrdered > 0 && poi.QuantityReceived < poi.QuantityOrdered) { //case 1918 poi.OverrideIsLockedForInternalUpdate = true; //get the current inventory values for later updating PartByWarehouseInventoryValuesFetcher invent = PartByWarehouseInventoryValuesFetcher.GetItem( poi.PartID, poi.PartWarehouseID, transaction ); //was nothing at all received? if (poi.QuantityReceived == 0) { #region Nothing received at all //If it's a woitempartrequest make it like it was never ordered at all if (poi.WorkorderItemPartRequestID != Guid.Empty) //Yes { #region Update part request //nope to make it like it never happened DBCommandWrapper cmUpdateRequest = DBUtil.GetCommandFromSQL( "UPDATE aWorkorderItemPartRequest SET aPurchaseOrderItemID=@PurchaseOrderItemID, " + "aModifier=@CurrentUserID, aModified=@Modified WHERE aID=@ID" ); //WorkorderItemPartRequest specific cmUpdateRequest.AddInParameter("@ID", DbType.Guid, poi.WorkorderItemPartRequestID); cmUpdateRequest.AddInParameter("@PurchaseOrderItemID", DbType.Guid, Guid.Empty);//set to no po so it's not on order any more //standard parameters cmUpdateRequest.AddInParameter("@CurrentUserID", DbType.Guid, CurrentUserID); cmUpdateRequest.AddInParameter("@Modified", DbType.DateTime, DBUtil.ToUTC(dtModified)); DBUtil.DB.ExecuteNonQuery(cmUpdateRequest, transaction); #endregion } //case 1828 moved out of if block above as it would only work if it was a request #region Remove empty poreceiptitem //so that we can delete this poitem //without invoking a sql index error because poreceiptitem references this //poitem DBCommandWrapper cmUpdatePORI = DBUtil.GetCommandFromSQL( "DELETE FROM APURCHASEORDERRECEIPTITEM WHERE APURCHASEORDERITEMID=@ID" ); cmUpdatePORI.AddInParameter("@ID", DbType.Guid, poi.ID); DBUtil.DB.ExecuteNonQuery(cmUpdatePORI, transaction); #endregion #region Update inventory quantity on order committed and qty on order //Update... DBCommandWrapper cmUpdateInventoryCommitted = null; cmUpdateInventoryCommitted = DBUtil.GetCommandFromSQL( "UPDATE aPartByWarehouseInventory SET aQtyOnOrderCommitted=@CMTQuantity, " + "aQuantityOnOrder=@OOQuantity, aModifier=@CurrentUserID, aModified=@Modified " + "WHERE (aPartID = @PartID) AND (aPartWarehouseID " + "= @PartWarehouseID)" ); cmUpdateInventoryCommitted.AddInParameter("@PartID", DbType.Guid, poi.PartID); cmUpdateInventoryCommitted.AddInParameter("@PartWarehouseID", DbType.Guid, poi.PartWarehouseID); cmUpdateInventoryCommitted.AddInParameter("@CurrentUserID", DbType.Guid, CurrentUserID); cmUpdateInventoryCommitted.AddInParameter("@Modified", DbType.DateTime, DBUtil.ToUTC(dtModified)); cmUpdateInventoryCommitted.AddInParameter("@CMTQuantity", DbType.Decimal, invent.QtyOnOrderCommitted - poi.QuantityOrdered); cmUpdateInventoryCommitted.AddInParameter("@OOQuantity", DbType.Decimal, invent.QuantityOnOrder - poi.QuantityOrdered); DBUtil.DB.ExecuteNonQuery(cmUpdateInventoryCommitted, transaction); #endregion //Add the id of the poitem to the list of items to delete in update later //can't call remove directly because //we're in the midst of iterating through the collection poItemsToDeleteList.Add(poi.ID); poi.WorkorderItemPartRequestID = Guid.Empty; #endregion } else if (poi.QuantityReceived > 0) {// was partially received #region Partially received decimal dBalanceUnreceived = poi.QuantityOrdered - poi.QuantityReceived; //change qty ordered to received poi.QuantityOrdered = poi.QuantityReceived; //case 3739 bOrderItemsNeedToBeSavedAgain = true; #region Update inventory quantity on order //Update... DBCommandWrapper cmUpdateInventoryCommitted = null; cmUpdateInventoryCommitted = DBUtil.GetCommandFromSQL( "UPDATE aPartByWarehouseInventory SET " + "aQuantityOnOrder=@OOQuantity, aModifier=@CurrentUserID, aModified=@Modified " + "WHERE (aPartID = @PartID) AND (aPartWarehouseID " + "= @PartWarehouseID)" ); cmUpdateInventoryCommitted.AddInParameter("@PartID", DbType.Guid, poi.PartID); cmUpdateInventoryCommitted.AddInParameter("@PartWarehouseID", DbType.Guid, poi.PartWarehouseID); cmUpdateInventoryCommitted.AddInParameter("@CurrentUserID", DbType.Guid, CurrentUserID); cmUpdateInventoryCommitted.AddInParameter("@Modified", DbType.DateTime, DBUtil.ToUTC(dtModified)); cmUpdateInventoryCommitted.AddInParameter("@OOQuantity", DbType.Decimal, invent.QuantityOnOrder - dBalanceUnreceived); DBUtil.DB.ExecuteNonQuery(cmUpdateInventoryCommitted, transaction); #endregion //Partially received so update workorder item part request record //so that the On order quantity matches the received quantity //so that the workorder can be closed etc. //case 1920 if (poi.WorkorderItemPartRequestID != Guid.Empty) //Yes { #region Update part request //Set quantity to the actual recieved amount DBCommandWrapper cmUpdateRequest = DBUtil.GetCommandFromSQL( "UPDATE AWORKORDERITEMPARTREQUEST SET AQUANTITY=ARECEIVED, " + "AMODIFIER=@CURRENTUSERID, AMODIFIED=@MODIFIED WHERE AID=@ID" ); //WorkorderItemPartRequest specific cmUpdateRequest.AddInParameter("@ID", DbType.Guid, poi.WorkorderItemPartRequestID); //standard parameters cmUpdateRequest.AddInParameter("@CurrentUserID", DbType.Guid, CurrentUserID); cmUpdateRequest.AddInParameter("@Modified", DbType.DateTime, DBUtil.ToUTC(dtModified)); DBUtil.DB.ExecuteNonQuery(cmUpdateRequest, transaction); #endregion } #endregion } //case 1918 poi.OverrideIsLockedForInternalUpdate = false; } }//foreach poitem //remove any poitems in delete list if (poItemsToDeleteList.Count > 0) { foreach (Guid g in poItemsToDeleteList) mOrderItems.Remove(g); //save these changes //case 3739 only save once below //mOrderItems.Update(this, transaction); bOrderItemsNeedToBeSavedAgain = true; } //case 3739 if (bOrderItemsNeedToBeSavedAgain) { mOrderItems.Update(this, transaction); } if (bOrderItemsWasReadOnly) mOrderItems.SetAllItemsReadOnly(); }//case 564 changed to closed not all received #endregion status change to closed but not fully received handle incomplete orders //Process keywords DBUtil.ProcessKeywords(transaction,this.mID,RootObjectTypes.PurchaseOrder,IsNew,AyaBizUtils.Break(false, mNotes,mReferenceNumber,mVendorMemo, /*Custom fields*/ mCustom1,mCustom2,mCustom3,mCustom4,mCustom5,mCustom6,mCustom7,mCustom8,mCustom9,mCustom0)); MarkOld();//db is now synched with object // Commit the transaction transaction.Commit(); //case 3738 it has just been saved successfully so we need to now upate previous status to reflect in db value mPreviousStatus = mStatus; } catch { // Rollback transaction transaction.Rollback(); throw; } finally { connection.Close(); } //Get new DB generated identity value if(bGetIdentity) this.mPONumber=DBUtil.GetIdentity("aPONumber","aPurchaseOrder",this.mID,null); //Successful update so //change modification time to match this.mModified.Date=dtModified; } #endregion } #endregion update #region Delete /// /// Remove a PurchaseOrder record . /// /// protected override void DataPortal_Delete(object Criteria) { Criteria crit = (Criteria)Criteria; //get the status and see if it's deleteable object o=DBUtil.GetScalarFromSQLString( "SELECT aStatus FROM aPurchaseOrder WHERE (aID = @ID)",crit.ID ); if(o==null || o==System.DBNull.Value) return; int nValue=System.Convert.ToInt32(o); if(nValue > (int)PurchaseOrderStatus.OpenNotYetOrdered) throw new System.ApplicationException ( LocalizedTextTable.GetLocalizedTextDirect("PurchaseOrder.Label.Error.Locked") ); //Delete object and child objects DBCommandWrapper cmDelete = DBUtil.GetCommandFromSQL("DELETE FROM aPurchaseOrder WHERE aID = @ID;"); cmDelete.AddInParameter("@ID",DbType.Guid,crit.ID); //Delete all child items DBCommandWrapper cmDeleteItems = DBUtil.GetCommandFromSQL("DELETE FROM aPurchaseOrderItem WHERE aPurchaseOrderID=@ID;"); cmDeleteItems.AddInParameter("@ID",DbType.Guid,crit.ID); using (IDbConnection connection = DBUtil.DB.GetConnection()) { connection.Open(); IDbTransaction transaction = connection.BeginTransaction(); try { DBUtil.DB.ExecuteNonQuery(cmDeleteItems, transaction); DBUtil.DB.ExecuteNonQuery(cmDelete, transaction); DBUtil.RemoveKeywords(transaction,RootObjectTypes.PurchaseOrder,crit.ID); DBUtil.RemoveDocs(transaction, RootObjectTypes.PurchaseOrder, crit.ID); // Commit the transaction transaction.Commit(); } catch { // Rollback transaction transaction.Rollback(); throw; } finally { connection.Close(); } } } #endregion delete #endregion #region Override IsValid / IsDirty //Override base class version if there are child objects /// /// /// public override bool IsValid { get { return base.IsValid && mOrderItems.IsValid ; } } /// /// /// public override bool IsDirty { get { return base.IsDirty || mOrderItems.IsDirty ; } } #endregion #region criteria /// /// Criteria for identifying existing object /// [Serializable] private class Criteria { public Guid ID; public Criteria(Guid _ID) { ID=_ID; } } #endregion #region Set VisibleIDNumber /// /// Set the DB generated visible ID number /// to a new user chosen starting point /// [Serializable(), System.ComponentModel.Browsable(false)] public class VisibleIDNumber//DO_NOT_OBFUSCATE { int _newStartID = -1; /// /// /// /// public VisibleIDNumber(int newStartID) { _newStartID = newStartID; } /// /// /// /// public static void SetVisibleIDNumber(int newStartID) { DataPortal.Update(new VisibleIDNumber(newStartID)); } /// /// /// public void DataPortal_Update() { //Find the highest existing number object o=DBUtil.GetScalarFromSQLString( "SELECT MAX(aPONumber) FROM aPurchaseOrder" ); if(o==null || o==System.DBNull.Value) o=0; int nHighestExisting=(int)o; //ensure new number is larger than highest existing one if(_newStartID