using Sarand.BusinessMgr.Net.Standard.Base.App; using Sarand.BusinessMgr.Net.Standard.Base.Bus; using Sarand.BusinessMgr.Net.Standard.Base.Consoles; using Sarand.BusinessMgr.Net.Standard.Base.Core; using Sarand.Net.Standard.Base.Bus; using Sarand.Net.Standard.Base.CodeTypes; using Sarand.Net.Standard.Base.Core; using Sarand.Net.Standard.Base.Dbas; using Sarand.Net.Standard.Base.Diary; using Sarand.Net.Standard.Base.Interfaces; using Sarand.Net.Standard.Base.ItemData; using Sarand.Net.Standard.Base.ItemDocs; using Sarand.Net.Standard.Base.ItemOptions; using Sarand.Net.Standard.Base.ReferenceData; using Sarand.Net.Standard.Base.Security; using Sarand.Net.Standard.Base.UpdateLog; using Sarand.Net.Standard.Base.Utils; using System; using System.Collections.Generic; using System.Linq; namespace Sarand.BusinessMgr.Net.Standard.Base.Mgr { //======================================================================= public abstract class SbmCoreMgr : SbmItemMgr { //------------------------------------------------------------------- // Code type cache. public class CodeTypeCache { /// /// Cached codes by code type. /// NB Likely to only contain a subset of code types depending on context. /// private Dictionary> codesByCodeType { get; } // Construction. public CodeTypeCache(Dictionary> codes) { codesByCodeType = codes; } /// Are there any codes of the specified type. public bool CodeTypeHasCodes(Sbm.ApplCodeType codeType) { String codeTypeCode = SbmSystem.GetCodeTypeCode(codeType); return codesByCodeType.ContainsKey(codeTypeCode) ? codesByCodeType[codeTypeCode].Count > 0 : false; } /// Get the description for the code belonging to the specified code type. public String GetDescForCodeTypeCode(Sbm.ApplCodeType codeType, String code, bool defaultToCode = true) { List codes = GetCodesForCodeType(codeType, false); return codes?.GetDescForCode(code, defaultToCode ? code : "") ?? ""; } /// Retrieve codes for specified code type. public List GetCodesForCodeType(Sbm.ApplCodeType codeType, bool activeOnly = true) { String codeTypeCode = SbmSystem.GetCodeTypeCode(codeType); return codesByCodeType.ContainsKey(codeTypeCode) ? new List(codesByCodeType[codeTypeCode].FindAll(code => !activeOnly || code.Status == SaCode.ActiveStatus)) : null; } /// Retrieve code descs for specified code type. public List GetCodeDescsForCodeType(Sbm.ApplCodeType codeType, bool activeOnly = true) { String codeTypeCode = SbmSystem.GetCodeTypeCode(codeType); return codesByCodeType.ContainsKey(codeTypeCode) ? new List(codesByCodeType[codeTypeCode].FindAll(code => !activeOnly || code.Status == SaCode.ActiveStatus).Select(code => new CodeDesc(code.Code, code.Description))) : null; } } //------------------------------------------------------------------- // Data members. private class DataMembers { // Externally supplied Internals - disposed elsewhere. public SbmInternals internalsSupplied; // Internally constructed Internals - disposed here. public SbmInternals internals; // Numeric control values. public bool numericControlValuesInitialised { get; set; } public int weightDecimals { get; set; } public int lengthDecimals { get; set; } public int volumeDecimals { get; set; } public int densityDecimals { get; set; } public int boxQuantityDecimals { get; set; } public int orderQuantityDecimals { get; set; } // Reference data. public List currencyCodes { get; set; } // Locations. public bool LocationIdsPopulated { get; set; } public HashSet LocationIds_All { get; } = new HashSet(); public HashSet LocationIds_Sales { get; } = new HashSet(); public HashSet LocationIds_NonSales { get; } = new HashSet(); public HashSet LocationIds_Calc { get; } = new HashSet(); } private readonly DataMembers mbr = new DataMembers(); //------------------------------------------------------------------- // Static initialisation. static SbmCoreMgr() { } //------------------------------------------------------------------- // Construction. protected SbmCoreMgr(SbmInternals internals) { if (internals == null) throw new NotSupportedException("SbmItemMgr Internals must be supplied"); mbr.internalsSupplied = internals; UserContext = internals.UserContext; Initialise(); } protected SbmCoreMgr(ISbmUserOrganisationContext userContext) { if (userContext == null) throw new NotSupportedException("SbmItemMgr User context must be supplied"); mbr.internalsSupplied = null; this.UserContext = userContext; Initialise(); } protected override void Dispose(bool disposing) { if (disposing) { if (mbr.internals != null) mbr.internals.Dispose(); } base.Dispose(disposing); } //------------------------------------------------------------------- // Initialisation. private void Initialise() { } private void InitialiseNumericControlValues() { if (mbr.numericControlValuesInitialised) return; mbr.numericControlValuesInitialised = true; // Numeric formatting values. mbr.weightDecimals = Internals.GetOwnerOption_NumericDecimals(Sbm.OrgOption_NumericDecimals.CommodityWeight); mbr.lengthDecimals = Internals.GetOwnerOption_NumericDecimals(Sbm.OrgOption_NumericDecimals.CommodityLength); mbr.volumeDecimals = Internals.GetOwnerOption_NumericDecimals(Sbm.OrgOption_NumericDecimals.CommodityVolume); mbr.densityDecimals = Internals.GetOwnerOption_NumericDecimals(Sbm.OrgOption_NumericDecimals.CommodityDensity); mbr.boxQuantityDecimals = 0; mbr.orderQuantityDecimals = Internals.GetOwnerOption_NumericDecimals(Sbm.OrgOption_NumericDecimals.OrderQuantity); } //------------------------------------------------------------------- // Async initialisation. public async void InitialiseCodeTypesAsync() { if (codeTypeCache != null) return; // Populate cache with codes for all supported code types. // Intended to minimise db I/O to retrieve all required codes. SaCode.Params prmCode = new SaCode.Params(); foreach (Sbm.ApplCodeType codeType in SupportedCodeTypes) prmCode.CodeTypeCodes.Add(SbmSystem.GetCodeTypeCode(codeType)); prmCode.StatusCat = SaCode.StatusCat.Any; codeTypeCache = new CodeTypeCache(await CodeTypeConsole.GetCodesAsync(prmCode)); } //------------------------------------------------------------------- // Properties. // System codes. protected List ItemTypes { get { return GetSystemCodes(Sbm.SystemCode.ItemType); } } protected List InterfaceOptionCodes { get { return GetSystemCodes(Sbm.SystemCode.InterfaceOption); } } // Numeric control values. protected int WeightDecimals { get { InitialiseNumericControlValues(); return mbr.weightDecimals; } } protected int LengthDecimals { get { InitialiseNumericControlValues(); return mbr.lengthDecimals; } } protected int VolumeDecimals { get { InitialiseNumericControlValues(); return mbr.volumeDecimals; } } protected int DensityDecimals { get { InitialiseNumericControlValues(); return mbr.densityDecimals; } } protected int BoxQuantityDecimals { get { InitialiseNumericControlValues(); return mbr.boxQuantityDecimals; } } protected int OrderQuantityDecimals { get { InitialiseNumericControlValues(); return mbr.orderQuantityDecimals; } } // Internals. protected SbmInternals Internals { get { if (mbr.internalsSupplied != null) return mbr.internalsSupplied; if (mbr.internals == null) mbr.internals = new SbmInternals(UserContext); return mbr.internals; } } // Session. protected ISbmUserOrganisationContext UserContext { get; } protected SbmSessionContext SessionContext { get { return UserContext.SessionContext; } } protected SysId AffiliateId_Owner { get { return UserContext.OrganisationAffiliateId; } } protected SbmAccountsConsole AccountsDfn { get { return Internals.AccountsConsole; } } protected DbUpdateInfo DbUpdateInfo { get { return Internals.DbUpdateInfo; } } // User security profile. public bool UserCanViewCommoditySalesFinancials() { return UserContext.SecurityProfile.UserCanViewFinancials(Sbm.FinancialType.CommoditySales); } public bool UserCanViewCommoditySupplyFinancials() { return UserContext.SecurityProfile.UserCanViewFinancials(Sbm.FinancialType.CommoditySupply); } // Managers. protected SbmAccountMgr AccountMgr { get { return Internals.AccountMgr; } } protected SbmCommodityMgr CommodityMgr { get { return Internals.CommodityMgr; } } protected SbmAssetMgr AssetMgr { get { return Internals.AssetMgr; } } protected SbmPriceMgr PriceMgr { get { return Internals.PriceMgr; } } protected SbmTransactionMgr TransactionMgr { get { return Internals.TransactionMgr; } } protected SbmStockMgr StockMgr { get { return Internals.StockMgr; } } protected SbmProcessMgr ProcessMgr { get { return Internals.ProcessMgr; } } protected SbmDataItemMgr DataItemMgr { get { return Internals.DataItemMgr; } } // Consoles. protected SbmSessionConsole SessionConsole { get { return Internals.SessionConsole; } } protected SaDiaryConsole DiaryConsole { get { return Internals.DiaryConsole; } } protected SaSecurityConsole SecurityConsole { get { return Internals.SecurityConsole; } } protected SaCodeTypeConsole CodeTypeConsole { get { return Internals.CodeTypeConsole; } } protected SaReferenceDataConsole ReferenceDataConsole { get { return Internals.ReferenceDataConsole; } } protected SaUpdateLogConsole UpdateLogConsole { get { return Internals.UpdateLogConsole; } } protected SaInterfaceConsole InterfaceConsole { get { return Internals.InterfaceConsole; } } protected SaItemDocConsole ItemDocConsole { get { return Internals.ItemDocConsole; } } protected SaItemOptionConsole ItemOptionConsole { get { return Internals.ItemOptionConsole; } } protected SaItemDataConsole ItemDataConsole { get { return Internals.ItemDataConsole; } } // Configurations. protected SbmStockControlConfig StockControlConfig { get { return Internals.StockControlConfig; } } protected SbmRequirementCostingConfig RequirementCostingConfig { get { return Internals.RequirementCostingConfig; } } // Currencies. protected List CurrencyCodes { get { if (mbr.currencyCodes == null) mbr.currencyCodes = SaReferenceDataConsole.GetReferenceDataCodes(ReferenceDataSystemCode.CurrencyCode); return new List(mbr.currencyCodes); } } protected List GetCurrencies() { return Internals.GetCurrencies(); } protected SaCurrency GetCurrencyById(SysId currencyId) { return Internals.GetCurrencyById(currencyId); } protected SaCurrency GetCurrencyByCode(String currencyCode) { return Internals.GetCurrencyByCode(currencyCode); } protected static ushort CurrencyDecimalsDefault { get { return SbmInternals.CurrencyDecimalsDefault; } } protected ushort GetCurrencyDecimalsForCurrencyById(SysId currencyId) { return Internals.GetCurrencyDecimalsById(currencyId); } //------------------------------------------------------------------- // Utilities. public List GetSystemCodes(Sbm.SystemCode systemCode) { return Internals.GetSystemCodes(systemCode); } // Database utilities. public bool TableExists(SbmDbDfn.TableIdx tableIdx) { SbmApplication application = SbmGlobals.Application; if (application != null) { return application.DbTableExists(Internals.BusMgrDatabase, tableIdx); } return false; } public virtual bool ColumnExists(SbmDbDfn.ColumnIdx columnIdx) { SbmApplication application = SbmGlobals.Application; if (application != null) { return application.DbColumnExists(Internals.BusMgrDatabase, columnIdx); } return false; } //------------------------------------------------------------------- // Session console utilities. public bool AllowConfigOption(Sbm.ConfigOption configOption) { return SessionConsole.AllowOption(configOption); } public bool AllowAffiliateType(Sbm.AffiliateType affiliateType) { return SessionConsole.AllowAffiliateType(affiliateType); } public bool AllowAssociationType(Sbm.AssociationType associationType) { return SessionConsole.AllowAssociationType(associationType); } public bool AllowTransactionType(Sbm.TransactionType transactionType) { return SessionConsole.AllowTransactionType(transactionType); } public String GetAttributeCaption(SbmDbDfn.ColumnIdx columnIdx, String defaultValue) { return SessionConsole.GetAttributeCaption(columnIdx, defaultValue); } //------------------------------------------------------------------- // C o d e T y p e s //------------------------------------------------------------------- public virtual List SupportedCodeTypes { get; } = new List(); private CodeTypeCache codeTypeCache; public bool CodeTypeHasCodes(Sbm.ApplCodeType codeType) { if (DebugMode && !SupportedCodeTypes.Contains(codeType)) throw new NotSupportedException($"{SysUtil.Fn} Unsupported code type: {codeType}"); PopulateCodeTypes(); return codeTypeCache.CodeTypeHasCodes(codeType); } public String GetCodeTypeCodeDesc(Sbm.ApplCodeType codeType, String code, bool defaultToCode = true) { if (DebugMode && !SupportedCodeTypes.Contains(codeType)) throw new NotSupportedException($"{SysUtil.Fn} Unsupported code type: {codeType}"); PopulateCodeTypes(); List codes = codeTypeCache.GetCodesForCodeType(codeType, false); if (codes != null) return codes.GetDescForCode(code, defaultToCode ? code : ""); return ""; } public List GetCodesForCodeType(Sbm.ApplCodeType codeType, bool activeOnly = true) { if (DebugMode && !SupportedCodeTypes.Contains(codeType)) throw new NotSupportedException($"{SysUtil.Fn} Unsupported code type: {codeType}"); PopulateCodeTypes(); return codeTypeCache.GetCodesForCodeType(codeType, activeOnly); } public List GetCodeDescsForCodeType(Sbm.ApplCodeType codeType, bool activeOnly = true) { if (DebugMode && !SupportedCodeTypes.Contains(codeType)) throw new NotSupportedException($"{SysUtil.Fn} Unsupported code type: {codeType}"); PopulateCodeTypes(); return codeTypeCache.GetCodeDescsForCodeType(codeType, activeOnly); } private void PopulateCodeTypes() { if (codeTypeCache != null) return; // Populate cache with codes for all supported code types. // Intended to minimise db I/O to retrieve all required codes. SaCode.Params prmCode = new SaCode.Params(); foreach (Sbm.ApplCodeType codeType in SupportedCodeTypes) prmCode.CodeTypeCodes.Add(SbmSystem.GetCodeTypeCode(codeType)); prmCode.StatusCat = SaCode.StatusCat.Any; Dictionary> codesByCodeType = CodeTypeConsole.GetCodes(prmCode); // Populate any supported code types without codes. foreach (Sbm.ApplCodeType codeType in SupportedCodeTypes) { String codeTypeCode = SbmSystem.GetCodeTypeCode(codeType); if (!codesByCodeType.ContainsKey(codeTypeCode)) codesByCodeType[codeTypeCode] = new List(); } codeTypeCache = new CodeTypeCache(codesByCodeType); } //------------------------------------------------------------------- // R e f e r e n c e D a t a //------------------------------------------------------------------- // Currencies. public SaCurrency GetDefaultCurrency() { String currencyCode = CurrencyCodes.GetCodeForType(SaCurrencyCode.Sterling); return Internals.GetCurrencyByCode(currencyCode); } public SaCurrency GetCurrency(SysId currencyId) { return Internals.GetCurrencyById(currencyId); } // Regions. public SaRegion FindRegionById(SysId regionId) { return Internals.GetRegionById(regionId); } // Tax codes. public SaTaxCode FindTaxCodeById(SysId taxCodeId) { return Internals.GetTaxCodeById(taxCodeId); } public SaTaxCode FindTaxCodeEffectiveOn(String taxCode, DateTime effectiveOn) { return Internals.GetTaxCodes().FindByCodeEffectiveOn(taxCode, effectiveOn); } // Units of measure. public SaUnitMeasure FindUnitOfMeasureById(SysId uomId) { return Internals.GetUnitOfMeasureById(uomId); } public List FindUnitsOfMeasureByCategory(SaUomCategory uomCategory) { return Internals.GetUnitsOfMeasureByCategory(uomCategory); } //------------------------------------------------------------------- // Locations. private bool PopulateLocationIds() { if (mbr.LocationIdsPopulated) return true; if (!StockMgr.StockDatabaseIsValid()) return false; mbr.LocationIdsPopulated = true; // Query active locations. SbmLocation.Params prmLocation = new SbmLocation.Params(); prmLocation.StatusCat = SbmLocation.StatusCat.ActiveOnly; foreach (SbmLocation location in StockMgr.GetLocationList(prmLocation)) { if (location == null) break; mbr.LocationIds_All.Add(location.Id); if (location.CalculateStock) mbr.LocationIds_Calc.Add(location.Id); if (location.SalesStock) mbr.LocationIds_Sales.Add(location.Id); else mbr.LocationIds_NonSales.Add(location.Id); } // Check if any Sales locations defined. if (!mbr.LocationIds_Sales.Any()) { // Assume that all locations are for sales. mbr.LocationIds_Sales.UnionWith(mbr.LocationIds_NonSales); mbr.LocationIds_NonSales.Clear(); } return true; } protected HashSet GetLocationIds_All() { PopulateLocationIds(); return new HashSet(mbr.LocationIds_All); } protected HashSet GetLocationIds_Sales() { PopulateLocationIds(); return new HashSet(mbr.LocationIds_Sales); } protected HashSet GetLocationIds_NonSales() { PopulateLocationIds(); return new HashSet(mbr.LocationIds_NonSales); } protected HashSet GetLocationIds_Calc() { PopulateLocationIds(); return new HashSet(mbr.LocationIds_Calc); } //------------------------------------------------------------------- } //======================================================================= }