/////////////////////////////////////////////////////////// // PartWarehouseInventoryList.cs // Implementation of Class PartWarehouseInventoryList // CSLA type: Read only collection // Created on: 03-Dec-2004 // Object design: John // Coded: 03-Dec-2004 // Re-Coded: 28-Oct-2005 /////////////////////////////////////////////////////////// using System; using System.Data; using GZTW.Data; using CSLA.Data; using CSLA; using System.ComponentModel; using System.Collections.Generic; namespace GZTW.AyaNova.BLL { #pragma warning disable 1591 /// /// Read only list of objects representing the inventory status of all parts. /// Used for reporting and grid listing. /// [Serializable] public class PartWarehouseInventoryList : ReadOnlyCollectionBase, ITypedList { #region ITypedList //Implementation of ITypedList to allow a grid to display a read only child collection //within a read only collection PropertyDescriptorCollection ITypedList.GetItemProperties(PropertyDescriptor[] listAccessors) { if(listAccessors==null)//then return properties of this (the parent) collection { //This class this code is in is the implementation of the //PartWarehouseInventoryList read only collection business object return TypeDescriptor.GetProperties(typeof(PartWarehouseInventoryListInfo)); } else if(listAccessors.Length==1)//then return the properties of a child object { //Return the properties of the struct inside the //PartWarehouseInventoryList read only collection if(listAccessors[0].Name=="LT_PartSerial_Label_List") return TypeDescriptor.GetProperties(typeof(PartSerialPickList.PartSerialPickListInfo)); //add more here if there are more children or grandchildren } return null; } /// /// Not required for grid but must be implemented /// /// /// string ITypedList.GetListName(PropertyDescriptor[] listAccessors) { return ""; } #endregion #region Data structure /// /// Properties /// [Serializable] public struct PartWarehouseInventoryListInfo { internal Guid mID; internal GridNameValueCellItem mPartWarehouseID; internal GridNameValueCellItem mPartID; internal decimal mQuantityOnHand; internal decimal mQuantityOnOrder; internal decimal mReorderQuantity; internal decimal mMinStockLevel; internal GridNameValueCellItem mPartCategory; internal GridNameValueCellItem mPartAssembly; //case 265 internal bool mPartActive; //Case 177 internal decimal mCost; internal decimal mRetail; [SqlColumnNameAttribute("aPartAssembly.aName", "aPartAssembly.aID"), Display(DisplayType.Button, RootObjectType = RootObjectTypes.PartAssembly)] public GridNameValueCellItem LT_O_PartAssembly {get{return mPartAssembly;}} [SqlColumnNameAttribute("aPartCategory.aName", "aPartCategory.aID"), Display(DisplayType.Button, RootObjectType = RootObjectTypes.PartCategory)] public GridNameValueCellItem LT_O_PartCategory {get{return mPartCategory;}} internal PartSerialPickList mSerials; /// /// Serial numbers in /// [SqlColumnNameAttribute("grid"),Display(DisplayType.Text)] public PartSerialPickList LT_PartSerial_Label_List {get{return mSerials;}} [Display(DisplayType.Hidden)] public Guid ID {get{return mID;}} [SqlColumnNameAttribute("aPartWarehouse.aName", "aPartByWarehouseInventory.aPartWarehouseID"), Display(DisplayType.Button, RootObjectType = RootObjectTypes.PartWarehouse)] public GridNameValueCellItem LT_O_PartWarehouse {get{return mPartWarehouseID;}} [SqlColumnNameAttribute("aPart.aPartNumber", "aPartByWarehouseInventory.aPartID"), Display(DisplayType.Button, RootObjectType = RootObjectTypes.Part)] public GridNameValueCellItem LT_O_Part {get{return mPartID;}} [Display(DisplayType.DecimalNumber)] public decimal LT_PartByWarehouseInventory_Label_QuantityOnHand {get{return mQuantityOnHand;}} [Display(DisplayType.DecimalNumber)] public decimal LT_PartByWarehouseInventory_Label_QuantityOnOrder {get{return mQuantityOnOrder;}} [Display(DisplayType.DecimalNumber)] public decimal LT_PartByWarehouseInventory_Label_MinStockLevel {get{return mMinStockLevel;}} [SqlColumnNameAttribute("AREORDERQUANTITY"),Display(DisplayType.DecimalNumber)] public decimal LT_PartByWarehouseInventory_Label_ReorderQuantity {get{return mReorderQuantity;}} //Case 265 [Display(DisplayType.TrueFalse)] public bool LT_Part_Label_Active { get { return mPartActive; } } //Case 177 [Display(DisplayType.Currency)] public decimal LT_Part_Label_Cost { get { return mCost; } } [Display(DisplayType.Currency)] public decimal LT_Part_Label_Retail { get { return mRetail; } } //Case 58 internal GridNameValueCellItem mRegion; [SqlColumnNameAttribute("aRegion.aName", "aRegion.aID"), Display(DisplayType.Button, RootObjectType = RootObjectTypes.Region)] public GridNameValueCellItem LT_O_Region { get { return mRegion; } } //case 460 internal GridNameValueCellItem mWholeSalerID; [SqlColumnNameAttribute("AVENDWHOLE.ANAME", "AVENDWHOLE.AID"), Display(DisplayType.Button, RootObjectType = RootObjectTypes.Vendor)] public GridNameValueCellItem LT_Part_Label_WholesalerID { get { return mWholeSalerID; } } internal GridNameValueCellItem mAlternativeWholeSalerID; [SqlColumnNameAttribute("AVENDALTWHOLE.ANAME", "AVENDALTWHOLE.AID"), Display(DisplayType.Button, RootObjectType = RootObjectTypes.Vendor)] public GridNameValueCellItem LT_Part_Label_AlternativeWholesalerID { get { return mAlternativeWholeSalerID; } } /// /// /// /// public bool Equals(PartWarehouseInventoryListInfo obj) { return this.mID.Equals(obj.mID); } }//end PartWarehouseInventoryListInfo #endregion #region Constructor protected PartWarehouseInventoryList() { // AllowSort=false; // AllowFind=true; // AllowEdit=false; // AllowNew=false; // AllowRemove=false; } #endregion #region Business properties and methods /// /// Get item by index /// /// public PartWarehouseInventoryListInfo this[int Item] { get { return (PartWarehouseInventoryListInfo) List[Item]; } } /// /// Returns display text that matches passed in itemid value /// /// public string this[Guid ItemID] { get { foreach (PartWarehouseInventoryListInfo child in List) { if(child.mID==ItemID) return child.ToString(); } return "Missing: "+ItemID.ToString(); } } #endregion #region contains /// /// Check if item in collection /// /// public bool Contains(PartWarehouseInventoryListInfo obj) { foreach (PartWarehouseInventoryListInfo child in List) { if(child.Equals(obj)) return true; } return false; } #endregion #region Reporting and shared UI editor helpers /// /// Returns the report key which is a property of /// reports used to link all reports that can be used /// with a particular data source. /// public static string ReportKey { get { return "PartWarehouseInventoryList"; } } /// /// Returns the Detailed report key /// which is used to determine which reports and objects /// will be used for detailed reports /// /// If empty string then indicates there is no detailed report object or reports /// public static string DetailedReportKey { get { return ""; } } /// /// Base object that this list is reporting on /// used by shared UI editor to instantiate new objects /// when user selects new in UI elements that display this list /// /// (I.E. when user clicks on new in a read only list grid, this is the object type created) /// public static RootObjectTypes BaseObjectType { get { return RootObjectTypes.PartByWarehouseInventory; } } /// /// Locale key so that generic list editor /// UI code knows what title to give the list in a /// grid /// public string LocaleKey { get { return "PartByWarehouseInventory.Label.List"; } } /// /// The Type of the struct used to store list records /// Used to fetch the custom display attributes of the fields /// contained within the record to modify the grid display accordingly /// /// public static Type ListRecordType { get { return typeof(PartWarehouseInventoryListInfo); } } /// /// Field that contains the ID of the objects /// that are the basis of this list. /// /// Used for compiling an ID list for reporting from user /// selections in a grid. /// public static string IDField { get { return "ID"; } } /// /// Same as IDField but for detailed reports /// public static string IDFieldDetailed { get { return IDField; } } #endregion #region Static methods /// /// Internal method used by list factory /// internal static PartWarehouseInventoryList Get(string Filter, int MaxRecords, List IDList) { return (PartWarehouseInventoryList)DataPortal.Fetch(new Criteria(Filter, IDList, MaxRecords)); } /// /// Get all PartByWarehouseInventory (filtered by crit) /// /// Use AyaNova UI to easily build xmlCriteria and Ctrl-Alt-g keyboard command to display it for use in your code /// public static PartWarehouseInventoryList GetList(string xmlCriteria) { return (PartWarehouseInventoryList) DataPortal.Fetch(new Criteria(xmlCriteria, null, -1)); } /// /// Takes a single ID and returns a "list" of one object /// /// ID of PartByWarehouseInventory object /// public static PartWarehouseInventoryList GetListForSingleItem(Guid PartByWarehouseInventoryID) { //Case 556 List l = new List(); l.Add(PartByWarehouseInventoryID); return GetListFromIDList(l); } /// /// Get list by items indicated in IDList /// /// Generic list of Guid's /// public static PartWarehouseInventoryList GetListFromIDList(List IDList) { //case 556 //Handle empty list if (IDList.Count == 0) return new PartWarehouseInventoryList(); return (PartWarehouseInventoryList)DataPortal.Fetch(new Criteria("", IDList, -1)); } /// /// Return an empty list /// used for initializing grid /// /// public static PartWarehouseInventoryList GetEmptyList() { return new PartWarehouseInventoryList(); } #endregion #region DAL DATA ACCESS /// /// protected override void DataPortal_Fetch(object Criteria) { Criteria crit = (Criteria)Criteria; SafeDataReader dr = null; try { //Workaround for sorting on the calculated column string sSort=AyaBizUtils.GetGridSortOrderColumns(crit.CriteriaXML); sSort=sSort.Replace("AREORDERQUANTITY","(aPartByWarehouseInventory.aMinStockLevel-(aPartByWarehouseInventory.aQuantityOnHand + aPartByWarehouseInventory.aQuantityOnOrder))"); //This is a funky workaround because AREORDERQUANTITY is based on a calculated value //you can't filter on an alias even though you can sort on one wierd in MS SQL (In firebird you can't // do either. AREORDERQUANTITY //so when it's filtered, it's distinctive name is easy to replace with the filter calculation //whereas when it's sorted it simply uses the alias so we replace here in case of filter" //Also we display zero when a reorderqty is less than zero so there needs to be a //hack to change a filter of =0 (as the user sees it) to <1 string sFilter=AyaBizUtils.GetGridColumnCriteria(crit.CriteriaXML,true); if(sFilter.IndexOf("AREORDERQUANTITY =0") !=-1) sFilter=sFilter.Replace("AREORDERQUANTITY =0","(aPartByWarehouseInventory.aMinStockLevel-(aPartByWarehouseInventory.aQuantityOnHand + aPartByWarehouseInventory.aQuantityOnOrder)) <1"); else if(sFilter.IndexOf("AREORDERQUANTITY <0") !=-1) sFilter=sFilter.Replace("AREORDERQUANTITY <0","(aPartByWarehouseInventory.aMinStockLevel-(aPartByWarehouseInventory.aQuantityOnHand + aPartByWarehouseInventory.aQuantityOnOrder)) <1"); else sFilter=sFilter.Replace("AREORDERQUANTITY","(aPartByWarehouseInventory.aMinStockLevel-(aPartByWarehouseInventory.aQuantityOnHand + aPartByWarehouseInventory.aQuantityOnOrder)) "); string q =//************************************************************ "SELECT ~MAXRECS~ aPart.aPartNumber AS aPARTNUMBER, aPart.aName, aPart.aActive, " +//case 265 added apartactive "aPart.aCost, aPart.aRetail, " + //case 177 " aPartByWarehouseInventory.aPartWarehouseID, " + " aPartWarehouse.aName AS aPartWarehouseName, " + " aPartWarehouse.aRegionID, aRegion.aName AS aRegionName, " + //case 58 " aPartByWarehouseInventory.aQuantityOnHand, " + " aPartByWarehouseInventory.aQtyOnOrderCommitted, " + " aPartByWarehouseInventory.aQuantityOnOrder, " + " aPartByWarehouseInventory.aMinStockLevel, " + "aPartByWarehouseInventory.aID, aPartByWarehouseInventory.aMinStockLevel " + "- (aPartByWarehouseInventory.aQuantityOnHand " + "+ aPartByWarehouseInventory.aQuantityOnOrder) " + "AS AREORDERQUANTITY, " + "aPartByWarehouseInventory.aPartID, aPart.aUPC, " + " AVENDMAN.aName AS aMANUFACTURERNAME, aPartCategory.aName " + "AS aPARTCATEGORYNAME, aPartCategory.aID " + "AS aPartCategoryID, aPartAssembly.aName " + "AS aPARTASSEMBLYNAME, aPartAssembly.aID " + "AS aPartAssemblyID, " + //case 460 "AVENDWHOLE.ANAME AS AVENDWHOLENAME, AVENDWHOLE.AID AS AVENDWHOLEID, " + "AVENDALTWHOLE.ANAME AS AVENDALTWHOLENAME, AVENDALTWHOLE.AID AS AVENDALTWHOLEID " + "FROM " + " APARTBYWAREHOUSEINVENTORY " + " LEFT OUTER JOIN APART ON (APARTBYWAREHOUSEINVENTORY.APARTID=APART.AID) " + //case 460 " LEFT OUTER JOIN AVENDOR AVENDMAN ON (APART.AMANUFACTURERID=AVENDMAN.AID) " + " LEFT OUTER JOIN AVENDOR AVENDWHOLE ON (APART.AWHOLESALERID=AVENDWHOLE.AID) " + " LEFT OUTER JOIN AVENDOR AVENDALTWHOLE ON (APART.AALTERNATIVEWHOLESALERID=AVENDALTWHOLE.AID) " + " LEFT OUTER JOIN APARTWAREHOUSE ON (APARTBYWAREHOUSEINVENTORY.APARTWAREHOUSEID=APARTWAREHOUSE.AID) " + " LEFT OUTER JOIN aRegion ON APARTWAREHOUSE.aRegionID = aRegion.aID " + //Case 58 " LEFT OUTER JOIN APARTCATEGORY ON (APART.APARTCATEGORYID=APARTCATEGORY.AID) " + " LEFT OUTER JOIN APARTASSEMBLY ON (APART.APARTASSEMBLYID=APARTASSEMBLY.AID) "; //************************************************************ if (crit.IDList != null) { //Case 556 System.Text.StringBuilder sbIN = new System.Text.StringBuilder(); sbIN.Append(" WHERE (aPartByWarehouseInventory.aID in ("); foreach (Guid gItem in crit.IDList) { sbIN.Append("'"); sbIN.Append("{"); sbIN.Append(gItem.ToString().ToUpperInvariant()); sbIN.Append("}"); sbIN.Append("',"); } sbIN.Length = sbIN.Length - 1; sbIN.Append(")) "); q = q.Replace("~MAXRECS~", "") + sbIN.ToString() + sSort; } else { //Case 566 if (string.IsNullOrEmpty(sFilter)) sFilter = " WHERE (AQUANTITYONHAND <> 0 OR AQUANTITYONORDER <> 0 OR AMINSTOCKLEVEL <> 0) "; else sFilter += " AND (AQUANTITYONHAND <> 0 OR AQUANTITYONORDER <> 0 OR AMINSTOCKLEVEL <> 0) "; q = q + sFilter + sSort; if (crit.MaxRecords > 0) q = q.Replace("~MAXRECS~", "TOP " + crit.MaxRecords.ToString()); else q = q.Replace("~MAXRECS~", ""); q = DBUtil.AddRegionFilter(q, "aPartWarehouse", "");//case 58 } dr=DBUtil.GetReaderFromSQLString(q); while(dr.Read()) { //******************************************* PartWarehouseInventoryListInfo info=new PartWarehouseInventoryListInfo(); info.mPartWarehouseID=new GridNameValueCellItem( dr.GetGuid("aPartWarehouseID"), dr.GetString("aPartWarehouseName"), RootObjectTypes.PartWarehouse); //Case 58 info.mRegion = new GridNameValueCellItem( dr.GetGuid("aRegionID"), dr.GetString("aRegionName"), RootObjectTypes.Region); info.mPartID=new GridNameValueCellItem( dr.GetGuid("aPartID"), Part.PartDisplayFormatter(dr.GetString("aName"),dr.GetString("aPARTNUMBER"),dr.GetString("aUPC"), dr.GetString("aMANUFACTURERNAME"),dr.GetString("aPARTCATEGORYNAME"),dr.GetString("aPARTASSEMBLYNAME"), AyaBizUtils.GlobalSettings.DefaultPartDisplayFormat), RootObjectTypes.Part); info.mPartCategory=new GridNameValueCellItem( dr.GetGuid("aPartCategoryID"), dr.GetString("aPartCategoryName"), RootObjectTypes.PartCategory); info.mPartAssembly=new GridNameValueCellItem( dr.GetGuid("aPartAssemblyID"), dr.GetString("aPartAssemblyName"), RootObjectTypes.PartAssembly); info.mQuantityOnHand=dr.GetDecimal("aQuantityOnHand"); info.mQuantityOnOrder=dr.GetDecimal("aQuantityOnOrder"); info.mMinStockLevel=dr.GetDecimal("aMinStockLevel"); //TODO: Why is this necessary, if I pull in the value from the query //under firebird it's over by a factor of 10000 //haven't tested with mssql yet //info.mReorderQuantity=dr.GetDecimal("AREORDERQUANTITY"); info.mReorderQuantity=info.mMinStockLevel-(info.mQuantityOnHand+info.mQuantityOnOrder); if(info.mReorderQuantity<0) info.mReorderQuantity=0; info.mID=dr.GetGuid("aID"); info.mSerials =PartSerialPickList.GetList(info.mPartID.Value,info.mPartWarehouseID.Value); //case 265 info.mPartActive = dr.GetBoolean("AACTIVE"); //Case 177 info.mCost = dr.GetDecimal("aCost"); info.mRetail = dr.GetDecimal("aRetail"); //case 460 info.mWholeSalerID = new GridNameValueCellItem( dr.GetGuid("AVENDWHOLEID"), dr.GetString("AVENDWHOLENAME"), RootObjectTypes.Vendor); info.mAlternativeWholeSalerID = new GridNameValueCellItem( dr.GetGuid("AVENDALTWHOLEID"), dr.GetString("AVENDALTWHOLENAME"), RootObjectTypes.Vendor); InnerList.Add(info); //******************************************* } } finally { if(dr!=null) dr.Close(); } } #endregion #region criteria /// /// Criteria for identifying existing object /// [Serializable] private class Criteria { public List IDList; public string CriteriaXML; public int MaxRecords; public Criteria(string _CriteriaXML, List _IDList, int _MaxRecords) { CriteriaXML = _CriteriaXML; IDList = _IDList; MaxRecords = _MaxRecords; } } #endregion }//end PartWarehouseInventoryList #pragma warning restore 1591 }//end namespace GZTW.AyaNova.BLL