Template
654 lines
30 KiB
C#
654 lines
30 KiB
C#
using FluentAssertions;
|
|
using Hangfire;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Moq;
|
|
using Strata.ContinuousImprovement.Biz.Generics;
|
|
using Strata.ContinuousImprovement.Biz.InitiativeRollupColumns;
|
|
using Strata.ContinuousImprovement.Biz.OpportunityRoleAssignment;
|
|
using Strata.ContinuousImprovement.Biz.OpportunityWorkbooks;
|
|
using Strata.ContinuousImprovement.Biz.Security;
|
|
using Strata.ContinuousImprovement.Biz.StrategicOpportunities;
|
|
using Strata.ContinuousImprovement.Biz.StrategicOpportunities.DistributionProcess;
|
|
using Strata.ContinuousImprovement.Biz.StrategicOpportunities.Dtos;
|
|
using Strata.ContinuousImprovement.Biz.StrategicOpportunities.Enums;
|
|
using Strata.ContinuousImprovement.Biz.Test.Unit.Utilities;
|
|
using Strata.CoreLib.Claims.Extensions;
|
|
using Strata.DataSchema.Client;
|
|
using Strata.DataSchema.Models.Query;
|
|
using Strata.DataSchema.Models.Schema;
|
|
using Strata.Id.Client;
|
|
using Strata.Schema.Client;
|
|
using Strata.Schema.Client.Dtos;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
|
|
namespace Strata.ContinuousImprovement.Biz.Test.Integration.SnowflakeIntegrationTests
|
|
{
|
|
[ExcludeFromCodeCoverage]
|
|
[Ignore("temporarily ignoring because schema is out of sync")]
|
|
[TestFixture, Category("Integration"), Category("CCI")]
|
|
public class StrategicOpportunityServiceTests : IntegrationTestBase
|
|
{
|
|
private const string POPULATION_NAME = "Mocked Population Name";
|
|
private IStrategicOpportunityService _strategicOpportunityService;
|
|
private IOpportunityRoleAssignmentService _opportunityRoleAssignmentService;
|
|
|
|
[OneTimeSetUp]
|
|
public void Setup()
|
|
{
|
|
// Arrange mocks
|
|
var mockSchemaServiceClient = new Mock<ISchemaServiceClient>();
|
|
var mockDataSchemaService = new Mock<IDataSchemaService>();
|
|
var mockIdServiceClient = new Mock<IIdServiceClient>();
|
|
var mockIdRollupColumn = new Mock<IInitiativeRollupColumnService>();
|
|
var mockOpportunityWorkbookService = new Mock<IOpportunityWorkbookService>();
|
|
var mockStrategicOpportunityDetailService = new Mock<IStrategicChargeCodeOpportunityDetailService>();
|
|
var mockStrategicGLOpportunityDetailService = new Mock<IStrategicGLOpportunityDetailService>();
|
|
var mockSimpleSecurityServiceClient = new Mock<ISimpleSecurityService>();
|
|
var mockOpportunityRoleAssignmentServiceClient = new Mock<IOpportunityRoleAssignmentService>();
|
|
var mockBackgroundJobClient = new Mock<IBackgroundJobClient>();
|
|
var mockDistributionProcessFactory = new Mock<IDistributionProcessFactory>();
|
|
|
|
// Add mock responses
|
|
mockDataSchemaService.Setup(x =>
|
|
x.GetDataTableBySqlFullNameAsync(It.IsAny<string>(), It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(new DataTable());
|
|
|
|
mockDataSchemaService.Setup(x =>
|
|
x.GetDataColumnsBySqlColumnNameAsync(It.IsAny<string>(), It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync([]);
|
|
|
|
mockDataSchemaService.Setup(x =>
|
|
x.BuildSqlQuery(It.IsAny<QueryConfig>(), It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(new SqlResponse
|
|
{
|
|
SqlQuery = DataSchemaServiceSelectSql,
|
|
Parameters = new List<KeyValuePair<string, object>>
|
|
{
|
|
new(":dischargedatetime_Start_0", new DateTime(2024, 1, 1)),
|
|
new(":dischargedatetime_End_1", new DateTime(2024, 12, 31)),
|
|
new(":chargecodeid_2", 3541)
|
|
}
|
|
});
|
|
|
|
mockSchemaServiceClient.Setup(x =>
|
|
x.GetDimensionByGlobalIdAsync(It.IsAny<string>(), It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(new Schema.Client.Dtos.Info.ScoreDimensionInfoDto());
|
|
|
|
var list = new List<HierarchyNodeDto>();
|
|
list.Add(new HierarchyNodeDto
|
|
{
|
|
Path = "CLINICALINDICATOR|CLINICALINDI|188",
|
|
Name = POPULATION_NAME
|
|
});
|
|
|
|
mockSchemaServiceClient.Setup(x =>
|
|
x.GetHierarchyNodesFromHierarchyPathsAsync(It.IsAny<Guid>(), It.IsAny<IEnumerable<string>>(), It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(list);
|
|
|
|
mockSchemaServiceClient.Setup(x =>
|
|
x.GetDimensionMembersFromHierarchyPathsAsync(It.IsAny<Guid>(), It.IsAny<IEnumerable<string>>(), It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(new List<MemberDto> {
|
|
new MemberDto
|
|
{
|
|
Id = "188",
|
|
Name = "All Readmissions"
|
|
}});
|
|
|
|
var claimsPrincipalAccessor = TestUtilities.GetClaimsPrincipalAccessor();
|
|
_opportunityRoleAssignmentService = new OpportunityRoleAssignmentService(
|
|
(DbContexts.CentralDbContext)CentralDbContext,
|
|
mockIdServiceClient.Object,
|
|
mockSimpleSecurityServiceClient.Object,
|
|
claimsPrincipalAccessor
|
|
);
|
|
|
|
_strategicOpportunityService = new StrategicOpportunityService(
|
|
JazzConnBuilderFactory,
|
|
(DbContexts.CentralDbContext)CentralDbContext,
|
|
claimsPrincipalAccessor,
|
|
mockSchemaServiceClient.Object,
|
|
SnowflakeDatabaseContext,
|
|
mockIdServiceClient.Object,
|
|
_opportunityRoleAssignmentService,
|
|
mockIdRollupColumn.Object,
|
|
mockOpportunityWorkbookService.Object,
|
|
mockBackgroundJobClient.Object,
|
|
mockStrategicOpportunityDetailService.Object,
|
|
new StrategicItemDimensionSyncService(JazzConnBuilderFactory, (DbContexts.CentralDbContext)CentralDbContext, SnowflakeDatabaseContext),
|
|
mockStrategicGLOpportunityDetailService.Object,
|
|
(Microsoft.Extensions.Logging.ILogger<StrategicOpportunityService>)logger);
|
|
}
|
|
|
|
[Test, Ignore("temporarily ignoring because schema is out of sync")]
|
|
public async Task CreatingOpportunityShouldAlsoCreateDetails()
|
|
{
|
|
//arrange
|
|
var opportunity = CreateOpportunityDto();
|
|
|
|
//act
|
|
var result = await _strategicOpportunityService.CreateOpportunityChargeCodeAsync(opportunity, CancellationToken.None);
|
|
|
|
//assert
|
|
result.Should().Be(1, "On success should return opportunity id.");
|
|
}
|
|
|
|
private static StrategicOpportunityChargeCodeDto CreateOpportunityDto()
|
|
{
|
|
var opportunity = new StrategicOpportunityChargeCodeDto()
|
|
{
|
|
Name = "Integration-StrategicOpportunityChargeCode",
|
|
OpportunityType = StrategicOpportunityTypes.ChargeCode,
|
|
OpportunityFiltersJSON = "[]",
|
|
Rollup1Id = 0,
|
|
Rollup2Id = 0,
|
|
Rollup3Id = 0,
|
|
BaselineType = BaselineType.MonthRange,
|
|
BaselineDistribution = DistributionMethod.Average,
|
|
BaselineStartDate = new DateOnly(2024, 1, 1),
|
|
BaselineEndDate = new DateOnly(2024, 12, 31),
|
|
EstimatedTrackingDuration = 12,
|
|
|
|
// Assume empty or test collections for these
|
|
Measures = Enumerable.Empty<StrategicOpportunityMeasureDto>(),
|
|
WorkbookIds = Enumerable.Empty<int>(),
|
|
|
|
// ChargeCode-specific properties
|
|
PatientPopulationHPath = "CLINICALINDICATOR|CLINICALINDI|188",
|
|
ExplorationPopulationId = 0,
|
|
ChargeCodeHPath = "CC|CCRU|Blood"
|
|
};
|
|
return opportunity;
|
|
}
|
|
|
|
[Test]
|
|
public async Task UpdateStrategicOpportunityRampUpsAsync_ShouldUpdateRampUps()
|
|
{
|
|
// Arrange
|
|
var opportunity = CreateOpportunityDto();
|
|
var opportunityId = await _strategicOpportunityService.CreateOpportunityChargeCodeAsync(opportunity, CancellationToken.None);
|
|
|
|
var rampUps = new List<StrategicOpportunityRampUpDto>
|
|
{
|
|
new() { OpportunityId = opportunityId, MonthNumber = 1, Percentage = 0.1 },
|
|
new() { OpportunityId = opportunityId, MonthNumber = 2, Percentage = 0.2 }
|
|
};
|
|
|
|
// Act
|
|
var updateResult = await _strategicOpportunityService.UpdateStrategicOpportunityRampUpsAsync(opportunityId, rampUps, CancellationToken.None);
|
|
|
|
// Assert
|
|
updateResult.Should().BeTrue();
|
|
|
|
// Verify persisted values
|
|
var retrieved = await _strategicOpportunityService.GetStrategicOpportunityRampUpsAsync(opportunityId, CancellationToken.None);
|
|
retrieved.Should().HaveCount(rampUps.Count);
|
|
retrieved[0].MonthNumber.Should().Be(rampUps[0].MonthNumber);
|
|
retrieved[0].Percentage.Should().Be(rampUps[0].Percentage);
|
|
retrieved[1].MonthNumber.Should().Be(rampUps[1].MonthNumber);
|
|
retrieved[1].Percentage.Should().Be(rampUps[1].Percentage);
|
|
}
|
|
|
|
[Test]
|
|
public async Task ResetStrategicOpportunityRampUps_ShouldResetRampUps()
|
|
{
|
|
// Arrange
|
|
var opportunity = CreateOpportunityDto();
|
|
var opportunityId = await _strategicOpportunityService.CreateOpportunityChargeCodeAsync(opportunity, CancellationToken.None);
|
|
|
|
var rampUps = new List<StrategicOpportunityRampUpDto>
|
|
{
|
|
new() { OpportunityId = opportunityId, MonthNumber = 1, Percentage = 0.1 },
|
|
new() { OpportunityId = opportunityId, MonthNumber = 2, Percentage = 0.2 }
|
|
};
|
|
|
|
await _strategicOpportunityService.UpdateStrategicOpportunityRampUpsAsync(opportunityId, rampUps, CancellationToken.None);
|
|
|
|
// Act
|
|
var resetResult = await _strategicOpportunityService.ResetStrategicOpportunityRampUps(opportunityId, CancellationToken.None);
|
|
|
|
// Assert
|
|
resetResult.Should().BeTrue();
|
|
var retrieved = await _strategicOpportunityService.GetStrategicOpportunityRampUpsAsync(opportunityId, CancellationToken.None);
|
|
|
|
// Verify persisted values
|
|
retrieved.Should().HaveCount(rampUps.Count);
|
|
retrieved[0].Percentage.Should().Be(1);
|
|
retrieved[1].Percentage.Should().Be(1);
|
|
}
|
|
|
|
[Test]
|
|
public async Task ResetStrategicOpportunityRampUps_ShouldNotResetRampUps()
|
|
{
|
|
// Arrange
|
|
var opportunity = CreateOpportunityDto();
|
|
var opportunityId = await _strategicOpportunityService.CreateOpportunityChargeCodeAsync(opportunity, CancellationToken.None);
|
|
|
|
// Act
|
|
var resetResult = await _strategicOpportunityService.ResetStrategicOpportunityRampUps(opportunityId, CancellationToken.None);
|
|
|
|
// Assert
|
|
resetResult.Should().BeFalse();
|
|
}
|
|
|
|
[Test]
|
|
public async Task UpdateStrategicOpportunityRoleAssignment_ShouldUpdateRoleAssignments()
|
|
{
|
|
// Arrange
|
|
var opportunity = CreateOpportunityDto();
|
|
var opportunityId = await _strategicOpportunityService.CreateOpportunityChargeCodeAsync(opportunity, CancellationToken.None);
|
|
|
|
var roleAssignments = new List<OpportunityRoleAssignmentView>()
|
|
{
|
|
new OpportunityRoleAssignmentView() { LootId = opportunityId, IdentityGuid = Guid.NewGuid(), IdentityName = "Test", CanRead = true, CanWrite = true, CanSecure = false }
|
|
};
|
|
|
|
// Act
|
|
var saveResult = await _opportunityRoleAssignmentService.SaveRoleAssignmentsAsync(opportunityId, roleAssignments, CancellationToken.None);
|
|
|
|
// Assert
|
|
saveResult.Should().BeTrue();
|
|
|
|
// Verify persisted values
|
|
var retrieved = await _opportunityRoleAssignmentService.GetRoleAssignmentsAsync(opportunityId, CancellationToken.None);
|
|
var userPermission = await _opportunityRoleAssignmentService.GetUserRoleAssignmentsAsync(opportunityId, CancellationToken.None);
|
|
|
|
retrieved.Should().HaveCount(roleAssignments.Count);
|
|
var item = retrieved.FirstOrDefault();
|
|
item.LootId.Should().Be(opportunityId);
|
|
item.IdentityGuid.Should().Be(roleAssignments[0].IdentityGuid);
|
|
item.IdentityName.Should().Be(roleAssignments[0].IdentityName);
|
|
item.CanRead.Should().Be(roleAssignments[0].CanRead);
|
|
item.CanWrite.Should().Be(roleAssignments[0].CanWrite);
|
|
item.CanSecure.Should().Be(roleAssignments[0].CanSecure);
|
|
|
|
}
|
|
|
|
[Test]
|
|
public async Task GetStrategicOpportunityRampUpsAsync_ShouldReturnEmptyListIfNoneExist()
|
|
{
|
|
// Arrange
|
|
var nonExistentOpportunityId = long.MaxValue;
|
|
|
|
// Act
|
|
var rampUps = await _strategicOpportunityService.GetStrategicOpportunityRampUpsAsync(nonExistentOpportunityId, CancellationToken.None);
|
|
|
|
// Assert
|
|
rampUps.Should().NotBeNull();
|
|
rampUps.Should().BeEmpty();
|
|
}
|
|
|
|
[Test]
|
|
public async Task GetStrategicOpportunitiesAsync_ShouldReturnOpportunitiesWithRollupsAndPopulation()
|
|
{
|
|
// Arrange
|
|
var opportunity = CreateOpportunityDto();
|
|
var opportunityId = await _strategicOpportunityService.CreateOpportunityChargeCodeAsync(opportunity, CancellationToken.None);
|
|
|
|
// Act
|
|
var results = await _strategicOpportunityService.GetStrategicOpportunitiesAsync(CancellationToken.None);
|
|
|
|
// Assert
|
|
results.Should().NotBeEmpty("At least one opportunity should be returned");
|
|
var createdOpportunity = results.FirstOrDefault(o => o.OpportunityId == opportunityId);
|
|
createdOpportunity.Should().NotBeNull("Created opportunity should be found in results");
|
|
|
|
createdOpportunity.OpportunityId.Should().Be(opportunityId);
|
|
createdOpportunity.Name.Should().Be(opportunity.Name);
|
|
createdOpportunity.OpportunityTypeName.Should().Be("Charge Code");
|
|
createdOpportunity.EncounterGroupName.Should().Be("Patient Population", "When PatientPopulationHPath is set, it should be Patient Population");
|
|
createdOpportunity.AdditionalFilters.Should().Be("No");
|
|
createdOpportunity.BaselinePeriod.Should()
|
|
.Be($"{opportunity.BaselineStartDate:MMM d, yyyy} - {opportunity.BaselineEndDate:MMM d, yyyy}");
|
|
createdOpportunity.EstimatedTrackDurationMonths.Should().Be(opportunity.EstimatedTrackingDuration);
|
|
|
|
createdOpportunity.Rollup1.Should().BeEmpty("When rollup1Id is 0, rollup should be empty");
|
|
createdOpportunity.Rollup2.Should().BeEmpty("When rollup2Id is 0, rollup should be empty");
|
|
createdOpportunity.Rollup3.Should().BeEmpty("When rollup3Id is 0, rollup should be empty");
|
|
|
|
createdOpportunity.PatientPopulationHPath.Should().Be(opportunity.PatientPopulationHPath);
|
|
createdOpportunity.ExplorationPopulationId.Should().Be(opportunity.ExplorationPopulationId);
|
|
createdOpportunity.Population.Should().Be(POPULATION_NAME);
|
|
}
|
|
|
|
[Test]
|
|
public async Task UpdateStrategicOpportunityStatus_WhenNewInitiative_ShouldUpdateStatusAndDates()
|
|
{
|
|
// Arrange
|
|
var opportunity = CreateOpportunityDto();
|
|
var opportunityId = await _strategicOpportunityService.CreateOpportunityChargeCodeAsync(opportunity, CancellationToken.None);
|
|
|
|
var updateStatusDto = new StrategicOpportunityUpdateStatusDto
|
|
{
|
|
Status = (byte)StrategicOpportunityStatus.NewInitiative,
|
|
TrackingStartDate = new DateOnly(2024, 1, 1),
|
|
TrackingEndDate = new DateOnly(2024, 12, 31)
|
|
};
|
|
|
|
// Act
|
|
var updateResult = await _strategicOpportunityService.UpdateStrategicOpportunityStatus(opportunityId, updateStatusDto, CancellationToken.None);
|
|
|
|
// Assert
|
|
updateResult.Should().BeTrue("Update should be successful");
|
|
|
|
var strataId = TestUtilities.GetClaimsPrincipalAccessor()?.GetCurrentClaimsPrincipal().GetStrataId();
|
|
var opportunityAfterUpdate = await CentralDbContext.StrategicOpportunities
|
|
.FirstOrDefaultAsync(x => x.OpportunityId == opportunityId && x.StrataId == strataId, CancellationToken.None);
|
|
|
|
opportunityAfterUpdate.Should().NotBeNull("Updated opportunity should exist");
|
|
opportunityAfterUpdate.Status.Should().Be(updateStatusDto.Status, "Status should be updated to NewInitiative");
|
|
opportunityAfterUpdate.TrackingStartDate.Should().Be(updateStatusDto.TrackingStartDate, "TrackingStartDate should be updated");
|
|
opportunityAfterUpdate.TrackingEndDate.Should().Be(updateStatusDto.TrackingEndDate, "TrackingEndDate should be updated");
|
|
}
|
|
|
|
[Test]
|
|
public async Task UpdateStrategicOpportunityStatus_WhenNewOpportunity_ShouldResetTrackingData()
|
|
{
|
|
// Arrange
|
|
var opportunity = CreateOpportunityDto();
|
|
var opportunityId = await _strategicOpportunityService.CreateOpportunityChargeCodeAsync(opportunity, CancellationToken.None);
|
|
|
|
var toInitiativeDto = new StrategicOpportunityUpdateStatusDto
|
|
{
|
|
Status = (byte)StrategicOpportunityStatus.NewInitiative,
|
|
TrackingStartDate = new DateOnly(2024, 1, 1),
|
|
TrackingEndDate = new DateOnly(2024, 12, 31)
|
|
};
|
|
await _strategicOpportunityService.UpdateStrategicOpportunityStatus(opportunityId, toInitiativeDto, CancellationToken.None);
|
|
|
|
var toOpportunityDto = new StrategicOpportunityUpdateStatusDto
|
|
{
|
|
Status = (byte)StrategicOpportunityStatus.NewOpportunity
|
|
};
|
|
|
|
// Act
|
|
var updateResult = await _strategicOpportunityService.UpdateStrategicOpportunityStatus(opportunityId, toOpportunityDto, CancellationToken.None);
|
|
|
|
// Assert
|
|
updateResult.Should().BeTrue("Update should be successful");
|
|
|
|
var strataId = TestUtilities.GetClaimsPrincipalAccessor()?.GetCurrentClaimsPrincipal().GetStrataId();
|
|
var opportunityAfterUpdate = await CentralDbContext.StrategicOpportunityChargeCodes
|
|
.FirstOrDefaultAsync(x => x.OpportunityId == opportunityId && x.StrataId == strataId, CancellationToken.None);
|
|
|
|
opportunityAfterUpdate.Should().NotBeNull("Updated opportunity should exist");
|
|
opportunityAfterUpdate.Status.Should().Be((byte)StrategicOpportunityStatus.NewOpportunity, "Status should be reset to NewOpportunity");
|
|
opportunityAfterUpdate.TrackingStartDate.Should().Be(default(DateOnly), "TrackingStartDate should be reset to default");
|
|
opportunityAfterUpdate.TrackingEndDate.Should().Be(default(DateOnly), "TrackingEndDate should be reset to default");
|
|
opportunityAfterUpdate.LastRunTrackingDate.Should().BeNull("LastRunTrackingDate should be cleared");
|
|
opportunityAfterUpdate.LastRunTrackingStatus.Should().Be(RunTrackingStatus.None, "LastRunTrackingStatus should be reset to None");
|
|
opportunityAfterUpdate.ProgressToDateActual.Should().Be(0, "ProgressToDateActual should be reset to 0");
|
|
opportunityAfterUpdate.ProgressToDateCommitted.Should().Be(0, "ProgressToDateCommitted should be reset to 0");
|
|
}
|
|
|
|
[Test]
|
|
public async Task UpdateStrategicOpportunityStatus_WhenOtherStatus_ShouldOnlyUpdateStatus()
|
|
{
|
|
// Arrange
|
|
var opportunity = CreateOpportunityDto();
|
|
var opportunityId = await _strategicOpportunityService.CreateOpportunityChargeCodeAsync(opportunity, CancellationToken.None);
|
|
|
|
var toInitiativeDto = new StrategicOpportunityUpdateStatusDto
|
|
{
|
|
Status = (byte)StrategicOpportunityStatus.NewInitiative,
|
|
TrackingStartDate = new DateOnly(2024, 1, 1),
|
|
TrackingEndDate = new DateOnly(2024, 12, 31)
|
|
};
|
|
await _strategicOpportunityService.UpdateStrategicOpportunityStatus(opportunityId, toInitiativeDto, CancellationToken.None);
|
|
|
|
var toInValidationDto = new StrategicOpportunityUpdateStatusDto
|
|
{
|
|
Status = (byte)StrategicOpportunityStatus.InValidation
|
|
};
|
|
|
|
// Act
|
|
var updateResult = await _strategicOpportunityService.UpdateStrategicOpportunityStatus(opportunityId, toInValidationDto, CancellationToken.None);
|
|
|
|
// Assert
|
|
updateResult.Should().BeTrue("Update should be successful");
|
|
|
|
var strataId = TestUtilities.GetClaimsPrincipalAccessor()?.GetCurrentClaimsPrincipal().GetStrataId();
|
|
var opportunityAfterUpdate = await CentralDbContext.StrategicOpportunityChargeCodes
|
|
.FirstOrDefaultAsync(x => x.OpportunityId == opportunityId && x.StrataId == strataId, CancellationToken.None);
|
|
|
|
opportunityAfterUpdate.Should().NotBeNull("Updated opportunity should exist");
|
|
opportunityAfterUpdate.Status.Should().Be((byte)StrategicOpportunityStatus.InValidation, "Status should be updated to InValidation");
|
|
opportunityAfterUpdate.TrackingStartDate.Should().Be(toInitiativeDto.TrackingStartDate, "TrackingStartDate should be unchanged");
|
|
opportunityAfterUpdate.TrackingEndDate.Should().Be(toInitiativeDto.TrackingEndDate, "TrackingEndDate should be unchanged");
|
|
}
|
|
|
|
[Test]
|
|
public async Task UpdateStrategicOpportunityStatus_WhenOpportunityNotFound_ShouldReturnFalse()
|
|
{
|
|
// Arrange
|
|
var nonExistentOpportunityId = long.MaxValue;
|
|
var updateStatusDto = new StrategicOpportunityUpdateStatusDto
|
|
{
|
|
Status = (byte)StrategicOpportunityStatus.NewOpportunity
|
|
};
|
|
|
|
// Act
|
|
var result = await _strategicOpportunityService.UpdateStrategicOpportunityStatus(nonExistentOpportunityId, updateStatusDto, CancellationToken.None);
|
|
|
|
// Assert
|
|
result.Should().BeFalse("Update should return false when the opportunity does not exist");
|
|
}
|
|
|
|
[Test]
|
|
public async Task CopyStrategicOpportunityRoleAssignments_ShouldReturnEmptyList()
|
|
{
|
|
// Arrange
|
|
var opportunity = CreateOpportunityDto();
|
|
var opportunityId = await _strategicOpportunityService.CreateOpportunityChargeCodeAsync(opportunity, CancellationToken.None);
|
|
|
|
// Act
|
|
var newOpportunityId = opportunityId + 1;
|
|
await _opportunityRoleAssignmentService.CopyTo(opportunityId, newOpportunityId, CancellationToken.None);
|
|
|
|
// Assert
|
|
var newRoles = await _opportunityRoleAssignmentService.GetRoleAssignmentsAsync(newOpportunityId, CancellationToken.None);
|
|
|
|
newRoles.Should().BeEmpty();
|
|
}
|
|
|
|
[Test]
|
|
public async Task CopyStrategicOpportunityRoleAssignments_ShouldReturnRoleAssignments()
|
|
{
|
|
// Arrange
|
|
var opportunity = CreateOpportunityDto();
|
|
var opportunityId = await _strategicOpportunityService.CreateOpportunityChargeCodeAsync(opportunity, CancellationToken.None);
|
|
|
|
var roleAssignments = new List<OpportunityRoleAssignmentView>()
|
|
{
|
|
new() { LootId = opportunityId, IdentityGuid = Guid.NewGuid(), IdentityName = "Test1", CanRead = true, CanWrite = false, CanSecure = true },
|
|
new() { LootId = opportunityId, IdentityGuid = Guid.NewGuid(), IdentityName = "Test2", CanRead = false, CanWrite = true, CanSecure = false },
|
|
};
|
|
|
|
await _opportunityRoleAssignmentService.SaveRoleAssignmentsAsync(opportunityId, roleAssignments, CancellationToken.None);
|
|
|
|
// Act
|
|
var newOpportunityId = opportunityId + 1;
|
|
await _opportunityRoleAssignmentService.CopyTo(opportunityId, newOpportunityId, CancellationToken.None);
|
|
|
|
// Assert
|
|
var newRoles = await _opportunityRoleAssignmentService.GetRoleAssignmentsAsync(newOpportunityId, CancellationToken.None);
|
|
|
|
// Verify persisted values
|
|
var retrieved = newRoles.ToList();
|
|
|
|
retrieved.Should().HaveCount(roleAssignments.Count);
|
|
CompareRoleAssignments(retrieved[0], roleAssignments[0]);
|
|
CompareRoleAssignments(retrieved[1], roleAssignments[1]);
|
|
}
|
|
|
|
private static void CompareRoleAssignments(OpportunityRoleAssignmentView item1, OpportunityRoleAssignmentView item2)
|
|
{
|
|
item1.IdentityGuid.Should().Be(item2.IdentityGuid);
|
|
item1.IdentityName.Should().Be(item2.IdentityName);
|
|
item1.CanRead.Should().Be(item2.CanRead);
|
|
item1.CanWrite.Should().Be(item2.CanWrite);
|
|
item1.CanSecure.Should().Be(item2.CanSecure);
|
|
}
|
|
|
|
public string DataSchemaServiceSelectSql = @"SELECT
|
|
""EncounterId"",
|
|
""DischargeDateTime"",
|
|
""EntityID"",
|
|
""PhysicianId"",
|
|
""PrimaryServiceLineId"",
|
|
""CPTCodeCaseTypeFamilyId"",
|
|
""MSDRGCaseTypeFamilyId"",
|
|
""APRDRGCaseTypeFamilyId"",
|
|
""DepartmentId"",
|
|
""PhysicianSpecialtyId"",
|
|
""ChargeCodeID"",
|
|
""CostDriver"",
|
|
""PatientTypeRollup"",
|
|
ZEROIFNULL(""Units"") AS ""Units"",
|
|
ZEROIFNULL(""Cost"") AS ""Cost""
|
|
|
|
FROM (
|
|
SELECT
|
|
""EncounterId"",
|
|
""DischargeDateTime"",
|
|
""EntityID"",
|
|
""PhysicianId"",
|
|
""PrimaryServiceLineId"",
|
|
""CPTCodeCaseTypeFamilyId"",
|
|
""MSDRGCaseTypeFamilyId"",
|
|
""APRDRGCaseTypeFamilyId"",
|
|
""DepartmentId"",
|
|
""PhysicianSpecialtyId"",
|
|
""ChargeCodeID"",
|
|
""CostDriver"",
|
|
""PatientTypeRollup"",
|
|
SUM(""Units"") AS ""Units"",
|
|
SUM(""Cost"") AS ""Cost""
|
|
|
|
FROM (
|
|
SELECT
|
|
DSSPES.encounterid AS ""EncounterId"",
|
|
DSSPES.dischargedatetime AS ""DischargeDateTime"",
|
|
DSSPES.entityid AS ""EntityID"",
|
|
DSSPES.primaryphysicianid AS ""PhysicianId"",
|
|
DSSPES.servicelineid AS ""PrimaryServiceLineId"",
|
|
DSSPES.cptcodecasetypefamilyid AS ""CPTCodeCaseTypeFamilyId"",
|
|
DSSPES.msdrgcasetypefamilyid AS ""MSDRGCaseTypeFamilyId"",
|
|
DSSPES.aprdrgcasetypefamilyid AS ""APRDRGCaseTypeFamilyId"",
|
|
PBLID.departmentid AS ""DepartmentId"",
|
|
PHYSPRIMARY.physicianspecialtyid AS ""PhysicianSpecialtyId"",
|
|
CC.chargecodeid AS ""ChargeCodeID"",
|
|
IFNULL(CC.costdriver::TEXT, '') AS ""CostDriver"",
|
|
IFNULL(EncounterPatientTypeRollup.patienttyperollup::TEXT, '') AS ""PatientTypeRollup"",
|
|
NULL AS ""Cost"",
|
|
SUM(PBLID.unitsofservice) AS ""Units""
|
|
|
|
FROM dss.FactPatientBillingLineItemDetail AS PBLID
|
|
INNER JOIN clientdss.FactPatientEncounterSummary AS DSSPES ON DSSPES.encounterrecordnumber = PBLID.encounterrecordnumber
|
|
LEFT JOIN dss.FactPatientEncounterClinicalIndicator AS DSSPECI ON DSSPECI.encounterid = PBLID.encounterid
|
|
LEFT JOIN CCI.VIEWENCOUNTERPATIENTTYPEROLLUP AS EncounterPatientTypeRollup ON EncounterPatientTypeRollup.encounterid = PBLID.encounterid
|
|
INNER JOIN FW.DIMCHARGECODE AS CC ON CC.chargecodeid = PBLID.chargecodeid
|
|
INNER JOIN DSS.DIMPHYSICIAN AS PHYSPRIMARY ON PHYSPRIMARY.physicianid = DSSPES.primaryphysicianid
|
|
|
|
WHERE
|
|
((DSSPES.dischargedatetime >= :dischargedatetime_Start_0 AND DSSPES.dischargedatetime <= :dischargedatetime_End_1) AND CC.chargecodeid IN (:chargecodeid_2))
|
|
|
|
GROUP BY
|
|
""EncounterId"",
|
|
""DischargeDateTime"",
|
|
""EntityID"",
|
|
""PhysicianId"",
|
|
""PrimaryServiceLineId"",
|
|
""CPTCodeCaseTypeFamilyId"",
|
|
""MSDRGCaseTypeFamilyId"",
|
|
""APRDRGCaseTypeFamilyId"",
|
|
""DepartmentId"",
|
|
""PhysicianSpecialtyId"",
|
|
""ChargeCodeID"",
|
|
""CostDriver"",
|
|
""PatientTypeRollup""
|
|
|
|
UNION ALL
|
|
|
|
SELECT
|
|
DSSPES.encounterid AS ""EncounterId"",
|
|
DSSPES.dischargedatetime AS ""DischargeDateTime"",
|
|
DSSPES.entityid AS ""EntityID"",
|
|
DSSPES.primaryphysicianid AS ""PhysicianId"",
|
|
DSSPES.servicelineid AS ""PrimaryServiceLineId"",
|
|
DSSPES.cptcodecasetypefamilyid AS ""CPTCodeCaseTypeFamilyId"",
|
|
DSSPES.msdrgcasetypefamilyid AS ""MSDRGCaseTypeFamilyId"",
|
|
DSSPES.aprdrgcasetypefamilyid AS ""APRDRGCaseTypeFamilyId"",
|
|
PBLID.departmentid AS ""DepartmentId"",
|
|
PHYSPRIMARY.physicianspecialtyid AS ""PhysicianSpecialtyId"",
|
|
CC.chargecodeid AS ""ChargeCodeID"",
|
|
IFNULL(CC.costdriver::TEXT, '') AS ""CostDriver"",
|
|
IFNULL(EncounterPatientTypeRollup.patienttyperollup::TEXT, '') AS ""PatientTypeRollup"",
|
|
SUM(COSTDETAIL.variabledirectcost) AS ""Cost"",
|
|
NULL AS ""Units""
|
|
|
|
FROM dss.FactPatientCostDetail AS COSTDETAIL
|
|
RIGHT JOIN dss.FactPatientBillingLineItemDetail AS PBLID ON PBLID.rowid = COSTDETAIL.pblidrowid
|
|
INNER JOIN clientdss.FactPatientEncounterSummary AS DSSPES ON DSSPES.encounterrecordnumber = PBLID.encounterrecordnumber
|
|
LEFT JOIN dss.FactPatientEncounterClinicalIndicator AS DSSPECI ON DSSPECI.encounterid = PBLID.encounterid
|
|
LEFT JOIN CCI.VIEWENCOUNTERPATIENTTYPEROLLUP AS EncounterPatientTypeRollup ON EncounterPatientTypeRollup.encounterid = PBLID.encounterid
|
|
INNER JOIN FW.DIMCHARGECODE AS CC ON CC.chargecodeid = PBLID.chargecodeid
|
|
INNER JOIN DSS.DIMPHYSICIAN AS PHYSPRIMARY ON PHYSPRIMARY.physicianid = DSSPES.primaryphysicianid
|
|
|
|
WHERE
|
|
((DSSPES.dischargedatetime >= :dischargedatetime_Start_0 AND DSSPES.dischargedatetime <= :dischargedatetime_End_1) AND CC.chargecodeid IN (:chargecodeid_2))
|
|
|
|
GROUP BY
|
|
""EncounterId"",
|
|
""DischargeDateTime"",
|
|
""EntityID"",
|
|
""PhysicianId"",
|
|
""PrimaryServiceLineId"",
|
|
""CPTCodeCaseTypeFamilyId"",
|
|
""MSDRGCaseTypeFamilyId"",
|
|
""APRDRGCaseTypeFamilyId"",
|
|
""DepartmentId"",
|
|
""PhysicianSpecialtyId"",
|
|
""ChargeCodeID"",
|
|
""CostDriver"",
|
|
""PatientTypeRollup""
|
|
|
|
|
|
)
|
|
|
|
GROUP BY
|
|
""EncounterId"",
|
|
""DischargeDateTime"",
|
|
""EntityID"",
|
|
""PhysicianId"",
|
|
""PrimaryServiceLineId"",
|
|
""CPTCodeCaseTypeFamilyId"",
|
|
""MSDRGCaseTypeFamilyId"",
|
|
""APRDRGCaseTypeFamilyId"",
|
|
""DepartmentId"",
|
|
""PhysicianSpecialtyId"",
|
|
""ChargeCodeID"",
|
|
""CostDriver"",
|
|
""PatientTypeRollup""
|
|
|
|
|
|
)
|
|
|
|
ORDER BY
|
|
""EncounterId"" ASC NULLS FIRST,
|
|
""DischargeDateTime"" ASC NULLS FIRST,
|
|
""EntityID"" ASC NULLS FIRST,
|
|
""PhysicianId"" ASC NULLS FIRST,
|
|
""PrimaryServiceLineId"" ASC NULLS FIRST,
|
|
""CPTCodeCaseTypeFamilyId"" ASC NULLS FIRST,
|
|
""MSDRGCaseTypeFamilyId"" ASC NULLS FIRST,
|
|
""APRDRGCaseTypeFamilyId"" ASC NULLS FIRST,
|
|
""DepartmentId"" ASC NULLS FIRST,
|
|
""PhysicianSpecialtyId"" ASC NULLS FIRST,
|
|
""ChargeCodeID"" ASC NULLS FIRST,
|
|
""CostDriver"" ASC NULLS FIRST,
|
|
""PatientTypeRollup"" ASC NULLS FIRST
|
|
|
|
";
|
|
}
|
|
}
|