/////////////////////////////////////////////////////////// // PurchaseOrderReceipt.cs // Implementation of Class PurchaseOrderReceipt // CSLA type: Editable Root // Created on: 17-Nov-2004 // Object design: Joyce & John // Coded: John 17-Nov-2004 /////////////////////////////////////////////////////////// using System; using System.Data; using CSLA.Data; using GZTW.Data; using CSLA; using System.Threading; using CSLA.Security; using System.Collections; using System.Collections.Generic; namespace GZTW.AyaNova.BLL { /// /// This is a write once only object. /// Once saved initially it can never be edited again /// as it affects many other objects and must follow standard business practices for inventory control. /// Corrections must be made through an inventory adjustment as per standard practices. /// [Serializable] public class PurchaseOrderReceipt : BusinessBase { #region Attributes private bool bReadOnly; private Guid mID; private SmartDate mCreated; private SmartDate mModified; private Guid mCreator; private Guid mModifier; private SmartDate mReceivedDate; private Guid mVendorID; private PurchaseOrderReceiptItems mItems; private string mText1 = ""; private string mText2 = ""; #endregion #region Constructor /// /// Private constructor to prevent direct instantiation /// private PurchaseOrderReceipt() { //Set to read / write initially so that properties //can be set bReadOnly=false; //New ID mID = Guid.NewGuid(); mItems=PurchaseOrderReceiptItems.NewItems(); mReceivedDate = new SmartDate(DBUtil.CurrentWorkingDateTime); //Set record history to defaults mCreated = new SmartDate(DBUtil.CurrentWorkingDateTime); mModified=new SmartDate(); mCreator=Guid.Empty; mModifier=Guid.Empty; } #endregion #region Business properties /// /// Purchase order items child collection /// public PurchaseOrderReceiptItems Items { get { return mItems; } } /// /// 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; } } /// /// Date items received /// public object ReceivedDate { get { return mReceivedDate.DBValue; } set { if(bReadOnly) ThrowSetError(); else { if (!AyaBizUtils.SmartDateEquals(mReceivedDate, value)) //Case 298 { mReceivedDate.DBValue = value; BrokenRules.Assert("ReceivedDateRequired", "Error.Object.RequiredFieldEmpty,PurchaseOrderReceipt.Label.ReceivedDate", "ReceivedDate",mReceivedDate.IsEmpty); MarkDirty(); } } } } /// /// /// public Guid VendorID { get { return mVendorID; } set { if(bReadOnly) ThrowSetError(); else { if(mVendorID!=value) { mVendorID = value; MarkDirty(); } } } } /// /// Copy all line items from po indicated into /// items collection of this receiving /// /// public void AddContentsOfPurchaseOrder(Guid PurchaseOrderID) { if(PurchaseOrderID==Guid.Empty) return; PurchaseOrder p = PurchaseOrder.GetItem(PurchaseOrderID); if(p.OrderItems.Count<1) return; if(p.Status!=PurchaseOrderStatus.OpenOrdered && p.Status!=PurchaseOrderStatus.OpenPartialReceived) { return; } foreach(PurchaseOrderItem poi in p.OrderItems) { //Only add items that are not already there //and not already fully received and not for some obscure //reason ordered as quantity zero and not closed already //just a safety, probably won't matter in practice but //who knows what yahoo will be using this function if(!Items.ContainsPurchaseOrderItem(poi.ID) && !(poi.QuantityOrdered==0) && !(poi.Closed) && !(poi.QuantityOrdered==poi.QuantityReceived)) { PurchaseOrderReceiptItem i =Items.Add(this); i.PurchaseOrderID=p.ID; i.PartID=poi.PartID; i.PurchaseOrderItemID=poi.ID; i.QuantityReceived=poi.QuantityOrdered-poi.QuantityReceived; i.ReceiptCost=poi.PurchaseOrderCost; //i.mQuantityOrdered=poi.QuantityOrdered; //i.mPurchaseOrderCost=poi.PurchaseOrderCost; //i.mWorkorderNumber=poi.WorkorderNumber; i.PartWarehouseID=poi.PartWarehouseID; //i.mPOReferenceNumber=p.ReferenceNumber; //i.mPurchaseTaxCodeID=poi.PurchaseTaxCodeID; //i.mWorkorderItemPartRequestID=poi.WorkorderItemPartRequestID; //i.mPartRequestedByID=poi.PartRequestedByID; //i.mOrderedDate=p.sdOrderedDate; //i.mExpectedReceiveDate=p.sdExpectedReceiveDate; } } } //Case 640 /// /// A List of Guid's of Part Warehouses selected /// anywhere in this work order. /// /// /// public System.Collections.Generic.List ListOfPartWarehousesSelected() { System.Collections.Generic.List l = new System.Collections.Generic.List(); foreach (PurchaseOrderReceiptItem p in this.Items) { if (!l.Contains(p.PartWarehouseID)) l.Add(p.PartWarehouseID); } return l; } /// /// Optional first text field /// public string Text1 { get { return mText1; } set { if (bReadOnly) ThrowSetError(); else { if (mText1 != value) { mText1 = value; BrokenRules.Assert("Text1Length", "Error.Object.FieldLengthExceeded255,PurchaseOrderReceipt.Label.Text1", "Text1", value.Length > 255); MarkDirty(); } } } } /// /// Optional second text field /// public string Text2 { get { return mText2; } set { if (bReadOnly) ThrowSetError(); else { if (mText2 != value) { mText2 = value; BrokenRules.Assert("Text2Length", "Error.Object.FieldLengthExceeded255,PurchaseOrderReceipt.Label.Text2", "Text2", value.Length > 255); MarkDirty(); } } } } /// /// 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.PurchaseOrderReceipt") ) ); } #endregion #region System.object overrides /// /// /// /// public override string ToString() { return "PurchaseOrderReceipt" + mID.ToString(); } /// /// /// /// /// public override bool Equals(Object obj) { if ( obj == null || GetType ( ) != obj.GetType ( ) ) return false; PurchaseOrderReceipt c=(PurchaseOrderReceipt)obj; return mID==c.mID; } /// /// /// /// public override int GetHashCode() { return ("PurchaseOrderReceipt"+mID).GetHashCode(); } #endregion #region Static methods /// /// Create new PurchaseOrderReceipt /// /// PurchaseOrderReceipt public static PurchaseOrderReceipt NewItem() { PurchaseOrderReceipt c; if(AyaBizUtils.Right("Object.PurchaseOrder")>(int)SecurityLevelTypes.ReadOnly) { c = new PurchaseOrderReceipt(); return c; } else throw new System.Security.SecurityException( string.Format( LocalizedTextTable.GetLocalizedTextDirect("Error.Security.NotAuthorizedToCreate"), LocalizedTextTable.GetLocalizedTextDirect("O.PurchaseOrderReceipt"))); } /// /// Fetch existing PurchaseOrderReceipt /// /// PurchaseOrderReceipt /// PurchaseOrderReceipt Guid public static PurchaseOrderReceipt GetItem(Guid _ID) { if(AyaBizUtils.Right("Object.PurchaseOrder")>(int)SecurityLevelTypes.NoAccess) return (PurchaseOrderReceipt)DataPortal.Fetch(new Criteria(_ID)); else throw new System.Security.SecurityException( string.Format( LocalizedTextTable.GetLocalizedTextDirect("Error.Security.NotAuthorizedToRetrieve"), LocalizedTextTable.GetLocalizedTextDirect("O.PurchaseOrderReceipt"))); } #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 aPurchaseOrderReceipt WHERE aID=@ID;",crit.ID); if(!dr.Read()) DBUtil.ThrowFetchError("PurchaseOrderReceipt 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"); //PurchaseOrderReceipt fields mReceivedDate=DBUtil.ToLocal(dr.GetSmartDate("aReceivedDate")); mVendorID=dr.GetGuid("aVendorID"); mText1 = dr.GetString("aText1"); mText2 = dr.GetString("aText2"); if(dr!=null) dr.Close(); //Fetch child collection dr=DBUtil.GetReaderFromSQLString( "SELECT * FROM aPurchaseOrderReceiptItem " + "WHERE (aPurchaseOrderReceiptItem.aPurchaseOrderReceiptID " + "= @ID)" ,crit.ID); mItems=PurchaseOrderReceiptItems.GetItems(dr); if(dr!=null) dr.Close(); } finally { if(dr!=null) dr.Close(); } MarkOld(); //as this is a write once object it's always read only //when fetched from DB bReadOnly=true; } #endregion fetch #region Update /// /// Called by DataPortal to add data into the database /// protected override void DataPortal_Update() { //unchangeable add only: if(!IsNew) throw new System.ApplicationException ( string.Format ( LocalizedTextTable.GetLocalizedTextDirect("Error.Object.NotChangeable"), LocalizedTextTable.GetLocalizedTextDirect("O.PurchaseOrderReceipt") ) ); if(IsDeleted) throw new System.ApplicationException ( string.Format ( LocalizedTextTable.GetLocalizedTextDirect("Error.Object.NotDeleteable"), LocalizedTextTable.GetLocalizedTextDirect("O.PurchaseOrderReceipt") ) ); #region Add //get modification time temporarily, if update succeeds then //set to this time System.DateTime dtModified = DBUtil.CurrentWorkingDateTime; //Since this is an add-only object there is only the insert to deal with DBCommandWrapper cm = DBUtil.GetCommandFromSQL( "INSERT INTO aPurchaseOrderReceipt (aID, aVendorID, aReceivedDate, " + "aCreated,aModified,aCreator,aModifier,aText1, aText2) VALUES (@ID,@VendorID, " + "@ReceivedDate,@Created,@Modified,@CurrentUserID,@CurrentUserID,@Text1,@Text2)" ); cm.AddInParameter("@ID",DbType.Guid,mID); cm.AddInParameter("@ReceivedDate",DbType.DateTime,DBUtil.ToUTC(mReceivedDate).DBValue); cm.AddInParameter("@VendorID",DbType.Guid,mVendorID); //case 78 cm.AddInParameter("@Text1", DbType.String, mText1); cm.AddInParameter("@Text2", DbType.String, mText2); //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)); using (IDbConnection connection = DBUtil.DB.GetConnection()) { connection.Open(); //Use a serializeable isolation level as this affects inventory //and must have full integrity throughout the transaction IDbTransaction transaction = connection.BeginTransaction(System.Data.IsolationLevel.Serializable); try { DBUtil.DB.ExecuteNonQuery(cm, transaction); //Update child collection mItems.Update(this,transaction); #region Update other objects affected foreach(PurchaseOrderReceiptItem i in mItems) { //poreceiptitem has a rule to disallow negative or //zero received amounts, but let's be on the safe side anyway //in case someone fucked with the database itself //Case 823: this is a bug because users can receive less than one //if(i.QuantityReceived<1) continue; if (i.QuantityReceived < 0 || i.QuantityReceived==0) continue; //get the current inventory values for later updating PartByWarehouseInventoryValuesFetcher invent= PartByWarehouseInventoryValuesFetcher.GetItem( i.PartID,i.PartWarehouseID,transaction ); Guid PartRequestID=Guid.Empty; decimal POItemQuantityReceived=0; decimal POItemQuantityOrdered=0; #region Update the corresponding purchase order item //Get the current received balance SafeDataReader dr = DBUtil.GetReaderFromSQLString( "SELECT aQuantityReceived, aQuantityOrdered, aWorkorderItemPartRequestID " + "FROM aPurchaseOrderItem WHERE aID=@ID", i.PurchaseOrderItemID,transaction ); if(!dr.Read()) DBUtil.ThrowFetchError("PurchaseOrderReceipt.Update fetching received balance for po ID: " + i.PurchaseOrderItemID.ToString()); POItemQuantityReceived=dr.GetDecimal("aQuantityReceived"); POItemQuantityOrdered=dr.GetDecimal("aQuantityOrdered"); PartRequestID=dr.GetGuid("aWorkorderItemPartRequestID"); //case 1086 i.mPartRequestID = PartRequestID; dr.Close(); //Update the Purchase order item current received balance POItemQuantityReceived+=i.QuantityReceived; DBCommandWrapper cmUpdatePOItem=DBUtil.GetCommandFromSQL( "UPDATE aPurchaseOrderItem SET " + "aQuantityReceived=@QuantityReceived, aClosed=@Closed, " + "aModifier=@CurrentUserID, aModified=@Modified " + "WHERE aID=@ID" ); cmUpdatePOItem.AddInParameter("@ID",DbType.Guid,i.PurchaseOrderItemID); cmUpdatePOItem.AddInParameter("@QuantityReceived",DbType.Decimal,POItemQuantityReceived); cmUpdatePOItem.AddInParameter("@Closed",DbType.Boolean,POItemQuantityReceived==POItemQuantityOrdered); cmUpdatePOItem.AddInParameter("@CurrentUserID",DbType.Guid, CurrentUserID); cmUpdatePOItem.AddInParameter("@Modified",DbType.DateTime, DBUtil.ToUTC(dtModified)); DBUtil.DB.ExecuteNonQuery(cmUpdatePOItem, transaction); #endregion #region Update the Partbywarehouseinventory //Update... DBCommandWrapper cmUpdateInventory = null; //is it a workorder item part request //initiated po item? if(PartRequestID!=Guid.Empty) //Yes { cmUpdateInventory = DBUtil.GetCommandFromSQL( "UPDATE aPartByWarehouseInventory SET " + "aQtyOnOrderCommitted=@NewQtyOnOrderCommitted, " + "aQuantityOnHand=@NewOnHandQuantity, " + "aModifier=@CurrentUserID, aModified=@Modified " + "WHERE (aPartID = @PartID) AND (aPartWarehouseID " + "= @PartWarehouseID)" ); cmUpdateInventory.AddInParameter("@NewQtyOnOrderCommitted",DbType.Decimal,invent.QtyOnOrderCommitted-i.QuantityReceived); } else { cmUpdateInventory = DBUtil.GetCommandFromSQL( "UPDATE aPartByWarehouseInventory SET aQuantityOnOrder=@NewOnOrderQuantity, " + "aQuantityOnHand=@NewOnHandQuantity, " + "aModifier=@CurrentUserID, aModified=@Modified " + "WHERE (aPartID = @PartID) AND (aPartWarehouseID " + "= @PartWarehouseID)" ); cmUpdateInventory.AddInParameter("@NewOnOrderQuantity",DbType.Decimal,invent.QuantityOnOrder-i.QuantityReceived); } cmUpdateInventory.AddInParameter("@PartID",DbType.Guid,i.PartID); cmUpdateInventory.AddInParameter("@PartWarehouseID",DbType.Guid,i.PartWarehouseID); cmUpdateInventory.AddInParameter("@CurrentUserID",DbType.Guid, CurrentUserID); cmUpdateInventory.AddInParameter("@Modified",DbType.DateTime, DBUtil.ToUTC(dtModified)); cmUpdateInventory.AddInParameter("@NewOnHandQuantity",DbType.Decimal,invent.QuantityOnHand+i.QuantityReceived); DBUtil.DB.ExecuteNonQuery(cmUpdateInventory, transaction); #endregion #region Update the WorkorderItemPartRequest if applicable if(PartRequestID!=Guid.Empty) //Yes { WorkorderItemPartRequest.ProcessPartsReceived(PartRequestID,i.QuantityReceived,transaction); } #endregion } #endregion #region Update purchase order status ArrayList al=Items.UniquePurchaseOrderGuids; for(int x=0;x /// True if no broken business rules /// public override bool IsValid { get { return base.IsValid && mItems.IsValid && mItems.GrandChildIsValid() ; } } /// /// True if there are pending edits unsaved /// public override bool IsDirty { get { return base.IsDirty || mItems.IsDirty || mItems.GrandChildIsDirty() ; } } #endregion #region criteria /// /// Criteria for identifying existing object /// [Serializable] private class Criteria { public Guid ID; public Criteria(Guid _ID) { ID=_ID; } } #endregion }//end PurchaseOrderReceipt }//end namespace GZTW.AyaNova.BLL