using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Diagnostics; using Moq; using MoreLinq; using MoreLinq.Extensions; using NUnit.Framework; using Strata.ContinuousImprovement.Biz.All; using Strata.ContinuousImprovement.Biz.All.Opportunities; using Strata.ContinuousImprovement.Biz.ChargeCode.Opportunities; using Strata.ContinuousImprovement.Biz.DbContexts; using Strata.ContinuousImprovement.Biz.FiscalMonths; using Strata.ContinuousImprovement.Biz.Generics; using Strata.ContinuousImprovement.Biz.OpportunityComments; using Strata.ContinuousImprovement.Biz.PeerGroups; using Strata.ContinuousImprovement.Biz.PeerGroups.Enums; using Strata.ContinuousImprovement.Biz.QualityVariation.Breakdowns; using Strata.ContinuousImprovement.Biz.Shared; using Strata.ContinuousImprovement.Biz.Utilities; using Strata.ContinuousImprovement.Biz.UtilizationVariation; using Strata.ContinuousImprovement.JazzEntityFrameworkStub.Generics; using Strata.SqlTools.Configuration.Common.AsyncFactory; using Strata.StrataSphereCompare.Client.Models.Enums; using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace Strata.ContinuousImprovement.JazzEntityFrameworkStub { public partial class JazzEntityFrameworkFactory : IAsyncDbContextFactory { public static List OpportunityGuids = new List { Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid() }; public static Guid CurrentConfigurationGuid = new Guid("e96abe3e-1526-43ca-815e-ee30c5b34345"); public static Guid CaseTypeGuid = new Guid("c7838982-b2c6-4e93-a571-c1fd5cedc961"); public static Guid DatabaseGuid = new Guid("21E97CAF-F37D-4F22-9777-0C6A36210FF9"); public string TestName { get; set; } = TestContext.CurrentContext?.Test.FullName ?? throw new InvalidOperationException("TestContext.CurrentContext cannot be null"); public JazzDbContext JazzDbContext; public CentralDbContext CentralDbContext; public IFiscalMonthResolver FiscalMonthResolver = Mock.Of(); public IDatabaseFunctionService DbFunctionService = Mock.Of(); public async Task CreateDbContextAsync(CancellationToken cancellationToken) => await CreateDbContextAsync(TestName, cancellationToken); public async Task CreateDbContextAsync(string dbName, CancellationToken cancellationToken) { if (string.IsNullOrEmpty(dbName)) { return await Task.FromResult((JazzDbContext)null); } var options = new DbContextOptionsBuilder() .UseInMemoryDatabase(dbName) // don't raise the error warning us that the in memory db doesn't support transactions .ConfigureWarnings(x => x.Ignore(InMemoryEventId.TransactionIgnoredWarning)) .Options; JazzDbContext = new JazzDbContext(options); Mock.Get(DbFunctionService) .Setup(x => x.SplitString(It.IsAny>())) .Returns>(x => (y => y.EntityId.Split(',', StringSplitOptions.TrimEntries).Intersect(x).Count() > 0)); await JazzDbContext.Database.EnsureCreatedAsync(cancellationToken); JazzDbContext.DatabaseFunctionService = DbFunctionService; if (FiscalMonthResolver != null) { Mock.Get(FiscalMonthResolver) .Setup(s => s.AllFiscalMonths) .Returns(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 } .Select(m => new FiscalMonth { MemberGuid = Guid.NewGuid(), FiscalMonthId = (byte)m, FiscalMonthCode = $"{m}", SortOrder = (byte)m, DaysInMonth = m switch { 2 => 28, 4 => 30, 6 => 30, 9 => 30, 11 => 30, _ => 31 }, MonthColumnName = $"Month{m:00}", Abbreviation = new DateTime(2024, m, 1).ToString("MMM"), IsReal = true }).ToList().AsReadOnly()); Mock.Get(FiscalMonthResolver) .Setup(s => s.FirstFiscalMonth()) .Returns(new FiscalMonth { MemberGuid = Guid.NewGuid(), FiscalMonthId = 1, FiscalMonthCode = "1", SortOrder = 1, DaysInMonth = 31, MonthColumnName = "Month01", Abbreviation = "Jan", IsReal = true, }); Mock.Get(FiscalMonthResolver) .Setup(s => s.LastFiscalMonth()) .Returns(new FiscalMonth { MemberGuid = Guid.NewGuid(), FiscalMonthId = 12, FiscalMonthCode = "12", SortOrder = 12, DaysInMonth = 31, MonthColumnName = "Month12", Abbreviation = "Dec", IsReal = true, }); } if (!JazzDbContext.SystemSettings.Any()) { await JazzDbContext.SystemSettings.AddRangeAsync(SystemSettings, cancellationToken); } if (!JazzDbContext.Configurations.Any()) { Configurations.ForEach(c => { c.FiscalMonthResolver = FiscalMonthResolver; }); await JazzDbContext.Configurations.AddRangeAsync(Configurations, cancellationToken); } if (!JazzDbContext.UserSettings.Any()) { await JazzDbContext.UserSettings.AddRangeAsync(UserSettings, cancellationToken); } if (!JazzDbContext.CaseTypeFamilies.Any()) { await JazzDbContext.CaseTypeFamilies.AddRangeAsync(CaseTypeFamilies, cancellationToken); } if (!JazzDbContext.FFOpportunities.Any()) { FFOpportunities.First().ConfigurationGuid = Configurations.First().ConfigurationGuid; await JazzDbContext.FFOpportunities.AddRangeAsync(FFOpportunities, cancellationToken); } if (!JazzDbContext.FreeFormOpportunities.Any()) { var configuration = Configurations[0]; configuration.FiscalMonthResolver = FiscalMonthResolver; FFOpportunitiesDataModel.ForEach(ff => { ff.ConfigurationGuid = configuration.ConfigurationGuid; ff.Configuration = configuration; }); await JazzDbContext.FreeFormOpportunities.AddRangeAsync(FFOpportunitiesDataModel, cancellationToken); } if (!JazzDbContext.GeneralLedgerOpportunities.Any()) { GLOpportunities.First().ConfigurationGuid = Configurations.First().ConfigurationGuid; await JazzDbContext.GeneralLedgerOpportunities.AddRangeAsync(GLOpportunities, cancellationToken); } if (!JazzDbContext.PayrollOpportunities.Any()) { PROpportunities.First().ConfigurationGuid = Configurations.First().ConfigurationGuid; await JazzDbContext.PayrollOpportunities.AddRangeAsync(PROpportunities, cancellationToken); } if (!JazzDbContext.VariationOpportunities.Any()) { UVOpportunities.First().ConfigurationGuid = Configurations.First().ConfigurationGuid; await JazzDbContext.VariationOpportunities.AddRangeAsync(UVOpportunities, cancellationToken); } if (!JazzDbContext.UtilizationVariationOpportunitiesData.Any()) { UtilizationVariationOpportunities.First().ConfigurationGuid = Configurations.First().ConfigurationGuid; await JazzDbContext.UtilizationVariationOpportunitiesData.AddRangeAsync(UtilizationVariationOpportunities, cancellationToken); } if (!JazzDbContext.ExplorationVariationOpportunitiesData.Any()) { ExplorationVariationOpportunities.First().ConfigurationGuid = Configurations.First().ConfigurationGuid; await JazzDbContext.ExplorationVariationOpportunitiesData.AddRangeAsync(ExplorationVariationOpportunities, cancellationToken); } if (!JazzDbContext.ChargeCodeOpportunities.Any()) { CCOpportunities.First().ConfigurationGuid = Configurations.First().ConfigurationGuid; await JazzDbContext.ChargeCodeOpps.AddRangeAsync(CCOpportunities, cancellationToken); var ccDataModels = CCOpportunities.Select(cc => cc.MapToDataModel()).ToList(); foreach (var cc in ccDataModels) { if (cc.ConfigurationGuid == Configurations.First().ConfigurationGuid) { cc.Configuration = Configurations.First(); } cc.EncounterGroup = (int)EncounterGroup.CaseType; cc.CaseTypes = new List { "CaseType 1", "CaseType 2", "CaseType 3" }; cc.ChargeCodes = new List { "CC 1", "CC 2", "CC 3", }; var details = new List(); details.AddRange( Enumerable.Range(1, 12).Select(month => new ChargeCodeOpportunityDetail { OpportunityGUID = cc.OpportunityGuid, OpportunityLevelId = 0, OpportunityLevelName = "Organization", ChargeCodeId = 0, ChargeCodeName = "", ChargeCodeRollupName = "CC 1", TotalCases = 10, TotalCost = 10, TotalUnitsOfService = 10, GoalTotalUnitsOfService = 10, IsBaseline = true, Month = month, GoalCostPerUnit = 10 })); cc.Details = details; } ChargeCodeOpportunities.AddRange(ccDataModels); ChargeCodeDetails.AddRange(ccDataModels.SelectMany(dm => dm.Details)); await JazzDbContext.ChargeCodeOpportunities.AddRangeAsync(ccDataModels, cancellationToken); await JazzDbContext.ChargeCodeDetails.AddRangeAsync(ccDataModels.SelectMany(dm => dm.Details), cancellationToken); } if (!JazzDbContext.EncounterOpportunities.Any()) { FFOpportunities.First().ConfigurationGuid = Configurations.First().ConfigurationGuid; await JazzDbContext.EncounterOpportunities.AddRangeAsync(ENOpportunities, cancellationToken); } if (!JazzDbContext.DimEntities.Any()) { await JazzDbContext.DimEntities.AddRangeAsync(DimEntities, cancellationToken); } if (!JazzDbContext.VariationCaseTypes.Any()) { await JazzDbContext.VariationCaseTypes.AddRangeAsync(UVCaseTypes, cancellationToken); } if (!JazzDbContext.QualityVariationItemOpportunities.Any()) { QVIOpportunities.First().ConfigurationGuid = Configurations.First().ConfigurationGuid; await JazzDbContext.QualityVariationItemOpportunities.AddRangeAsync(QVIOpportunities, cancellationToken); } if (!JazzDbContext.QualityVariationItemEvents.Any()) { QVIEvents.First().ConfigurationGuid = Configurations.First().ConfigurationGuid; await JazzDbContext.QualityVariationItemEvents.AddRangeAsync(QVIEvents, cancellationToken); } if (!JazzDbContext.QualityVariationItemBreakdowns.Any()) { qviBreakdowns.AddRange( QVIOpportunities.GroupBy( opp => new { opp.ConfigurationGuid, opp.BreakdownId }, (g, d) => new QVIBreakdown { BreakdownId = g.BreakdownId, BreakdownName = d.First().BreakdownName, IdentifiedSavingsTotal = d.Sum(b => b.IdentifiedSavings), QVICasesTotal = d.Sum(b => b.QVICases), CasesTotal = d.Sum(b => b.Cases), OpportunitiesCount = d.Count(), QVIRate = (decimal)d.Sum(b => b.QVICases).DivideBy(d.Sum(b => b.Cases)), ConfigurationGuid = g.ConfigurationGuid })); await JazzDbContext.QualityVariationItemBreakdowns.AddRangeAsync(qviBreakdowns, cancellationToken); } if (!JazzDbContext.AllOpportunities.Any()) { var configurationGuid = Configurations.First().ConfigurationGuid; await JazzDbContext.AllOpportunities.AddRangeAsync(UVOpportunities .ConvertAll(uv => new AllOpportunity { ConfigurationGuid = configurationGuid, OpportunityGuid = uv.OpportunityGuid, OpportunityKey = uv.OpportunityKey, OpportunityType = (int)OpportunityTypes.Variation, OpportunityTypeName = OpportunityTypes.Variation.OpportunityTypeName(), Name = $"{uv.CaseTypeName} - {uv.EntityName}", IdentifiedSavings = uv.IdentifiedSavings, Initiative = uv.Initiative, InitiativeGuid = uv.InitiativeGuid, IsHidden = uv.IsHidden, CostDriver = uv.CostDriver, Note = uv.Note }), cancellationToken); await JazzDbContext.AllOpportunities.AddRangeAsync(CCOpportunities .ConvertAll(opp => new AllOpportunity { ConfigurationGuid = configurationGuid, OpportunityGuid = opp.OpportunityGuid, OpportunityKey = opp.OpportunityKey, OpportunityType = (int)OpportunityTypes.Encounter, OpportunityTypeName = OpportunityTypes.Encounter.OpportunityTypeName(), Name = opp.Name, IdentifiedSavings = opp.IdentifiedSavings, Initiative = opp.Initiative, InitiativeGuid = opp.InitiativeGuid, IsHidden = opp.IsHidden, CostDriver = "Encounter", Note = opp.Note }), cancellationToken); await JazzDbContext.AllOpportunities.AddRangeAsync(ENOpportunities .ConvertAll(en => new AllOpportunity { ConfigurationGuid = configurationGuid, OpportunityGuid = en.OpportunityGuid, OpportunityKey = en.OpportunityKey, OpportunityType = (int)OpportunityTypes.Encounter, OpportunityTypeName = OpportunityTypes.Encounter.OpportunityTypeName(), Name = en.Name, IdentifiedSavings = en.IdentifiedSavings, Initiative = en.Initiative, InitiativeGuid = en.InitiativeGuid, IsHidden = en.IsHidden, CostDriver = "Encounter", Note = en.Note }), cancellationToken); await JazzDbContext.AllOpportunities.AddRangeAsync(GLOpportunities .ConvertAll(gl => new AllOpportunity { ConfigurationGuid = configurationGuid, OpportunityGuid = gl.OpportunityGuid, OpportunityKey = gl.OpportunityKey, OpportunityType = (int)OpportunityTypes.FreeForm, OpportunityTypeName = OpportunityTypes.FreeForm.OpportunityTypeName(), Name = gl.Name, IdentifiedSavings = gl.IdentifiedSavings, Initiative = gl.Initiative, InitiativeGuid = gl.InitiativeGuid, IsHidden = gl.IsHidden, CostDriver = "", Note = gl.Note }), cancellationToken); await JazzDbContext.AllOpportunities.AddRangeAsync(PROpportunities .ConvertAll(pr => new AllOpportunity { ConfigurationGuid = configurationGuid, OpportunityGuid = pr.OpportunityGuid, OpportunityKey = pr.OpportunityKey, OpportunityType = (int)OpportunityTypes.Payroll, OpportunityTypeName = OpportunityTypes.Payroll.OpportunityTypeName(), Name = pr.Name, IdentifiedSavings = pr.IdentifiedSavings, Initiative = pr.Initiative, InitiativeGuid = pr.InitiativeGuid, IsHidden = pr.IsHidden, CostDriver = "", Note = pr.Note }), cancellationToken); await JazzDbContext.AllOpportunities.AddRangeAsync(QVIOpportunities .ConvertAll(qv => new AllOpportunity { ConfigurationGuid = configurationGuid, OpportunityGuid = qv.OpportunityGuid, OpportunityKey = qv.OpportunityKey, OpportunityType = (int)OpportunityTypes.QualityVariation, OpportunityTypeName = OpportunityTypes.QualityVariation.OpportunityTypeName(), Name = qv.BreakdownName, IdentifiedSavings = qv.IdentifiedSavings, Initiative = qv.Initiative, InitiativeGuid = qv.InitiativeGuid, IsHidden = qv.IsHidden, CostDriver = "", Note = qv.Note }), cancellationToken); await JazzDbContext.AllOpportunities.AddRangeAsync(FFOpportunities .ConvertAll(ff => new AllOpportunity { ConfigurationGuid = configurationGuid, OpportunityGuid = Guid.NewGuid(), OpportunityKey = ff.OpportunityKey, OpportunityType = (int)OpportunityTypes.FreeForm, OpportunityTypeName = OpportunityTypes.FreeForm.OpportunityTypeName(), Name = ff.Name, IdentifiedSavings = ff.IdentifiedSavings, Initiative = ff.Initiative, InitiativeGuid = ff.InitiativeGuid, IsHidden = ff.IsHidden, CostDriver = ff.MetricType == ContinuousImprovement.Biz.FreeForm.Opportunities.MetricType.Financial ? "Financial Free Form" : "Free Form", Note = ff.Note }), cancellationToken); if (!JazzDbContext.PeerGroups.Any()) { await JazzDbContext.PeerGroups.AddAsync(new PeerGroup() { PeerGroupId = 1, Name = "Test Name" }, cancellationToken); } if (!JazzDbContext.PeerGroupCriteriaMappings.Any()) { var mappings = new List() { new PeerGroupCriteriaMapping() { RowId = 1, PeerGroupId = 1, MappingType = (byte)PeerGroupCritetiaType.EntityTypes, MappingValue = (byte)HospitalType.RehabLTACOther }, new PeerGroupCriteriaMapping() { RowId = 2, PeerGroupId = 1, MappingType = (byte)PeerGroupCritetiaType.UrbanRural, MappingValue = (byte)UrbanRural.Urban }, new PeerGroupCriteriaMapping() { RowId = 3, PeerGroupId = 1, MappingType = (byte)PeerGroupCritetiaType.AMCTypes, MappingValue = (byte)IsAmc.AcademicMedicalCenters }, new PeerGroupCriteriaMapping() { RowId = 4, PeerGroupId = 1, MappingType = (byte)PeerGroupCritetiaType.CensusRegions, MappingValue = (byte)CensusRegion.Midwest }, new PeerGroupCriteriaMapping() { RowId = 5, PeerGroupId = 1, MappingType = (byte)PeerGroupCritetiaType.BedSize, MappingValue = (byte)BedSize._0_250 }, new PeerGroupCriteriaMapping() { RowId = 6, PeerGroupId = 1, MappingType = (byte)PeerGroupCritetiaType.OperatingExpenses, MappingValue = (byte)OperatingExpense._250MTo500M }, }; await JazzDbContext.PeerGroupCriteriaMappings.AddRangeAsync(mappings, cancellationToken); } } await JazzDbContext.SaveChangesAsync(cancellationToken); return await Task.FromResult(JazzDbContext); } public Task CreateDbContextAsync(Guid databaseGuid, CancellationToken cancellationToken) { throw new NotImplementedException(); } public async Task CreateCentralDbContextAsync(CancellationToken cancellationToken) => await CreateCentralDbContextAsync(TestName, cancellationToken); public async Task CreateCentralDbContextAsync(string dbName, CancellationToken cancellationToken) { if (string.IsNullOrEmpty(dbName)) { return await Task.FromResult((CentralDbContext)null); } var centralOptions = new DbContextOptionsBuilder() .UseInMemoryDatabase(dbName) .Options; CentralDbContext = new CentralDbContext(centralOptions); await EnsureCreatedAsync(CentralDbContext, JazzDbContext, cancellationToken); return await Task.FromResult(CentralDbContext); } public async Task EnsureCreatedAsync(ICentralDbContext dbContext, CancellationToken cancellationToken) { var centralDbContext = (CentralDbContext)dbContext; await centralDbContext.Database.EnsureCreatedAsync(cancellationToken); if (!(await centralDbContext.NetworkOpportunities.AnyAsync(cancellationToken))) { await centralDbContext.NetworkOpportunities.AddRangeAsync(NetworkOpportunities, cancellationToken); } if (!(await centralDbContext.ClientNetworkOpportunities.AnyAsync(cancellationToken))) { await centralDbContext.ClientNetworkOpportunities.AddRangeAsync(ClientNetworkOpportunities, cancellationToken); } await centralDbContext.SaveChangesAsync(cancellationToken); } public async Task EnsureCreatedAsync(ICentralDbContext dbContext, IJazzDbContext jazzDbContext, CancellationToken cancellationToken) { await EnsureCreatedAsync(dbContext, cancellationToken); var centralDbContext = (CentralDbContext)dbContext; if (await centralDbContext.Comments.AnyAsync(cancellationToken)) { return; } await centralDbContext.Comments.AddRangeAsync(Comments, cancellationToken); if (jazzDbContext != null) { var allOpportunities = await jazzDbContext.AllOpportunities.ToListAsync(cancellationToken); if (!allOpportunities.Any()) { return; } var dateTime = new DateTimeOffset(DateTime.UtcNow, TimeSpan.Zero).UtcDateTime; var comments = allOpportunities .Select((opp, idx) => new Comment { CommentDate = dateTime.AddHours(idx), CommentId = idx + 2, CommentText = $"Comment on {opp.Name}", Author = "Name, Author", SourceOfSavingsId = (int)opp.OpportunityType, StrataId = 9, OpportunityId = opp.OpportunityId }).ToList(); await centralDbContext.Comments.AddRangeAsync(comments, cancellationToken); } try { await centralDbContext.SaveChangesAsync(cancellationToken); } catch (Exception ex) { // ILB } } } }