This commit is contained in:
Zeeshaun
2026-04-07 13:11:39 -05:00
parent d9931b3c36
commit e37826fe30
184 changed files with 2192 additions and 2196 deletions
@@ -29,6 +29,7 @@ RUN dotnet publish ./source/LCU.API.Internal.MemberPreferencesApi/LCU.API.Intern
# ASP.NET Core # ASP.NET Core
FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine3.20 FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine3.20
RUN apk add --no-cache icu-libs && apk add --no-cache tzdata; RUN apk add --no-cache icu-libs && apk add --no-cache tzdata;
ENV TZ America/Chicago
ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false
ENV ASPNETCORE_ENVIRONMENT=Development ENV ASPNETCORE_ENVIRONMENT=Development
@@ -13,9 +13,8 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="LCU.Api.Internal.FTPLib" Version="2.11.2" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" /> <PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="nunit" Version="4.1.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" /> <PackageReference Include="NUnit3TestAdapter" Version="3.15.1" />
<PackageReference Include="FluentAssertions" Version="5.10.3" /> <PackageReference Include="FluentAssertions" Version="5.10.3" />
<PackageReference Include="Moq" Version="4.13.1" /> <PackageReference Include="Moq" Version="4.13.1" />
@@ -4,61 +4,42 @@ using Moq;
using NUnit.Framework; using NUnit.Framework;
using LCU.API.Internal.MemberPreferencesApiLib.Repositories; using LCU.API.Internal.MemberPreferencesApiLib.Repositories;
using LCU.API.Internal.MemberPreferencesApi.Services.XdiServices; using LCU.API.Internal.MemberPreferencesApi.Services.XdiServices;
using LCU.API.Internal.MemberPreferencesApi.Configuration;
using LCU.Library.Internal.MemberPreferencesApiModels.Entities; using LCU.Library.Internal.MemberPreferencesApiModels.Entities;
using LCU.Library.Internal.MemberPreferencesApiModels.Enums; using LCU.Library.Internal.MemberPreferencesApiModels.Enums;
using LCU.Library.Internal.LcuMassTransitModels;
using LCU.API.Internal.MemberPreferencesApi.MicroApiServices; using LCU.API.Internal.MemberPreferencesApi.MicroApiServices;
namespace LCU.API.Internal.MemberPreferencesApi.IntegrationTests namespace LCU.API.Internal.MemberPreferencesApi.IntegrationTests
{ {
public class XdiTransferTest public class XdiBatchItemTest
{ {
private IXdiBatchService _xdiBatchItemService; private IXdiBatchService _xdiBatchItemService;
private Mock<IXdiBatchItemsRepository> _mockBatchItemsRepository; private Mock<IXdiBatchItemsRepository> _mockBatchItemsRepository;
private Mock<IUnitOfWork> _mockUnitOfWork; private Mock<IUnitOfWork> _mockUnitOfWork;
private XdiSftpApiConfiguration _xdiSftpConfiguration;
private FtpApiConfiguration _ftpConfiguration;
private Mock<IUnifiedOptInRepository> _mockUnifiedOptinRepository; private Mock<IUnifiedOptInRepository> _mockUnifiedOptinRepository;
private Mock<IMemberPreferenceRepository> _mockMemberPreferenceRepository; private Mock<IMemberPreferenceRepository> _mockMemberPreferenceRepository;
private Mock<IFtpApiService> _mockFtpApiService; private Mock<IFileOperationsApiService> _mockFileOperationsApiService;
private ConnectionConfiguration _connectionConfiguration; private IMock<IXdiBatchProcessInfoRepository> _mockXdiBatchProcessInfoRepository;
private ReceiveEndpointConfiguration _completionReceiveEndpoint;
private ReceiveEndpointConfigurations _endpointConfiguration;
[SetUp] [SetUp]
public void Setup() public void Setup()
{ {
_mockFtpApiService = new Mock<IFtpApiService>(); _mockFileOperationsApiService = new Mock<IFileOperationsApiService>();
_connectionConfiguration = new ConnectionConfiguration();
_mockBatchItemsRepository = new Mock<IXdiBatchItemsRepository>();
_mockMemberPreferenceRepository = new Mock<IMemberPreferenceRepository>();
_endpointConfiguration = new ReceiveEndpointConfigurations();
_completionReceiveEndpoint = _endpointConfiguration.XdiBatchConfirmEndpoint;
_mockUnitOfWork = new Mock<IUnitOfWork>();
_ftpConfiguration = new FtpApiConfiguration()
{
Url = "https://qa-ftpapi.lcu-internal.com/api/"
};
_xdiSftpConfiguration = new XdiSftpApiConfiguration()
{
HostName = "sftp.xdi.com",
UserName = "LANDMARKCU",
PortNumber = 22,
Password = "FILLMEIN",
Fingerprint = "ssh-dss 2048 12:78:33:0a:cf:71:21:e2:8b:0e:ef:6a:8a:c6:8e:4f"
};
_mockUnifiedOptinRepository = new Mock<IUnifiedOptInRepository>(); _mockUnifiedOptinRepository = new Mock<IUnifiedOptInRepository>();
_mockBatchItemsRepository = new Mock<IXdiBatchItemsRepository>();
_mockXdiBatchProcessInfoRepository = new Mock<IXdiBatchProcessInfoRepository>();
_mockUnitOfWork = new Mock<IUnitOfWork>();
_mockUnifiedOptinRepository = new Mock<IUnifiedOptInRepository>();
_mockMemberPreferenceRepository = new Mock<IMemberPreferenceRepository>();
_mockFileOperationsApiService = new Mock<IFileOperationsApiService>();
_xdiBatchItemService = new XdiBatchService(_mockBatchItemsRepository.Object, _mockUnitOfWork.Object, _xdiBatchItemService = new XdiBatchService(_mockBatchItemsRepository.Object, _mockUnitOfWork.Object,
_xdiSftpConfiguration, _mockUnifiedOptinRepository.Object, _mockMemberPreferenceRepository.Object, _mockUnifiedOptinRepository.Object, _mockMemberPreferenceRepository.Object,
_connectionConfiguration, _endpointConfiguration, _mockFtpApiService.Object); _mockFileOperationsApiService.Object, _mockXdiBatchProcessInfoRepository.Object);
} }
[Test]
[Ignore("This will actually create the items and FTP them to XDI Test Folder. Be Careful. Fill in password.")] public void Test_XdiBatchItem_Setup()
public void Test_Send_Test_Files()
{ {
IReadOnlyCollection<XdiBatchItem> items = new List<XdiBatchItem>() IReadOnlyCollection<XdiBatchItem> items = new List<XdiBatchItem>()
{ {
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
@@ -9,11 +9,11 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.8.0" /> <PackageReference Include="FluentAssertions" Version="6.8.0" />
<PackageReference Include="LCU.Api.Internal.FTPLib" Version="2.11.2" />
<PackageReference Include="LCU.Library.Internal.CoreApiWrapperModel" Version="2.27.14" /> <PackageReference Include="LCU.Library.Internal.CoreApiWrapperModel" Version="2.27.14" />
<PackageReference Include="LCU.Library.Internal.LcuClassPatterns.CrudTests" Version="1.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="7.0.5" /> <PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="7.0.5" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
<PackageReference Include="Moq" Version="4.18.3" /> <PackageReference Include="Moq" Version="4.18.4" />
<PackageReference Include="NUnit" Version="3.12.0" /> <PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" /> <PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
</ItemGroup> </ItemGroup>
@@ -1,130 +1,35 @@
using LCU.API.Internal.MemberPreferencesApi.Interfaces;
using LCU.API.Internal.MemberPreferencesApi.MicroApiServices;
using LCU.API.Internal.MemberPreferencesApi.Services.DnaAuditServices;
using LCU.API.Internal.MemberPreferencesApiLib.Repositories;
using LCU.Library.Internal.LCUServiceFactory.Services;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Linq;
using LCU.Library.Internal.MemberPreferencesApiModels.Entities;
using LCU.Library.Internal.MemberPreferencesApiModels.Enums;
using LCU.API.Internal.MemberPreferencesApi.Services.QueueServices;
using LCU.API.Internal.MemberPreferencesApi.Interfaces;
using LCU.API.Internal.MemberPreferencesApi.Configuration;
using LCU.API.Internal.MemberPreferencesApiLib.Repositories;
using LCU.API.Internal.MemberPreferencesApi.Services.DnaAuditServices;
using LCU.API.Internal.MemberPreferencesApi.MicroApiServices;
namespace LCU.API.Internal.MemberPreferencesApi.UnitTests.Services namespace LCU.API.Internal.MemberPreferencesApi.UnitTests.Services
{ {
public class DNADataAuditProcessServiceTest public class DNADataAuditProcessServiceTest
{ {
private Mock<ICoreApiWrapperService> _coreApiWrapperServiceMock; private Mock<ICoreApiWrapperService> _coreApiWrapperServiceMock;
private Mock<IQueueDnaAccountAuditService> _queueAccountMock; private Mock<IScanBiCoreApiWrapperService> _scanBiCoreApiWrapperServiceMock;
private Mock<IQueueDnaAgreementAuditService> _queueAgreementMock;
private Mock<IQueueDnaOrganizationAuditService> _queueOrganizationMock;
private Mock<IDnaAuditProcessRepository> _dnaAuditProcessRepositoryMock; private Mock<IDnaAuditProcessRepository> _dnaAuditProcessRepositoryMock;
private DNADataAuditProcessService _service; private DNADataAuditProcessService _service;
private Mock<IDateTime> _dateTimeMock; private Mock<IDateTime> _dateTimeMock;
private DnaAuditProcessConfiguration _config; private Mock<ILcuServiceFactory<IDNAAuditCheckService>> _serviceFactoryMock;
[SetUp] [SetUp]
public void Setup() public void Setup()
{ {
_dateTimeMock = new Mock<IDateTime>(); _dateTimeMock = new Mock<IDateTime>();
_config = new DnaAuditProcessConfiguration();
_coreApiWrapperServiceMock = new Mock<ICoreApiWrapperService>(); _coreApiWrapperServiceMock = new Mock<ICoreApiWrapperService>();
_queueAccountMock = new Mock<IQueueDnaAccountAuditService>(); _scanBiCoreApiWrapperServiceMock = new Mock<IScanBiCoreApiWrapperService>();
_queueAgreementMock = new Mock<IQueueDnaAgreementAuditService>();
_queueOrganizationMock = new Mock<IQueueDnaOrganizationAuditService>();
_dnaAuditProcessRepositoryMock = new Mock<IDnaAuditProcessRepository>(); _dnaAuditProcessRepositoryMock = new Mock<IDnaAuditProcessRepository>();
_service = new DNADataAuditProcessService(_queueAccountMock.Object, _queueAgreementMock.Object, _queueOrganizationMock.Object, _serviceFactoryMock = new Mock<ILcuServiceFactory<IDNAAuditCheckService>>();
_coreApiWrapperServiceMock.Object, _dateTimeMock.Object, _dnaAuditProcessRepositoryMock.Object, _config); _service = new DNADataAuditProcessService(_coreApiWrapperServiceMock.Object,
} _scanBiCoreApiWrapperServiceMock.Object,
_dateTimeMock.Object,
[Test] _dnaAuditProcessRepositoryMock.Object,
public async Task RunDnaAuditProcessesChange_HandleProcessUpdate_Ok() _serviceFactoryMock.Object);
{
var processlistAccount = new List<DnaAuditProcess>
{
new DnaAuditProcess()
{
ConsecutiveFailures = 0,
DnaProcessType = DnaAuditProcessType.DNAAccounts,
LastUpdated = DateTime.Now,
ProcessId = 0,
}
};
var processlistAgreement = new List<DnaAuditProcess>
{
new DnaAuditProcess()
{
ConsecutiveFailures = 0,
DnaProcessType = DnaAuditProcessType.DNAAgreement,
LastUpdated = DateTime.Now,
ProcessId = 0,
}
};
var processlistOrg = new List<DnaAuditProcess>
{
new DnaAuditProcess()
{
ConsecutiveFailures = 0,
DnaProcessType = DnaAuditProcessType.DNAOrganization,
LastUpdated = DateTime.Now,
ProcessId = 0,
}
};
await _service.RunDataAuditProcesses();
await _service.AuditDNAAccountsForTimePeriod(DateTime.Now, processlistAccount.First());
var resultAccount = _service.HandleDnaAuditProcessSuccess(processlistAccount.First());
await _service.AuditDNAAgreementForTimePeriod(DateTime.Now, processlistAgreement.First());
var resultAgreement = _service.HandleDnaAuditProcessSuccess(processlistAgreement.First());
await _service.AuditDNAOrganizationForTimePeriod(DateTime.Now, processlistOrg.First());
var resultOrg = _service.HandleDnaAuditProcessSuccess(processlistOrg.First());
//assert
Assert.NotNull(resultAccount);
Assert.AreEqual(resultAccount.DnaProcessType, DnaAuditProcessType.DNAAccounts);
Assert.AreEqual(resultAccount.ConsecutiveFailures, 0);
Assert.NotNull(resultAgreement);
Assert.AreEqual(resultAgreement.DnaProcessType, DnaAuditProcessType.DNAAgreement);
Assert.AreEqual(resultAgreement.ConsecutiveFailures, 0);
Assert.NotNull(resultOrg);
Assert.AreEqual(resultOrg.DnaProcessType, DnaAuditProcessType.DNAOrganization);
Assert.AreEqual(resultOrg.ConsecutiveFailures, 0);
}
[Test]
public async Task RunDnaAuditProcessesChange_HandleProcessUpdateException_Ok()
{
var processlistAccount = new List<DnaAuditProcess>
{
new DnaAuditProcess()
{
ConsecutiveFailures = 0,
DnaProcessType = DnaAuditProcessType.DNAAccounts,
LastUpdated = DateTime.Now,
ProcessId = 0,
}
};
var ex = new Exception();
await _service.RunDataAuditProcesses();
await _service.AuditDNAAccountsForTimePeriod(DateTime.Now, processlistAccount.First());
var resultAccount = _service.HandleDnaAuditProcessException(processlistAccount.First(), ex);
//assert
Assert.NotNull(resultAccount);
Assert.AreEqual(resultAccount.DnaProcessType, DnaAuditProcessType.DNAAccounts);
Assert.AreEqual(resultAccount.ConsecutiveFailures, 1);
} }
} }
} }
@@ -1,223 +0,0 @@
using Moq;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using LCU.API.Internal.MemberPreferencesApi.Services;
using LCU.Library.Internal.MemberPreferencesApiModels.Entities;
using LCU.Library.Internal.MemberPreferencesApiModels.Enums;
using LCU.Library.Internal.CoreApiWrapperModel.CoreModels.Agreements;
using LCU.API.Internal.MemberPreferencesApi.Services.DnaAuditServices;
using LCU.API.Internal.MemberPreferencesApi.MicroApiServices;
using LCU.API.Internal.MemberPreferencesApi.Models.Requests;
namespace LCU.API.Internal.MemberPreferencesApi.UnitTests.Services
{
public class DNADataAuditServiceTest
{
private Mock<ICoreApiWrapperService> _coreApiWrapperServiceMock;
private Mock<IOptinService> _optinServiceMock;
private DNADataAuditService _service;
[SetUp]
public void Setup()
{
_coreApiWrapperServiceMock = new Mock<ICoreApiWrapperService>();
_optinServiceMock = new Mock<IOptinService>();
_service = new DNADataAuditService(_coreApiWrapperServiceMock.Object, _optinServiceMock.Object);
}
[Test]
public async Task HandleChangedFields_AccountChange_OK_UPDATE()
{
var account = new AgreementAccount
{
AccountNumber = 123456,
OvrDeliveryMethCD = "PRNT",
AccountOwner = new AgreementAccountOwner
{
AccountNumber = 123456,
AgreementNumber = 222,
PersonNumber = 123,
UserId = "1234"
}
};
var memberOptinSettings = new MemberOptInSettings
{
EStatements = null,
UniversalOptIn = "Electronic"
};
//setup
_coreApiWrapperServiceMock.Setup(x => x.GetAgreementAccountByAccountId(123456)).ReturnsAsync(account).Verifiable();
_optinServiceMock.Setup(x => x.GetMemberOptInSettings("1234")).ReturnsAsync(memberOptinSettings).Verifiable();
var request = new DnaFieldChangeRequest()
{
ConsecutiveFailures = 0,
DnaFieldIdInformation = 123456L,
DnaProcessType = DnaAuditProcessType.DNAAgreement,
LastUpdated = DateTime.Now,
ProcessId = 1
};
await _service.HandleAccountAuditCheck(request);
//assert
_coreApiWrapperServiceMock.Verify(x => x.UpdateAgreementAccountsDeliveryMethod(It.Is<List<long>>(list => list.Contains(123456)), It.Is<string>(x => x.Equals("WWW")), It.Is<string>(x => x.Equals("1234"))), Times.Once);
_coreApiWrapperServiceMock.Verify();
_optinServiceMock.Verify();
}
[Test]
public async Task HandleChangedFields_AccountChange_OK_DONTUPDATE()
{
var account = new AgreementAccount
{
AccountNumber = 123456,
OvrDeliveryMethCD = "PRNT",
AccountOwner = new AgreementAccountOwner
{
AccountNumber = 123456,
AgreementNumber = 222,
PersonNumber = 123,
UserId = "1234"
}
};
var memberOptinSettings = new MemberOptInSettings
{
EStatements = null,
UniversalOptIn = "Paper"
};
//setup
_coreApiWrapperServiceMock.Setup(x => x.GetAgreementAccountByAccountId(123456)).ReturnsAsync(account).Verifiable();
_optinServiceMock.Setup(x => x.GetMemberOptInSettings("1234"))
.ReturnsAsync(memberOptinSettings).Verifiable();
var request = new DnaFieldChangeRequest()
{
ConsecutiveFailures = 0,
DnaFieldIdInformation = 123456L,
DnaProcessType = DnaAuditProcessType.DNAAccounts,
LastUpdated = DateTime.Now,
ProcessId = 1
};
await _service.HandleAccountAuditCheck(request);
//assert
_coreApiWrapperServiceMock.Verify(x => x.UpdateAgreementAccountsDeliveryMethod(It.IsAny<List<long>>(), It.IsAny<string>(), It.IsAny<string>()), Times.Never);
_coreApiWrapperServiceMock.Verify();
_optinServiceMock.Verify();
}
[Test]
public async Task HandleChangedFields_AgreementChange_OK_UPDATE()
{
var agreement = new Agreement
{
AgreementNumber = 1127,
PersonNumber = 123,
UserId = "1234"
};
var accounts = new List<AgreementAccount>
{
new AgreementAccount{
AccountNumber = 123456,
OvrDeliveryMethCD = "PRNT",
TaxReportForPersonNumber = 123,
AccountOwner = new AgreementAccountOwner{
AccountNumber = 123456,
AgreementNumber = 1127,
PersonNumber = 123,
UserId = "1234"
}
}
};
var memberOptinSettings = new MemberOptInSettings
{
EStatements = null,
UniversalOptIn = "Electronic"
};
//setup
_coreApiWrapperServiceMock.Setup(x => x.GetAgreementByAgreementId(1127)).ReturnsAsync(agreement).Verifiable();
_coreApiWrapperServiceMock.Setup(x => x.GetAgreementAccountsByUserId("1234")).ReturnsAsync(accounts).Verifiable();
_optinServiceMock.Setup(x => x.GetMemberOptInSettings("1234")).ReturnsAsync(memberOptinSettings).Verifiable();
var request = new DnaFieldChangeRequest()
{
ConsecutiveFailures = 0,
DnaFieldIdInformation = 1127L,
DnaProcessType = DnaAuditProcessType.DNAAgreement,
LastUpdated = DateTime.Now,
ProcessId = 1
};
await _service.HandleAgreementAuditCheck(request);
//assert
_coreApiWrapperServiceMock.Verify(x => x.UpdateAgreementAccountsDeliveryMethod(It.Is<List<long>>(list => list.Contains(123456)), It.Is<string>(x => x.Equals("WWW")), It.Is<string>(x => x.Equals("1234"))), Times.Once);
_coreApiWrapperServiceMock.Verify();
_optinServiceMock.Verify();
}
[Test]
public async Task HandleChangedFields_OrganizationChange_OK_UPDATE()
{
var accounts = new List<AgreementAccount>
{
new AgreementAccount{
AccountNumber = 123456,
TaxReportForOrgNumber = 11267,
OvrDeliveryMethCD = "PRNT",
AccountOwner = new AgreementAccountOwner
{
AccountNumber = 123456,
AgreementNumber = 222,
PersonNumber = 123,
UserId = "1234"
}
}
};
var memberOptinSettings = new MemberOptInSettings
{
EStatements = null,
UniversalOptIn = "Electronic"
};
//setup
_coreApiWrapperServiceMock.Setup(x => x.GetAgreementAccountsByOrganizationId(1126)).ReturnsAsync(accounts).Verifiable();
_optinServiceMock.Setup(x => x.GetMemberOptInSettings("1234")).ReturnsAsync(memberOptinSettings).Verifiable();
var request = new DnaFieldChangeRequest()
{
ConsecutiveFailures = 0,
DnaFieldIdInformation = 1126L,
DnaProcessType = DnaAuditProcessType.DNAAgreement,
LastUpdated = DateTime.Now,
ProcessId = 1
};
//act
await _service.HandleOrganizationAuditCheck(request);
//assert
_coreApiWrapperServiceMock.Verify(x => x.UpdateAgreementAccountsDeliveryMethod(It.Is<List<long>>(list => list.Contains(123456)), It.Is<string>(x => x.Equals("WWW")), It.Is<string>(x => x.Equals("1234"))), Times.Once);
_coreApiWrapperServiceMock.Verify();
_optinServiceMock.Verify();
}
}
}
@@ -1,48 +1,45 @@
using System; using LCU.API.Internal.MemberPreferencesApi.MicroApiServices;
using System.Collections.Generic; using LCU.API.Internal.MemberPreferencesApi.Models;
using System.Threading.Tasks; using LCU.API.Internal.MemberPreferencesApi.Models.Requests;
using LCU.API.Internal.MemberPreferencesApi.Configuration; using LCU.API.Internal.MemberPreferencesApi.Services.XdiServices;
using LCU.API.Internal.MemberPreferencesApiLib.Repositories;
using LCU.Library.Internal.LcuClassPatterns.CrudTests.Tests;
using LCU.Library.Internal.LcuClassPatterns.CrudTests.Utilities;
using LCU.Library.Internal.MemberPreferencesApiModels.Entities; using LCU.Library.Internal.MemberPreferencesApiModels.Entities;
using LCU.Library.Internal.MemberPreferencesApiModels.Enums; using LCU.Library.Internal.MemberPreferencesApiModels.Enums;
using LCU.Library.Internal.LcuMassTransitModels;
using LCU.API.Internal.MemberPreferencesApiLib.Repositories;
using LCU.API.Internal.MemberPreferencesApi.Services.XdiServices;
using LCU.API.Internal.MemberPreferencesApi.MicroApiServices;
using Moq; using Moq;
using Newtonsoft.Json; using Newtonsoft.Json;
using NUnit.Framework; using NUnit.Framework;
using LCU.API.Internal.MemberPreferencesApi.Models; using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace LCU.API.Internal.MemberPreferencesApi.UnitTests.Services namespace LCU.API.Internal.MemberPreferencesApi.UnitTests.Services
{ {
public class XdiBatchItemServiceTest public class XdiBatchItemServiceTest : CrudServiceTest<XdiBatchProcessInfo>
{ {
private IXdiBatchService _xdiBatchItemService; private IXdiBatchService _xdiBatchItemService;
private Mock<IXdiBatchItemsRepository> _mockBatchItemsRepository; private Mock<IXdiBatchItemsRepository> _mockBatchItemsRepository;
private Mock<IXdiBatchProcessInfoRepository> _mockXdiBatchProcessInfoRepository;
private Mock<IUnitOfWork> _mockUnitOfWork; private Mock<IUnitOfWork> _mockUnitOfWork;
private XdiSftpApiConfiguration _ftpConfiguration;
private Mock<IUnifiedOptInRepository> _mockUnifiedOptinRepository; private Mock<IUnifiedOptInRepository> _mockUnifiedOptinRepository;
private Mock<IMemberPreferenceRepository> _mockMemberPreferenceRepository; private Mock<IMemberPreferenceRepository> _mockMemberPreferenceRepository;
private Mock<IFtpApiService> _mockFtpApiService; private Mock<IFileOperationsApiService> _mockFileOperationsApiService;
private ConnectionConfiguration _connectionConfiguration;
private ReceiveEndpointConfiguration _completionReceiveEndpoint;
private ReceiveEndpointConfigurations _endpointConfiguration;
[SetUp] [SetUp]
public void Setup() public void Setup()
{ {
_mockBatchItemsRepository = new Mock<IXdiBatchItemsRepository>(); _mockBatchItemsRepository = new Mock<IXdiBatchItemsRepository>();
_mockXdiBatchProcessInfoRepository = new Mock<IXdiBatchProcessInfoRepository>();
_mockUnitOfWork = new Mock<IUnitOfWork>(); _mockUnitOfWork = new Mock<IUnitOfWork>();
_ftpConfiguration = new XdiSftpApiConfiguration();
_mockUnifiedOptinRepository = new Mock<IUnifiedOptInRepository>(); _mockUnifiedOptinRepository = new Mock<IUnifiedOptInRepository>();
_mockMemberPreferenceRepository = new Mock<IMemberPreferenceRepository>(); _mockMemberPreferenceRepository = new Mock<IMemberPreferenceRepository>();
_mockFtpApiService = new Mock<IFtpApiService>(); _mockFileOperationsApiService = new Mock<IFileOperationsApiService>();
_endpointConfiguration = new ReceiveEndpointConfigurations();
_completionReceiveEndpoint = _endpointConfiguration.XdiBatchConfirmEndpoint;
_xdiBatchItemService = new XdiBatchService(_mockBatchItemsRepository.Object, _mockUnitOfWork.Object, _xdiBatchItemService = new XdiBatchService(_mockBatchItemsRepository.Object, _mockUnitOfWork.Object,
_ftpConfiguration, _mockUnifiedOptinRepository.Object, _mockMemberPreferenceRepository.Object, _mockUnifiedOptinRepository.Object, _mockMemberPreferenceRepository.Object,
_connectionConfiguration, _endpointConfiguration, _mockFtpApiService.Object); _mockFileOperationsApiService.Object, _mockXdiBatchProcessInfoRepository.Object);
} }
[Test] [Test]
@@ -226,7 +223,7 @@ namespace LCU.API.Internal.MemberPreferencesApi.UnitTests.Services
} }
[Test] [Test]
public async Task CreateFtpQueryPayload_Ok() public async Task CreateXdiBatchExport_MultipleResults_Ok()
{ {
var testFile = new XdiBatchFile var testFile = new XdiBatchFile
{ {
@@ -308,7 +305,26 @@ namespace LCU.API.Internal.MemberPreferencesApi.UnitTests.Services
UniversalOptIn = DeliveryPreference.Hold UniversalOptIn = DeliveryPreference.Hold
}); });
var results = await _xdiBatchItemService.CreateFtpPayload(testFile); var xdiBatchProcessInfo = new List<XdiBatchProcessInfo>
{
new()
{
XdiBatchProcessInfoId = (int)typeof(int).GetRandomValue(),
StartTimeStamp = DateTime.Now,
XdiBatchProcessStatus = XdiBatchProcessStatus.InProgress,
ApiResponse = "Started"
}
};
var request = new XdiBatchRequest()
{
XdiAppendFileRootBasePath = "test/test"
};
_mockXdiBatchProcessInfoRepository.Setup(x => x.FindBatchProcessInfoByStatus(XdiBatchProcessStatus.InProgress)).ReturnsAsync(xdiBatchProcessInfo)
.Verifiable();
var results = await _xdiBatchItemService.BuildXdiFiles(testFile, request.XdiAppendFileRootBasePath, xdiBatchProcessInfo.FirstOrDefault());
Assert.AreEqual(4, results.Count); Assert.AreEqual(4, results.Count);
Assert.True(results.Exists(x => x.UserId == "100" && x.Value == "[email protected]")); Assert.True(results.Exists(x => x.UserId == "100" && x.Value == "[email protected]"));
@@ -318,7 +334,7 @@ namespace LCU.API.Internal.MemberPreferencesApi.UnitTests.Services
} }
[Test] [Test]
public async Task CreateFtpQueryPayload_No_Result_Ok() public async Task CreateXdiBatchExport_Result_Ok()
{ {
var testFile = new XdiBatchFile var testFile = new XdiBatchFile
{ {
@@ -331,6 +347,17 @@ namespace LCU.API.Internal.MemberPreferencesApi.UnitTests.Services
} }
}; };
var xdiBatchProcessInfo = new List<XdiBatchProcessInfo>
{
new()
{
XdiBatchProcessInfoId = (int)typeof(int).GetRandomValue(),
StartTimeStamp = DateTime.Now,
XdiBatchProcessStatus = XdiBatchProcessStatus.InProgress,
ApiResponse = "Started"
}
};
_mockUnifiedOptinRepository _mockUnifiedOptinRepository
.Setup(x => x.GetMemberOptInSettingsNoTracking("100")).ReturnsAsync(new MemberOptInSettings .Setup(x => x.GetMemberOptInSettingsNoTracking("100")).ReturnsAsync(new MemberOptInSettings
{ {
@@ -341,8 +368,16 @@ namespace LCU.API.Internal.MemberPreferencesApi.UnitTests.Services
_mockUnifiedOptinRepository _mockUnifiedOptinRepository
.Setup(x => x.GetMemberOptInSettingsNoTracking(It.Is<string>(userId => int.Parse(userId) > 100))) .Setup(x => x.GetMemberOptInSettingsNoTracking(It.Is<string>(userId => int.Parse(userId) > 100)))
.Returns(Task.FromResult<MemberOptInSettings>(null)); .Returns(Task.FromResult<MemberOptInSettings>(null));
var results = await _xdiBatchItemService.CreateFtpPayload(testFile); _mockXdiBatchProcessInfoRepository.Setup(x => x.FindBatchProcessInfoByStatus(XdiBatchProcessStatus.InProgress)).ReturnsAsync(xdiBatchProcessInfo)
.Verifiable();
var request = new XdiBatchRequest()
{
XdiAppendFileRootBasePath = "test/test"
};
var results = await _xdiBatchItemService.BuildXdiFiles(testFile, request.XdiAppendFileRootBasePath, xdiBatchProcessInfo.FirstOrDefault());
Assert.AreEqual(1, results.Count); Assert.AreEqual(1, results.Count);
Assert.True(results.Exists(x => x.UserId == "100" && x.Value == DeliveryPreference.Paper)); Assert.True(results.Exists(x => x.UserId == "100" && x.Value == DeliveryPreference.Paper));
@@ -351,20 +386,20 @@ namespace LCU.API.Internal.MemberPreferencesApi.UnitTests.Services
[Test] [Test]
public async Task MarkPendingSuccessful_OK() public async Task MarkPendingSuccessful_OK()
{ {
var payload = new List<FtpQueuePayloadItem>() var batchFileExportList = new List<XdiBatchFileExport>()
{ {
new FtpQueuePayloadItem() new XdiBatchFileExport()
{ {
UserId = "100", UserId = "100",
Value = DeliveryPreference.Paper Value = DeliveryPreference.Paper
}, },
new FtpQueuePayloadItem() new XdiBatchFileExport()
{ {
UserId = "101", UserId = "101",
Value = "[email protected]" Value = "[email protected]"
} }
}; };
var payloadString = JsonConvert.SerializeObject(payload); var payloadString = JsonConvert.SerializeObject(batchFileExportList);
var response = new LCU.Library.Internal.ApiResponse.Models.Response() var response = new LCU.Library.Internal.ApiResponse.Models.Response()
{ {
@@ -381,7 +416,7 @@ namespace LCU.API.Internal.MemberPreferencesApi.UnitTests.Services
_mockBatchItemsRepository.Setup(x => x.MarkPendingSuccessful(It.IsAny<List<string>>())).ReturnsAsync(true) _mockBatchItemsRepository.Setup(x => x.MarkPendingSuccessful(It.IsAny<List<string>>())).ReturnsAsync(true)
.Verifiable(); .Verifiable();
var result = await _xdiBatchItemService.MarkPendingSuccessful(response); var result = await _xdiBatchItemService.MarkPendingSuccessful(batchFileExportList);
Assert.True(result); Assert.True(result);
@@ -47,7 +47,7 @@ namespace LCU.API.Internal.MemberPreferencesApi.UnitTests.XdiBatch
var results = newFile.ConvertToDataFile(); var results = newFile.ConvertToDataFile();
Assert.NotNull(fileName); Assert.NotNull(fileName);
Assert.AreEqual("Enrollment_AddElectronic_LMCU.txt", fileName); Assert.AreEqual("Enrollment_AddElectronic_LMCU", fileName);
Assert.NotNull(results); Assert.NotNull(results);
Assert.NotNull(stringResults); Assert.NotNull(stringResults);
@@ -1,6 +1,6 @@
namespace LCU.API.Internal.MemberPreferencesApi.Configuration; namespace LCU.API.Internal.MemberPreferencesApi.Configuration;
public class CoreApiWrapperConfiguration public class CoreApiWrapperConfiguration
{ {
public string CoreApiBaseUrl { get; set; } public string CoreApiBaseUrl { get; set; }
public string CoreApiGetAgreementByUserId { get; set; } public string CoreApiGetAgreementByUserId { get; set; }
@@ -11,6 +11,5 @@ public class CoreApiWrapperConfiguration
public string CoreApiGetAgreementAccountsByOrganizationId { get; set; } public string CoreApiGetAgreementAccountsByOrganizationId { get; set; }
public string CoreApiGetAuditAccountsFromDateLastMaintained { get; set; } public string CoreApiGetAuditAccountsFromDateLastMaintained { get; set; }
public string CoreApiGetAuditAgreementFromDateLastMaintained { get; set; } public string CoreApiGetAuditAgreementFromDateLastMaintained { get; set; }
public string CoreApiGetAuditOrganizationFromDateLastMaintained { get; set; }
public string CoreApiUpdateAccountsMaintenanceRequest { get; set; } public string CoreApiUpdateAccountsMaintenanceRequest { get; set; }
} }
@@ -1,7 +0,0 @@
namespace LCU.API.Internal.MemberPreferencesApi.Configuration;
public class DnaAuditProcessConfiguration
{
public int LookBackMinutes { get; set; }
public int NumberOfAllowedConsecutiveFailures { get; set; }
}
@@ -1,11 +1,7 @@
namespace LCU.API.Internal.MemberPreferencesApi.Configuration; namespace LCU.API.Internal.MemberPreferencesApi.Configuration;
public class FeatureFlags public class FeatureFlags
{ {
public bool RunHostedServices { get; set; }
public bool RunXdiBatchProcessConsumer { get; set; } public bool RunXdiBatchProcessConsumer { get; set; }
public bool RunXdiSshResponseConsumer { get; set; } public bool RunDnaAuditProcessConsumer { get; set; }
public bool RunAccountDnaFieldChangeConsumer { get; set; }
public bool RunAgreementDnaFieldChangeConsumer { get; set; }
public bool RunOrganizationDnaFieldChangeConsumer { get; set; }
} }
@@ -0,0 +1,11 @@
using System.ComponentModel.DataAnnotations.Schema;
namespace LCU.API.Internal.MemberPreferencesApi.Configuration;
public class FileOperationsApiConfiguration
{
public string Url { get; set; }
public string AppendFile { get; set; }
[NotMapped]
public string AppendFileUrl => Url + AppendFile;
}
@@ -1,11 +0,0 @@
using System.ComponentModel.DataAnnotations.Schema;
namespace LCU.API.Internal.MemberPreferencesApi.Configuration;
public class FtpApiConfiguration
{
public string Url { get; set; }
public string QueueSshFtpRequestEndpoint { get; set; }
[NotMapped]
public string QueueSshFtpRequestEndpointUrl => Url + QueueSshFtpRequestEndpoint;
}
@@ -6,8 +6,6 @@ public class ReceiveEndpointConfigurations
{ {
public ReceiveEndpointConfiguration XdiBatchProcessEndpoint { get; set; } public ReceiveEndpointConfiguration XdiBatchProcessEndpoint { get; set; }
public ReceiveEndpointConfiguration XdiBatchConfirmEndpoint { get; set; } public ReceiveEndpointConfiguration XdiBatchConfirmEndpoint { get; set; }
public ReceiveEndpointConfiguration DnaAccountAuditEndpoint { get; set; } public ReceiveEndpointConfiguration DnaAuditProcessEndpoint { get; set; }
public ReceiveEndpointConfiguration DnaOrganizationAuditEndpoint { get; set; }
public ReceiveEndpointConfiguration DnaAgreementAuditEndpoint { get; set; }
} }
@@ -0,0 +1,12 @@
using System.ComponentModel.DataAnnotations.Schema;
namespace LCU.API.Internal.MemberPreferencesApi.Configuration
{
public class ScanBiCoreApiWrapperConfiguration
{
public string ScanBiCoreApiWrapperUrl { get; set; }
public string GetAuditOrganizationFromDateLastMaintainedEndpoint { get; set; }
[NotMapped]
public string GetAuditOrganizationFromDateLastMaintainedUrl => ScanBiCoreApiWrapperUrl + GetAuditOrganizationFromDateLastMaintainedEndpoint;
}
}
@@ -1,11 +0,0 @@
namespace LCU.API.Internal.MemberPreferencesApi.Configuration;
public class XdiSftpApiConfiguration
{
public string HostName { get; set; }
public int PortNumber { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string Fingerprint { get; set; }
public string SftpRootBasePath { get; set; }
}
@@ -1,43 +0,0 @@
using LCU.API.Internal.MemberPreferencesApi.Services.DnaAuditServices;
using MassTransit;
namespace LCU.API.Internal.MemberPreferencesApi.Consumers;
public class AccountDnaFieldChangeConsumer : IConsumer<DnaFieldChangeRequest>
{
private readonly IServiceScopeFactory _scopeFactory;
public AccountDnaFieldChangeConsumer(IServiceScopeFactory scopeFactory)
{
_scopeFactory = scopeFactory;
}
public async Task Consume(ConsumeContext<DnaFieldChangeRequest> context)
{
try
{
Log.Debug("Starting AccountDnaFieldChangeConsumer.");
Log.Information($"New Account Received for: {context.Message.DnaProcessType} Process - {context.Message.DnaFieldIdInformation}");
using var scope = _scopeFactory.CreateScope();
await Task.Run(async () => await scope.ServiceProvider.GetRequiredService<IDNADataAuditService>().HandleAccountAuditCheck(context.Message));
Log.Debug("Ending DnaAccountAuditServiceConsumer.");
}
catch (ServiceException serviceException)
{
Log.ForContext(Enum.GetName(typeof(PropertyEnum), PropertyEnum.Group),
Enum.GetName(typeof(GroupEnum), GroupEnum.ITDevelopment))
.Error(serviceException, $"AccountDnaFieldChangeConsumer Failure. " +
$"The request is placed on AccountDnaFieldChangeConsumer_error.");
throw serviceException;
}
catch (Exception exception)
{
Log.ForContext(Enum.GetName(typeof(PropertyEnum), PropertyEnum.Group),
Enum.GetName(typeof(GroupEnum), GroupEnum.ITDevelopment))
.Fatal(exception, $"Unexpected AccountDnaFieldChangeConsumer Failure. " +
$"The request is placed on AccountDnaFieldChangeConsumer_error.");
throw;
}
}
}
@@ -1,42 +0,0 @@
using LCU.API.Internal.MemberPreferencesApi.Services.DnaAuditServices;
using MassTransit;
namespace LCU.API.Internal.MemberPreferencesApi.Consumers;
public class AgreementDnaFieldChangeConsumer : IConsumer<DnaFieldChangeRequest>
{
private readonly IServiceScopeFactory _scopeFactory;
public AgreementDnaFieldChangeConsumer(IServiceScopeFactory scopeFactory)
{
_scopeFactory = scopeFactory;
}
public async Task Consume(ConsumeContext<DnaFieldChangeRequest> context)
{
try
{
Log.Debug("Starting AgreementDnaFieldChangeConsumer.");
Log.Information($"New Agreement Received for : {context.Message.DnaProcessType} Process - {context.Message.DnaFieldIdInformation}");
using var scope = _scopeFactory.CreateScope();
await Task.Run(async () => await scope.ServiceProvider.GetRequiredService<IDNADataAuditService>().HandleAgreementAuditCheck(context.Message));
Log.Debug("Ending AgreementDnaFieldChangeConsumer.");
}
catch (ServiceException serviceException)
{
Log.ForContext(Enum.GetName(typeof(PropertyEnum), PropertyEnum.Group),
Enum.GetName(typeof(GroupEnum), GroupEnum.ITDevelopment))
.Error(serviceException, $"AgreementDnaFieldChangeConsumer Failure. " +
$"The request is placed on AgreementDnaFieldChangeConsumer_error.");
throw;
}
catch (Exception exception)
{
Log.ForContext(Enum.GetName(typeof(PropertyEnum), PropertyEnum.Group),
Enum.GetName(typeof(GroupEnum), GroupEnum.ITDevelopment))
.Fatal(exception, $"Unexpected AgreementDnaFieldChangeConsumer Failure. " +
$"The TransactionRequest is placed on AgreementDnaFieldChangeConsumer_error.");
throw;
}
}
}
@@ -0,0 +1,41 @@
using LCU.API.Internal.MemberPreferencesApi.Services.DnaAuditServices;
using MassTransit;
namespace LCU.API.Internal.MemberPreferencesApi.Consumers;
public class DnaAuditProcessConsumer : IConsumer<DnaAuditProcessRequest>
{
private readonly IServiceScopeFactory _scopeFactory;
public DnaAuditProcessConsumer(IServiceScopeFactory scopeFactory)
{
_scopeFactory = scopeFactory;
}
public async Task Consume(ConsumeContext<DnaAuditProcessRequest> context)
{
try
{
Log.Debug("Starting DnaAuditProcessConsumer.");
using var scope = _scopeFactory.CreateAsyncScope();
await scope.ServiceProvider.GetRequiredService<IDNADataAuditProcessService>().HandleDnaAuditProcessRequest(context.Message);
Log.Debug("Ending DnaAuditProcessConsumer.");
}
catch (ServiceException serviceException)
{
Log.ForContext(Enum.GetName(typeof(PropertyEnum), PropertyEnum.Group),
Enum.GetName(typeof(GroupEnum), GroupEnum.ITDevelopment))
.Error(serviceException, $"DnaAuditProcess Failure. " +
$"The request is placed on DnaAuditProcess_error.");
throw;
}
catch (Exception exception)
{
Log.ForContext(Enum.GetName(typeof(PropertyEnum), PropertyEnum.Group),
Enum.GetName(typeof(GroupEnum), GroupEnum.ITDevelopment))
.Fatal(exception, $"Unexpected DnaAuditProcess Failure. " +
$"The TransactionRequest is placed on DnaAuditProcess_error.");
throw;
}
}
}
@@ -1,43 +0,0 @@
using LCU.API.Internal.MemberPreferencesApi.Services.DnaAuditServices;
using MassTransit;
namespace LCU.API.Internal.MemberPreferencesApi.Consumers;
public class OrganizationDnaFieldChangeConsumer : IConsumer<DnaFieldChangeRequest>
{
private readonly IServiceScopeFactory _scopeFactory;
public OrganizationDnaFieldChangeConsumer(IServiceScopeFactory scopeFactory)
{
_scopeFactory = scopeFactory;
}
public async Task Consume(ConsumeContext<DnaFieldChangeRequest> context)
{
try
{
Log.Debug("Starting OrganizationDnaFieldChangeConsumer.");
Log.Information($"New Organization Received for: {context.Message.DnaProcessType} Process - {context.Message.DnaFieldIdInformation}");
using var scope = _scopeFactory.CreateScope();
await Task.Run(async () => await scope.ServiceProvider.GetRequiredService<IDNADataAuditService>().HandleOrganizationAuditCheck(context.Message));
Log.Debug("Ending OrganizationDnaFieldChangeConsumer.");
}
catch (ServiceException serviceException)
{
Log.ForContext(Enum.GetName(typeof(PropertyEnum), PropertyEnum.Group),
Enum.GetName(typeof(GroupEnum), GroupEnum.ITDevelopment))
.Error(serviceException, $"OrganizationDnaFieldChangeConsumer Failure. " +
$"The request is placed on OrganizationDnaFieldChangeConsumer_error.");
throw;
}
catch (Exception exception)
{
Log.ForContext(Enum.GetName(typeof(PropertyEnum), PropertyEnum.Group),
Enum.GetName(typeof(GroupEnum), GroupEnum.ITDevelopment))
.Fatal(exception, $"Unexpected OrganizationDnaFieldChangeConsumer Consumer Failure. " +
$"The request is placed on OrganizationDnaFieldChangeConsumer_error.");
throw;
}
}
}
@@ -3,26 +3,26 @@ using MassTransit;
namespace LCU.API.Internal.MemberPreferencesApi.Consumers; namespace LCU.API.Internal.MemberPreferencesApi.Consumers;
public class XdiBatchProcessConsumer : IConsumer<XdiBatchRequest> public class XdiBatchProcessConsumer : IConsumer<XdiBatchProcessRequest>
{ {
private readonly IServiceScopeFactory _scopeFactory; private readonly IServiceScopeFactory _scopeFactory;
public XdiBatchProcessConsumer(IServiceScopeFactory scopeFactory) public XdiBatchProcessConsumer(IServiceScopeFactory scopeFactory)
{ {
_scopeFactory = scopeFactory; _scopeFactory = scopeFactory;
} }
public async Task Consume(ConsumeContext<XdiBatchRequest> context) public async Task Consume(ConsumeContext<XdiBatchProcessRequest> context)
{ {
try try
{ {
using var scope = _scopeFactory.CreateScope(); using var scope = _scopeFactory.CreateScope();
await Task.Run(async () => await scope.ServiceProvider.GetRequiredService<IXdiBatchService>().CreateXdiBatchFiles(context.Message)); await Task.Run(async () => await scope.ServiceProvider.GetRequiredService<IXdiBatchProcessService>().HandleXdiBatchProcess(context.Message));
} }
catch (ServiceException ex) catch (ServiceException ex)
{ {
Log.ForContext(Enum.GetName(typeof(PropertyEnum), PropertyEnum.Group), Log.ForContext(Enum.GetName(typeof(PropertyEnum), PropertyEnum.Group),
Enum.GetName(typeof(GroupEnum), GroupEnum.ITDevelopment)) Enum.GetName(typeof(GroupEnum), GroupEnum.ITDevelopment))
.Error($"XdiBatchProcessConsumer Failure. " + .Error($"XdiBatchProcessConsumer Failure. " +
$"The response is placed on LCU.MemberPreferencesApi.XdiAuditProcess_error. " + $"The response is placed on LCU.MemberPreferencesApi.XdiBatchProcess_error. " +
$"Error Message: {ex.Message}"); $"Error Message: {ex.Message}");
throw; throw;
} }
@@ -31,7 +31,7 @@ public class XdiBatchProcessConsumer : IConsumer<XdiBatchRequest>
Log.ForContext(Enum.GetName(typeof(PropertyEnum), PropertyEnum.Group), Log.ForContext(Enum.GetName(typeof(PropertyEnum), PropertyEnum.Group),
Enum.GetName(typeof(GroupEnum), GroupEnum.ITDevelopment)) Enum.GetName(typeof(GroupEnum), GroupEnum.ITDevelopment))
.Fatal(exception, $"Unexpected XdiBatchProcessConsumer Failure. " + .Fatal(exception, $"Unexpected XdiBatchProcessConsumer Failure. " +
$"The response is placed on LCU.MemberPreferencesApi.XdiAuditProcess_error."); $"The response is placed on LCU.MemberPreferencesApi.XdiBatchProcess_error.");
throw; throw;
} }
} }
@@ -1,39 +0,0 @@
using ApiResponse = LCU.Library.Internal.ApiResponse.Models;
using LCU.API.Internal.MemberPreferencesApi.Services.XdiServices;
using MassTransit;
namespace LCU.API.Internal.MemberPreferencesApi.Consumers;
public class XdiSshResponseConsumer : IConsumer<ApiResponse.Response>
{
private readonly IServiceScopeFactory _scopeFactory;
public XdiSshResponseConsumer(IServiceScopeFactory scopeFactory)
{
_scopeFactory = scopeFactory;
}
public async Task Consume(ConsumeContext<ApiResponse.Response> context)
{
try
{
using var scope = _scopeFactory.CreateScope();
await Task.Run(async () => await scope.ServiceProvider.GetRequiredService<IXdiBatchService>().MarkPendingSuccessful(context.Message));
}
catch (ServiceException ex)
{
Log.ForContext(Enum.GetName(typeof(PropertyEnum), PropertyEnum.Group),
Enum.GetName(typeof(GroupEnum), GroupEnum.ITDevelopment))
.Error($"XdiSshResponseConsumer Failure. " +
$"The ApiResponse.Response is placed on LCU.MemberPreferencesApi.XdiBatchConfirm_error. " +
$"Error Message: {ex.Message}");
throw;
}
catch (Exception exception)
{
Log.ForContext(Enum.GetName(typeof(PropertyEnum), PropertyEnum.Group),
Enum.GetName(typeof(GroupEnum), GroupEnum.ITDevelopment))
.Fatal(exception, $"Unexpected XdiSshResponseConsumer Failure. " +
$"The ApiResponse.Response is placed on LCU.MemberPreferencesApi.XdiBatchConfirm_error.");
throw;
}
}
}
@@ -1,79 +0,0 @@
using LCU.API.Internal.MemberPreferencesApi.Services.QueueServices;
using Microsoft.AspNetCore.Mvc;
namespace LCU.API.Internal.MemberPreferencesApi.Controllers;
[ApiController]
[Route("api/[controller]")]
public class AuditController : ControllerBase
{
private readonly IQueueDnaAccountAuditService _dnaAccountAuditService;
private readonly IQueueDnaOrganizationAuditService _dnaOrganizationAuditService;
private readonly IQueueDnaAgreementAuditService _dnaAgreementAuditService;
public AuditController(IQueueDnaAccountAuditService dnaAccountAuditService,
IQueueDnaOrganizationAuditService dnaOrganizationAuditService,
IQueueDnaAgreementAuditService dnaAgreementAuditService)
{
_dnaAccountAuditService = dnaAccountAuditService;
_dnaOrganizationAuditService = dnaOrganizationAuditService;
_dnaAgreementAuditService = dnaAgreementAuditService;
}
[HttpPost("EnqueueDNAOrganizationAuditRecords")]
[ProducesResponseType(200)]
[ProducesResponseType(400)]
[ProducesResponseType(500)]
public async Task<IActionResult> EnqueueDNAOrganizationAuditRecords([FromBody] List<long> organizationIds)
{
try
{
Log.Information($"Forced {organizationIds.Count} DNAOrganizationAuditRecords to be queued");
await _dnaOrganizationAuditService.QueueDataAuditForOrganizations(organizationIds);
return Ok();
}
catch (Exception ex)
{
Log.Error(ex, $"Failure in {GetType().Name}");
return StatusCode((int) System.Net.HttpStatusCode.InternalServerError);
}
}
[HttpPost("EnqueueDNAAgreementAuditRecords")]
[ProducesResponseType(200)]
[ProducesResponseType(400)]
[ProducesResponseType(500)]
public async Task<IActionResult> EnqueueDNAAgreementAuditRecords([FromBody] List<long> agreementIds)
{
try
{
Log.Information($"Forced {agreementIds.Count} DNAAgreementAuditRecords to be queued");
await _dnaAgreementAuditService.QueueDataAuditForAgreements(agreementIds);
return Ok();
}
catch (Exception ex)
{
Log.Error(ex, $"Failure in {GetType().Name}");
return StatusCode((int) System.Net.HttpStatusCode.InternalServerError);
}
}
[HttpPost("EnqueueDNAAccountAuditRecords")]
[ProducesResponseType(200)]
[ProducesResponseType(400)]
[ProducesResponseType(500)]
public async Task<IActionResult> EnqueueDNAAccountAuditRecords([FromBody] List<long> accountNumbers)
{
try
{
Log.Information($"Forced {accountNumbers.Count} DNAAccountAuditRecords to be queued");
await _dnaAccountAuditService.QueueDataAuditForAccounts(accountNumbers);
return Ok();
}
catch (Exception ex)
{
Log.Error(ex, $"Failure in {GetType().Name}");
return StatusCode((int) System.Net.HttpStatusCode.InternalServerError);
}
}
}
@@ -0,0 +1,39 @@
using LCU.API.Internal.MemberPreferencesApi.Services.QueueServices;
using Microsoft.AspNetCore.Mvc;
using Microsoft.FeatureManagement.Mvc;
namespace LCU.API.Internal.MemberPreferencesApi.Controllers;
[FeatureGate(FeatureGates.EnableControllers)]
[ApiController]
[Route("api/[controller]")]
public class QueueDnaAuditProcessController : ControllerBase
{
private readonly IQueueDnaAuditProcessService _queueDnaAuditProcessService;
public QueueDnaAuditProcessController(IQueueDnaAuditProcessService queueDnaAuditProcessService)
{
_queueDnaAuditProcessService = queueDnaAuditProcessService;
}
[HttpPost]
[ProducesResponseType(200)]
[ProducesResponseType(500)]
public async Task<IActionResult> QueueDnaAuditProcessRequest(DnaAuditProcessRequest request)
{
try
{
await _queueDnaAuditProcessService.QueueDnaAuditProcessRequest(request);
return Ok();
}
catch (ServiceException)
{
return StatusCode(StatusCodes.Status500InternalServerError);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
}
@@ -0,0 +1,37 @@
using LCU.API.Internal.MemberPreferencesApi.Services.QueueServices;
using Microsoft.AspNetCore.Mvc;
namespace LCU.API.Internal.MemberPreferencesApi.Controllers;
[ApiController]
[Route("api/[controller]")]
public class QueueXdiBatchProcessController : ControllerBase
{
private readonly IQueueXdiBatchProcessService _queueXdiBatchProcessService;
public QueueXdiBatchProcessController(IQueueXdiBatchProcessService queueXdiBatchProcessService)
{
_queueXdiBatchProcessService = queueXdiBatchProcessService;
}
[HttpPost]
[ProducesResponseType(200)]
[ProducesResponseType(500)]
public async Task<IActionResult> QueueXdiBatchRequest(XdiBatchProcessRequest request)
{
try
{
await _queueXdiBatchProcessService.QueueXdiBatchProcess(request);
return Ok();
}
catch (ServiceException)
{
return StatusCode(StatusCodes.Status500InternalServerError);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
}
@@ -0,0 +1,44 @@
using LCU.API.Internal.MemberPreferencesApi.Services.XdiServices;
using LCU.Library.Internal.MemberPreferencesApiModels.Entities;
using Microsoft.AspNetCore.Mvc;
namespace LCU.API.Internal.MemberPreferencesApi.Controllers;
[ApiController]
[Route("api/[controller]")]
public class XdiController : ControllerBase
{
private readonly IXdiBatchService _xdiBatchService;
public XdiController(IXdiBatchService xdiBatchService)
{
_xdiBatchService = xdiBatchService;
}
[HttpPost("SaveRange")]
[ProducesResponseType(200)]
[ProducesResponseType(typeof(IEnumerable<XdiBatchItem>), 400)]
[ProducesResponseType(500)]
public async Task<IActionResult> SaveRange([FromBody] List<XdiBatchItem> xdiBatchItems)
{
try
{
if (xdiBatchItems is null || !xdiBatchItems.Any())
{
return BadRequest("XdiBatchItems cannot be null or empty.");
}
Log.Information($"Save {xdiBatchItems.Count} Xdi Batch Items attempted.");
await _xdiBatchService.SaveRangeAsync(xdiBatchItems);
return Ok();
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
}
@@ -41,7 +41,8 @@ public class CoreApiWrapperDao : ICoreApiWrapperDao
public async Task<IEnumerable<Agreement>> GetAgreementsByAccountId(long accountId) public async Task<IEnumerable<Agreement>> GetAgreementsByAccountId(long accountId)
{ {
var path = $"{_coreApiWrapperConfig.CoreApiBaseUrl}{_coreApiWrapperConfig.CoreApiGetAgreementsByAccountId.Replace("{accountId}", accountId.ToString())}"; var path = $"{_coreApiWrapperConfig.CoreApiBaseUrl}{_coreApiWrapperConfig.CoreApiGetAgreementsByAccountId.Replace("{accountId}", accountId.ToString())}";
return await _getRequest.Async<IEnumerable<Agreement>>(path, 0);
return await _getRequest.AsyncWithNewton<IEnumerable<Agreement>>(new Uri(path), null, 0);
} }
public async Task<AgreementAccount> GetAgreementAccountByAccountId(long accountId) public async Task<AgreementAccount> GetAgreementAccountByAccountId(long accountId)
@@ -85,13 +86,6 @@ public class CoreApiWrapperDao : ICoreApiWrapperDao
return await _getRequest.Async<IEnumerable<long>>(path, 0, 240); return await _getRequest.Async<IEnumerable<long>>(path, 0, 240);
} }
public async Task<IEnumerable<long>> GetAuditOrganizationFromDateLastMaintained(DateTime dateTime)
{
var dtString = dateTime.ToString("s").Replace(":", "%3A");
var path = $"{_coreApiWrapperConfig.CoreApiBaseUrl}{_coreApiWrapperConfig.CoreApiGetAuditOrganizationFromDateLastMaintained}?dateLastMaintained={dtString}";
return await _getRequest.Async<IEnumerable<long>>(path, 0, 240);
}
public async Task UpdateAgreementAccountsDeliveryMethod(IEnumerable<long> accountIds, string deliveryMethod, string userId) public async Task UpdateAgreementAccountsDeliveryMethod(IEnumerable<long> accountIds, string deliveryMethod, string userId)
{ {
var path = $"{_coreApiWrapperConfig.CoreApiBaseUrl}{_coreApiWrapperConfig.CoreApiUpdateAccountsMaintenanceRequest}"; var path = $"{_coreApiWrapperConfig.CoreApiBaseUrl}{_coreApiWrapperConfig.CoreApiUpdateAccountsMaintenanceRequest}";
@@ -0,0 +1,24 @@
using LCU.Library.Internal.FileOperationsModels.Models;
using LCU.Library.Internal.LcuHttpClient.HttpRequest;
namespace LCU.API.Internal.MemberPreferencesApi.DataAccess;
public class FileOperationsApiDao : IFileOperationsApiDao
{
private readonly FileOperationsApiConfiguration _fileOperationsApiConfiguration;
private readonly IPostRequest _postRequest;
public FileOperationsApiDao(FileOperationsApiConfiguration fileOperationsApiConfiguration, IPostRequest postRequest)
{
_fileOperationsApiConfiguration = fileOperationsApiConfiguration;
_postRequest = postRequest;
}
public async Task<RequestResponse> AppendFileAsync(AppendFileRequest request)
{
var url = new Uri($"{_fileOperationsApiConfiguration.AppendFileUrl}");
var result = await _postRequest.AsyncWithNewton<AppendFileRequest, RequestResponse>(url, request, 0);
return result;
}
}
@@ -1,21 +0,0 @@
using LCU.Api.Internal.FTPLib.Models;
using LCU.Library.Internal.LcuHttpClient.HttpRequest;
namespace LCU.API.Internal.MemberPreferencesApi.DataAccess;
public class FtpApiDao : IFtpApiDao
{
private readonly FtpApiConfiguration _ftpApiConfiguration;
private readonly IPostRequest _postRequest;
public FtpApiDao(FtpApiConfiguration ftpApiConfiguration, IPostRequest postRequest)
{
_ftpApiConfiguration = ftpApiConfiguration;
_postRequest = postRequest;
}
public async Task SendFtpAsync(SshFtpRequest request)
{
await _postRequest.Async(new Uri(_ftpApiConfiguration.QueueSshFtpRequestEndpointUrl), request, 0);
}
}
@@ -12,6 +12,5 @@ public interface ICoreApiWrapperDao
public Task<IEnumerable<AgreementAccount>> GetAgreementAccountsByOrganizationId(long organizationId); public Task<IEnumerable<AgreementAccount>> GetAgreementAccountsByOrganizationId(long organizationId);
public Task<IEnumerable<long>> GetAuditAccountsFromDateLastMaintained(DateTime dateTime); public Task<IEnumerable<long>> GetAuditAccountsFromDateLastMaintained(DateTime dateTime);
public Task<IEnumerable<long>> GetAuditAgreementFromDateLastMaintained(DateTime dateTime); public Task<IEnumerable<long>> GetAuditAgreementFromDateLastMaintained(DateTime dateTime);
public Task<IEnumerable<long>> GetAuditOrganizationFromDateLastMaintained(DateTime dateTime);
public Task UpdateAgreementAccountsDeliveryMethod(IEnumerable<long> accountIds, string deliveryMethod, string userId); public Task UpdateAgreementAccountsDeliveryMethod(IEnumerable<long> accountIds, string deliveryMethod, string userId);
} }
@@ -0,0 +1,8 @@
using LCU.Library.Internal.FileOperationsModels.Models;
namespace LCU.API.Internal.MemberPreferencesApi.DataAccess;
public interface IFileOperationsApiDao
{
public Task<RequestResponse> AppendFileAsync(AppendFileRequest request);
}
@@ -1,8 +0,0 @@
using LCU.Api.Internal.FTPLib.Models;
namespace LCU.API.Internal.MemberPreferencesApi.DataAccess;
public interface IFtpApiDao
{
public Task SendFtpAsync(SshFtpRequest sftpRequest);
}
@@ -0,0 +1,7 @@
namespace LCU.API.Internal.MemberPreferencesApi.DataAccess
{
public interface IScanBiCoreApiWrapperDao
{
public Task<IEnumerable<long>> GetAuditOrganizationFromDateLastMaintained(DateTime dateTime);
}
}
@@ -0,0 +1,22 @@
using LCU.Library.Internal.LcuHttpClient.HttpRequest;
namespace LCU.API.Internal.MemberPreferencesApi.DataAccess;
public class ScanBiCoreApiWrapperDao : IScanBiCoreApiWrapperDao
{
private readonly ScanBiCoreApiWrapperConfiguration _scanBiCoreApiWrapperConfig;
private readonly IGetRequest _getRequest;
public ScanBiCoreApiWrapperDao(ScanBiCoreApiWrapperConfiguration scanBiCoreApiWrapperConfig, IGetRequest getRequest)
{
_scanBiCoreApiWrapperConfig = scanBiCoreApiWrapperConfig;
_getRequest = getRequest;
}
public async Task<IEnumerable<long>> GetAuditOrganizationFromDateLastMaintained(DateTime dateTime)
{
var dtString = dateTime.ToString("s").Replace(":", "%3A");
var path = $"{_scanBiCoreApiWrapperConfig.GetAuditOrganizationFromDateLastMaintainedUrl}?dateLastMaintained={dtString}";
return await _getRequest.Async<IEnumerable<long>>(path, 0, 360);
}
}
@@ -6,17 +6,20 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="LCU.Api.Internal.FTPLib" Version="2.11.2" /> <PackageReference Include="LCU.Library.Internal.ApiResponse" Version="3.4.1" />
<PackageReference Include="LCU.Library.Internal.ApiSecurity" Version="1.0.2" /> <PackageReference Include="LCU.Library.Internal.ApiSecurity" Version="1.0.2" />
<PackageReference Include="LCU.Library.Internal.Configuration" Version="1.0.0" /> <PackageReference Include="LCU.Library.Internal.Configuration" Version="1.0.0" />
<PackageReference Include="LCU.Library.Internal.CoreApiWrapperModel" Version="2.27.14" /> <PackageReference Include="LCU.Library.Internal.CoreApiWrapperModel" Version="2.27.14" />
<PackageReference Include="LCU.Api.Internal.MaidBotLib" Version="1.0.2" /> <PackageReference Include="LCU.Api.Internal.MaidBotLib" Version="1.0.2" />
<PackageReference Include="LCU.Library.Internal.Exceptions" Version="1.1.0" /> <PackageReference Include="LCU.Library.Internal.Exceptions" Version="2.0.0" />
<PackageReference Include="LCU.Library.Internal.FileOperationsModels" Version="4.1.5" />
<PackageReference Include="LCU.Library.Internal.LcuClassPatterns.Crud" Version="1.0.2" />
<PackageReference Include="LCU.Library.Internal.LcuHttpClient" Version="1.21.0" /> <PackageReference Include="LCU.Library.Internal.LcuHttpClient" Version="1.21.0" />
<PackageReference Include="LCU.Library.Internal.LcuMassTransit" Version="1.0.0" /> <PackageReference Include="LCU.Library.Internal.LcuMassTransit" Version="1.0.0" />
<PackageReference Include="LCU.Library.Internal.LcuMassTransitModels" Version="1.1.0" /> <PackageReference Include="LCU.Library.Internal.LcuMassTransitModels" Version="1.1.0" />
<PackageReference Include="LCU.Library.Internal.Logging" Version="1.1.0" /> <PackageReference Include="LCU.Library.Internal.LCUServiceFactory" Version="4.0.0" />
<PackageReference Include="LCU.Library.Internal.Status" Version="1.1.0" /> <PackageReference Include="LCU.Library.Internal.Logging" Version="2.2.0" />
<PackageReference Include="LCU.Library.Internal.Status" Version="2.0.0" />
<PackageReference Include="LCU.Library.Internal.StatusModels" Version="1.1.0" /> <PackageReference Include="LCU.Library.Internal.StatusModels" Version="1.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.0"> <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.0">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
@@ -6,5 +6,5 @@ public class XdiBatchRequest
{ {
public List<XdiBatchItem> XdiBatchItems { get; set; } public List<XdiBatchItem> XdiBatchItems { get; set; }
public XdiBatch XdiBatch { get; set; } public XdiBatch XdiBatch { get; set; }
public string SftpRootBasePath { get; set; } public string XdiAppendFileRootBasePath { get; set; }
} }
@@ -1,6 +0,0 @@
namespace LCU.API.Internal.MemberPreferencesApi.Models.Requests;
public class XdiBatchRequests
{
public List<XdiBatchRequest> XdiBatchRequestList { get; set; }
}
@@ -77,30 +77,26 @@ public class XdiBatch
return false; return false;
} }
public IReadOnlyCollection<XdiBatchFile> GetNonEmptyFiles(string pathPrefix = "") public IReadOnlyCollection<XdiBatchFile> GetNonEmptyFiles()
{ {
var list = new List<XdiBatchFile>(); var list = new List<XdiBatchFile>();
if (_updateMemberEmail.HasRows()) if (_updateMemberEmail.HasRows())
{ {
_updateMemberEmail.FolderPrefix = pathPrefix;
list.Add(_updateMemberEmail); list.Add(_updateMemberEmail);
} }
if (_addMemberElectronic.HasRows()) if (_addMemberElectronic.HasRows())
{ {
_addMemberElectronic.FolderPrefix = pathPrefix;
list.Add(_addMemberElectronic); list.Add(_addMemberElectronic);
} }
if (_updateMemberToElectronic.HasRows()) if (_updateMemberToElectronic.HasRows())
{ {
_updateMemberToElectronic.FolderPrefix = pathPrefix;
list.Add(_updateMemberToElectronic); list.Add(_updateMemberToElectronic);
} }
if (_updateMemberToPrint.HasRows()) if (_updateMemberToPrint.HasRows())
{ {
_updateMemberToPrint.FolderPrefix = pathPrefix;
list.Add(_updateMemberToPrint); list.Add(_updateMemberToPrint);
} }
@@ -5,20 +5,16 @@ namespace LCU.API.Internal.MemberPreferencesApi.Models;
public class XdiBatchFile public class XdiBatchFile
{ {
private const string Ext = "LMCU.txt";
public XdiFileType Type { get; set; } public XdiFileType Type { get; set; }
public List<XdiBatchFileRow> Data { get; set; } = new List<XdiBatchFileRow>(); public List<XdiBatchFileRow> Data { get; set; } = new List<XdiBatchFileRow>();
public string FolderPrefix { get; set; } = "";
public string GetFileName() public string GetFileName()
{ {
switch (Type) switch (Type)
{ {
case XdiFileType.AddMemberElectronic: return $"{FolderPrefix}Enrollment_AddElectronic_{Ext}"; case XdiFileType.AddMemberElectronic: return $"Enrollment_AddElectronic_LMCU";
case XdiFileType.DeleteMember: return $"{FolderPrefix}Enrollment_Delete_{Ext}"; case XdiFileType.UpdateMemberEmail: return $"Enrollment_UpdateEmail_LMCU";
case XdiFileType.UpdateMemberEmail: return $"{FolderPrefix}Enrollment_UpdateEmail_{Ext}"; case XdiFileType.UpdateMemberToElectronic: return $"Enrollment_UpdateToElectronic_LMCU";
case XdiFileType.UpdateMemberToElectronic: return $"{FolderPrefix}Enrollment_UpdateToElectronic_{Ext}"; case XdiFileType.UpdateMemberToPrint: return $"Enrollment_UpdateToPrint_LMCU";
case XdiFileType.UpdateMemberToPrint: return $"{FolderPrefix}Enrollment_UpdateToPrint_{Ext}";
default: throw new Exception($"Unknown File Type in XDI BatchFile: {Type}"); default: throw new Exception($"Unknown File Type in XDI BatchFile: {Type}");
} }
} }
@@ -39,11 +35,10 @@ public class XdiBatchFile
return Data.Select(batchRow => batchRow.ConvertToRow(Type)); return Data.Select(batchRow => batchRow.ConvertToRow(Type));
} }
public byte[] ConvertToDataFile() public string ConvertToDataFile()
{ {
var allRows = ConvertToDataRows(); var allRows = ConvertToDataRows();
var file = string.Join("\n", allRows); return string.Join("\n", allRows);
return Encoding.UTF8.GetBytes(file);
} }
public bool HasRows() public bool HasRows()
@@ -1,6 +1,6 @@
namespace LCU.API.Internal.MemberPreferencesApi.Models; namespace LCU.API.Internal.MemberPreferencesApi.Models;
public class FtpQueuePayloadItem public class XdiBatchFileExport
{ {
public string UserId { get; set; } public string UserId { get; set; }
public string Value { get; set; } public string Value { get; set; }
@@ -13,7 +13,6 @@ public class XdiBatchFileRow
switch (type) switch (type)
{ {
case XdiFileType.UpdateMemberToPrint: case XdiFileType.UpdateMemberToPrint:
case XdiFileType.DeleteMember: return UserId + "|";
case XdiFileType.AddMemberElectronic: case XdiFileType.AddMemberElectronic:
case XdiFileType.UpdateMemberEmail: case XdiFileType.UpdateMemberEmail:
case XdiFileType.UpdateMemberToElectronic: return UserId + "|" + Email + "|"; case XdiFileType.UpdateMemberToElectronic: return UserId + "|" + Email + "|";
@@ -1,31 +1,33 @@
using LCU.Library.Internal.Logging.Models;
using LCU.Library.Internal.Logging;
using LCU.Library.Internal.ApiSecurity;
using LCU.Library.Internal.LcuHttpClient;
using LCU.Library.Internal.Status;
using LCU.Library.Internal.Configuration;
using LCU.Library.Internal.LcuMassTransit;
using LCU.Library.Internal.Logging.Middleware;
using LCU.API.Internal.MemberPreferencesApi.Consumers;
using LCU.API.Internal.MemberPreferencesApi.HostedServices;
using LCU.API.Internal.MemberPreferencesApiLib.Persistence;
using LCU.API.Internal.MemberPreferencesApi.Services.XdiServices;
using LCU.API.Internal.MemberPreferencesApi.Services.DnaAuditServices;
using LCU.API.Internal.MemberPreferencesApi.Interfaces;
using LCU.API.Internal.MemberPreferencesApi.Services.QueueServices;
using LCU.API.Internal.MemberPreferencesApi.MicroApiServices;
using LCU.API.Internal.MemberPreferencesApi.DataAccess;
using LCU.API.Internal.MemberPreferencesApi.Services;
using LCU.Library.Internal.MemberPreferencesApiModels.Models;
using LCU.API.Internal.MemberPreferencesApi.Models.EmailPolicies;
using LCU.API.Internal.MemberPreferencesApiLib.Repositories;
using LCU.Library.Internal.MemberPreferencesApiModels.Entities;
using LCU.Library.Internal.LcuMassTransitModels;
using Infrastructure.Services; using Infrastructure.Services;
using Microsoft.FeatureManagement; using LCU.API.Internal.MemberPreferencesApi.Consumers;
using Microsoft.EntityFrameworkCore; using LCU.API.Internal.MemberPreferencesApi.DataAccess;
using Microsoft.OpenApi.Models; using LCU.API.Internal.MemberPreferencesApi.Interfaces;
using LCU.API.Internal.MemberPreferencesApi.MicroApiServices;
using LCU.API.Internal.MemberPreferencesApi.Models.EmailPolicies;
using LCU.API.Internal.MemberPreferencesApi.Services;
using LCU.API.Internal.MemberPreferencesApi.Services.DnaAuditServices;
using LCU.API.Internal.MemberPreferencesApi.Services.QueueServices;
using LCU.API.Internal.MemberPreferencesApi.Services.XdiServices;
using LCU.API.Internal.MemberPreferencesApiLib.Persistence;
using LCU.API.Internal.MemberPreferencesApiLib.Repositories;
using LCU.Library.Internal.ApiSecurity;
using LCU.Library.Internal.Configuration;
using LCU.Library.Internal.LcuClassPatterns.Crud;
using LCU.Library.Internal.LcuHttpClient;
using LCU.Library.Internal.LcuMassTransit;
using LCU.Library.Internal.LcuMassTransitModels;
using LCU.Library.Internal.LCUServiceFactory;
using LCU.Library.Internal.LCUServiceFactory.Configurations;
using LCU.Library.Internal.Logging;
using LCU.Library.Internal.Logging.Middleware;
using LCU.Library.Internal.Logging.Models;
using LCU.Library.Internal.MemberPreferencesApiModels.Entities;
using LCU.Library.Internal.MemberPreferencesApiModels.Models;
using LCU.Library.Internal.Status;
using MassTransit; using MassTransit;
using Microsoft.EntityFrameworkCore;
using Microsoft.FeatureManagement;
using Microsoft.OpenApi.Models;
string MyAllowSpecificOrigins = "_myAllowSpecificOrigins"; string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
@@ -37,11 +39,9 @@ BuildAppAndRun(builder);
WebApplicationBuilder BuildBuilder(string[] args) WebApplicationBuilder BuildBuilder(string[] args)
{ {
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
builder.Configuration.AddJsonFile("/app/config/mapped-appsettings/primary.json", optional: true, reloadOnChange: true); builder.Configuration.AddJsonFile("/app/config/environment-appsettings/appsettings.json", optional: true, reloadOnChange: true);
builder.Configuration.AddJsonFile("/app/config/workload-appsettings/appsettings.json", optional: true, reloadOnChange: true);
builder.Configuration.AddJsonFile("/vault/secrets/member-preferences-api-member-preferences-api-key.json", optional: true, reloadOnChange: true); builder.Configuration.AddJsonFile("/vault/secrets/member-preferences-api-member-preferences-api-key.json", optional: true, reloadOnChange: true);
builder.Configuration.AddJsonFile("/vault/secrets/member-preferences-api-ftp-fingerprint.json", optional: true, reloadOnChange: true);
builder.Configuration.AddJsonFile("/vault/secrets/member-preferences-api-ftp-password.json", optional: true, reloadOnChange: true);
builder.Configuration.AddJsonFile("/vault/secrets/member-preferences-api-ftp-username.json", optional: true, reloadOnChange: true);
builder.Configuration.AddJsonFile("/vault/secrets/member-preferences-api-queue-password.json", optional: true, reloadOnChange: true); builder.Configuration.AddJsonFile("/vault/secrets/member-preferences-api-queue-password.json", optional: true, reloadOnChange: true);
builder.Configuration.AddJsonFile("/vault/secrets/member-preferences-api-queue-username.json", optional: true, reloadOnChange: true); builder.Configuration.AddJsonFile("/vault/secrets/member-preferences-api-queue-username.json", optional: true, reloadOnChange: true);
builder.Configuration.AddJsonFile("/vault/secrets/member-preferences-api-db-connection.json", optional: true, reloadOnChange: true); builder.Configuration.AddJsonFile("/vault/secrets/member-preferences-api-db-connection.json", optional: true, reloadOnChange: true);
@@ -55,12 +55,12 @@ void BuildServicesAndConfigurations(WebApplicationBuilder builder)
{ {
var services = builder.Services; var services = builder.Services;
var configuration = builder.Configuration; var configuration = builder.Configuration;
var servicesFactoryConfiguration = configuration.Bind<ServicesFactoryConfiguration>(services);
var apiConfiguration = configuration.Bind<ApiConfiguration>(services, "Primary"); var apiConfiguration = configuration.Bind<ApiConfiguration>(services, "Primary");
configuration.Bind<XdiSftpApiConfiguration>(services); configuration.Bind<FileOperationsApiConfiguration>(services);
configuration.Bind<FtpApiConfiguration>(services);
configuration.Bind<NotificationApiConfiguration>(services); configuration.Bind<NotificationApiConfiguration>(services);
configuration.Bind<CoreApiWrapperConfiguration>(services); configuration.Bind<CoreApiWrapperConfiguration>(services);
configuration.Bind<DnaAuditProcessConfiguration>(services); configuration.Bind<ScanBiCoreApiWrapperConfiguration>(services);
var loggerConfiguration = new LoggingConfiguration(apiConfiguration.AppName, var loggerConfiguration = new LoggingConfiguration(apiConfiguration.AppName,
apiConfiguration.SeqKey, apiConfiguration.SeqKey,
@@ -82,10 +82,11 @@ void BuildServicesAndConfigurations(WebApplicationBuilder builder)
services.AddHttpContextAccessor(); services.AddHttpContextAccessor();
services.AddHttpClient(); services.AddHttpClient();
services.AddLcuCrudServices();
var databaseSettings = configuration.Bind<SqlConnectionConfiguration>(services, "SqlConnectionConfiguration"); var databaseSettings = configuration.Bind<SqlConnectionConfiguration>(services, "SqlConnectionConfiguration");
services.AddDbContext<ApplicationDbContext>(options => services.AddDbContextPool<ApplicationDbContext>(options =>
{ {
options.UseSqlServer options.UseSqlServer
( (
@@ -94,6 +95,7 @@ void BuildServicesAndConfigurations(WebApplicationBuilder builder)
); );
}); });
AddServiceFactoryServices(services);
services.AddLCUStatusServicesWithApiHealthCheck(configuration); services.AddLCUStatusServicesWithApiHealthCheck(configuration);
services.AddLCUHttpServices(); services.AddLCUHttpServices();
services.AddControllers(); services.AddControllers();
@@ -103,12 +105,6 @@ void BuildServicesAndConfigurations(WebApplicationBuilder builder)
c.SwaggerDoc("v1", new OpenApiInfo { Title = $"{apiConfiguration.AppName}", Version = "v1" }); c.SwaggerDoc("v1", new OpenApiInfo { Title = $"{apiConfiguration.AppName}", Version = "v1" });
}); });
if (apiConfiguration.FeatureFlags.RunHostedServices)
{
services.AddHostedService<HostedXdiBatchProcessService>();
services.AddHostedService<HostedDnaDataAuditProcessService>();
}
services.AddFeatureManagement(configuration.GetSection("Primary:FeatureGates")); services.AddFeatureManagement(configuration.GetSection("Primary:FeatureGates"));
services.AddScoped<IApplicationDbContext>(provider => provider.GetService<ApplicationDbContext>()); services.AddScoped<IApplicationDbContext>(provider => provider.GetService<ApplicationDbContext>());
@@ -122,13 +118,7 @@ void BuildServicesAndConfigurations(WebApplicationBuilder builder)
{ {
XdiBatchProcessEndpoint = MassTransitConfigurationSetUp.GetReceiveEndpointConfiguration(configuration, "XdiBatchProcessEndpoint"), XdiBatchProcessEndpoint = MassTransitConfigurationSetUp.GetReceiveEndpointConfiguration(configuration, "XdiBatchProcessEndpoint"),
XdiBatchConfirmEndpoint = MassTransitConfigurationSetUp.GetReceiveEndpointConfiguration(configuration, "XdiBatchConfirmEndpoint"), DnaAuditProcessEndpoint = MassTransitConfigurationSetUp.GetReceiveEndpointConfiguration(configuration, "DnaAuditProcessEndpoint")
DnaAccountAuditEndpoint = MassTransitConfigurationSetUp.GetReceiveEndpointConfiguration(configuration, "DnaAccountAuditEndpoint"),
DnaAgreementAuditEndpoint = MassTransitConfigurationSetUp.GetReceiveEndpointConfiguration(configuration, "DnaAgreementAuditEndpoint"),
DnaOrganizationAuditEndpoint = MassTransitConfigurationSetUp.GetReceiveEndpointConfiguration(configuration, "DnaOrganizationAuditEndpoint"),
}; };
services.AddSingleton(receiveEndpointConfigurations); services.AddSingleton(receiveEndpointConfigurations);
@@ -137,6 +127,7 @@ void BuildServicesAndConfigurations(WebApplicationBuilder builder)
AddMemberPreferencesApiServices(services); AddMemberPreferencesApiServices(services);
AddMemberPreferencesDaos(services); AddMemberPreferencesDaos(services);
AddMemberPreferencesLib(ref services); AddMemberPreferencesLib(ref services);
services.AddLCUServiceFactoryAndValidateServiceRegistration<IDNAAuditCheckService>(servicesFactoryConfiguration);
} }
void AddMassTransitServices(ref IServiceCollection services, void AddMassTransitServices(ref IServiceCollection services,
@@ -147,10 +138,7 @@ void AddMassTransitServices(ref IServiceCollection services,
services.AddMassTransit(x => services.AddMassTransit(x =>
{ {
x.AddConsumer<XdiBatchProcessConsumer>(); x.AddConsumer<XdiBatchProcessConsumer>();
x.AddConsumer<XdiSshResponseConsumer>(); x.AddConsumer<DnaAuditProcessConsumer>();
x.AddConsumer<AccountDnaFieldChangeConsumer>();
x.AddConsumer<AgreementDnaFieldChangeConsumer>();
x.AddConsumer<OrganizationDnaFieldChangeConsumer>();
x.UsingRabbitMq((context, cfg) => x.UsingRabbitMq((context, cfg) =>
{ {
@@ -170,43 +158,13 @@ void AddMassTransitServices(ref IServiceCollection services,
}); });
} }
if (configuration.FeatureFlags.RunXdiSshResponseConsumer) if (configuration.FeatureFlags.RunDnaAuditProcessConsumer)
{ {
cfg.ReceiveEndpoint(receiveEndpointConfigurations.XdiBatchConfirmEndpoint.ReceiveEndpoint, e => cfg.ReceiveEndpoint(receiveEndpointConfigurations.DnaAuditProcessEndpoint.ReceiveEndpoint, e =>
{ {
e.ConfigureConsumer<XdiSshResponseConsumer>(context); e.ConfigureConsumer<DnaAuditProcessConsumer>(context);
e.SetQuorumQueue(); e.SetQuorumQueue();
e.PrefetchCount = receiveEndpointConfigurations.XdiBatchConfirmEndpoint.PrefetchLimit; e.PrefetchCount = receiveEndpointConfigurations.DnaAuditProcessEndpoint.PrefetchLimit;
});
}
if (configuration.FeatureFlags.RunAccountDnaFieldChangeConsumer)
{
cfg.ReceiveEndpoint(receiveEndpointConfigurations.DnaAccountAuditEndpoint.ReceiveEndpoint, e =>
{
e.ConfigureConsumer<AccountDnaFieldChangeConsumer>(context);
e.SetQuorumQueue();
e.PrefetchCount = receiveEndpointConfigurations.DnaAccountAuditEndpoint.PrefetchLimit;
});
}
if (configuration.FeatureFlags.RunAgreementDnaFieldChangeConsumer)
{
cfg.ReceiveEndpoint(receiveEndpointConfigurations.DnaAgreementAuditEndpoint.ReceiveEndpoint, e =>
{
e.ConfigureConsumer<AgreementDnaFieldChangeConsumer>(context);
e.SetQuorumQueue();
e.PrefetchCount = receiveEndpointConfigurations.DnaAgreementAuditEndpoint.PrefetchLimit;
});
}
if (configuration.FeatureFlags.RunOrganizationDnaFieldChangeConsumer)
{
cfg.ReceiveEndpoint(receiveEndpointConfigurations.DnaOrganizationAuditEndpoint.ReceiveEndpoint, e =>
{
e.ConfigureConsumer<OrganizationDnaFieldChangeConsumer>(context);
e.SetQuorumQueue();
e.PrefetchCount = receiveEndpointConfigurations.DnaOrganizationAuditEndpoint.PrefetchLimit;
}); });
} }
}); });
@@ -214,6 +172,13 @@ void AddMassTransitServices(ref IServiceCollection services,
services.AddMassTransitHostedService(); services.AddMassTransitHostedService();
} }
void AddServiceFactoryServices(IServiceCollection services)
{
services.AddScoped<IDNAAuditCheckService, DNADataAccountAuditCheckService>();
services.AddScoped<IDNAAuditCheckService, DNADataAgreementAuditCheckService>();
services.AddScoped<IDNAAuditCheckService, DNADataOrganizationAuditService>();
}
void AddMemberPreferencesApiServices(IServiceCollection services) void AddMemberPreferencesApiServices(IServiceCollection services)
{ {
services.AddScoped<IOptinService, OptinService>(); services.AddScoped<IOptinService, OptinService>();
@@ -230,7 +195,7 @@ void AddMemberPreferencesApiServices(IServiceCollection services)
void AddDnaAuditServices(IServiceCollection services) void AddDnaAuditServices(IServiceCollection services)
{ {
services.AddScoped<IDNADataAuditService, DNADataAuditService>(); services.AddScoped<IDNAAuditHelperService, DNAAuditHelperService>();
services.AddScoped<IDNADataAuditProcessService, DNADataAuditProcessService>(); services.AddScoped<IDNADataAuditProcessService, DNADataAuditProcessService>();
} }
@@ -253,24 +218,24 @@ void AddEmailUndeliverableServices(IServiceCollection services)
void AddQueueServices(IServiceCollection services) void AddQueueServices(IServiceCollection services)
{ {
services.AddScoped<IQueueDnaAccountAuditService, QueueDnaAccountAuditService>(); services.AddScoped<IQueueXdiBatchProcessService, QueueXdiBatchProcessService>();
services.AddScoped<IQueueDnaOrganizationAuditService, QueueDnaOrganizationService>(); services.AddScoped<IQueueDnaAuditProcessService, QueueDnaAuditProcessService>();
services.AddScoped<IQueueDnaAgreementAuditService, QueueDnaAgreementAuditService>();
services.AddScoped<IQueueXdiBatchService, QueueXdiBatchService>();
} }
void AddMicroApiServices(IServiceCollection services) void AddMicroApiServices(IServiceCollection services)
{ {
services.AddScoped<ICoreApiWrapperService, CoreApiWrapperService>(); services.AddScoped<ICoreApiWrapperService, CoreApiWrapperService>();
services.AddScoped<IFtpApiService, FtpApiService>(); services.AddScoped<IScanBiCoreApiWrapperService, ScanBiCoreApiWrapperService>();
services.AddScoped<INotificationService, NotificationService>(); services.AddScoped<INotificationService, NotificationService>();
services.AddScoped<IFileOperationsApiService, FileOperationsApiService>();
} }
void AddMemberPreferencesDaos(IServiceCollection services) void AddMemberPreferencesDaos(IServiceCollection services)
{ {
services.AddScoped<INotificationApiDao, NotificationApiDao>(); services.AddScoped<INotificationApiDao, NotificationApiDao>();
services.AddScoped<IFtpApiDao, FtpApiDao>();
services.AddScoped<ICoreApiWrapperDao, CoreApiWrapperDao>(); services.AddScoped<ICoreApiWrapperDao, CoreApiWrapperDao>();
services.AddScoped<IScanBiCoreApiWrapperDao, ScanBiCoreApiWrapperDao>();
services.AddScoped<IFileOperationsApiDao, FileOperationsApiDao>();
} }
void AddMemberPreferencesLib(ref IServiceCollection services) void AddMemberPreferencesLib(ref IServiceCollection services)
@@ -280,6 +245,7 @@ void AddMemberPreferencesLib(ref IServiceCollection services)
services.AddScoped<IMemberPreferenceRepository, MemberPreferenceRepository>(); services.AddScoped<IMemberPreferenceRepository, MemberPreferenceRepository>();
services.AddScoped<IMemberPreferences, MemberPreferenceRepository>(); services.AddScoped<IMemberPreferences, MemberPreferenceRepository>();
services.AddScoped<IXdiBatchItemsRepository, XdiBatchItemsRepository>(); services.AddScoped<IXdiBatchItemsRepository, XdiBatchItemsRepository>();
services.AddScoped<IXdiBatchProcessInfoRepository, XdiBatchProcessInfoRepository>();
services.AddScoped<IDnaAuditProcessRepository, DnaAuditProcessRepository>(); services.AddScoped<IDnaAuditProcessRepository, DnaAuditProcessRepository>();
} }
@@ -0,0 +1,9 @@
using LCU.Library.Internal.LCUServiceFactory.Configurations;
using LCU.Library.Internal.LCUServiceFactory.Services;
namespace LCU.API.Internal.MemberPreferencesApi.Services.DnaAuditServices;
public abstract class DNAAuditCheckService(ServicesFactoryConfiguration servicesFactoryConfiguration)
: LcuAbstractService(servicesFactoryConfiguration.GetServiceFactoryRegistrationByInterface<IDNAAuditCheckService>())
{
}
@@ -0,0 +1,78 @@
using LCU.API.Internal.MemberPreferencesApi.MicroApiServices;
using LCU.Library.Internal.CoreApiWrapperModel.CoreModels.Agreements;
using LCU.Library.Internal.MemberPreferencesApiModels.Entities;
namespace LCU.API.Internal.MemberPreferencesApi.Services.DnaAuditServices;
public class DNAAuditHelperService : IDNAAuditHelperService
{
private readonly ICoreApiWrapperService _coreApiWrapperService;
private readonly IOptinService _optinService;
private const string MemberPreferencePrint = "PRNT";
private const string MemberPreferenceElectronic = "WWW";
public DNAAuditHelperService(ICoreApiWrapperService coreApiWrapperService, IOptinService optinService)
{
_optinService = optinService;
_coreApiWrapperService = coreApiWrapperService;
}
public async Task UpdateAccountDeliveryMethodIfNotEqualToMemberPreference(AgreementAccount account)
{
try
{
if (account.AccountOwner?.UserId == null)
{
await _coreApiWrapperService.UpdateAgreementAccountsDeliveryMethod(new List<long> { account.AccountNumber }, "PRNT", "None Found During Audit");
return;
}
var currentAccountDeliveryMethod = account.OvrDeliveryMethCD;
var memberOptinSettings = await _optinService.GetMemberOptInSettings(account.AccountOwner.UserId);
var memberPreferenceDeliveryMethod = DetermineMemberPreference(memberOptinSettings);
if (!string.Equals(currentAccountDeliveryMethod, memberPreferenceDeliveryMethod, StringComparison.InvariantCultureIgnoreCase))
{
await _coreApiWrapperService.UpdateAgreementAccountsDeliveryMethod(new List<long> { account.AccountNumber }, memberPreferenceDeliveryMethod, account.AccountOwner.UserId);
}
}
catch (Exception ex)
{
var error = $"Failed to UpdateAccountDeliveryMethodIfNotEqualToMemberPreference for account number: {account.AccountNumber}";
Log.Error(ex, error);
throw new ServiceException(error);
}
}
private string DetermineMemberPreference(MemberOptInSettings optinSettings)
{
if (optinSettings == null)
{
return MemberPreferencePrint;
}
if (optinSettings.IsUnifiedElectronicEnrolled())
{
return MemberPreferenceElectronic;
}
if (optinSettings.IsUnifiedPaperEnrolled())
{
return MemberPreferencePrint;
}
if (string.Equals(optinSettings.EStatements, "Paper", StringComparison.InvariantCultureIgnoreCase))
{
return MemberPreferencePrint;
}
if (string.Equals(optinSettings.EStatements, "Electronic", StringComparison.InvariantCultureIgnoreCase))
{
return MemberPreferenceElectronic;
}
return MemberPreferencePrint;
}
}
@@ -0,0 +1,75 @@
using LCU.API.Internal.MemberPreferencesApi.MicroApiServices;
using LCU.Library.Internal.LCUServiceFactory.Configurations;
using LCU.Library.Internal.MemberPreferencesApiModels.Entities;
using LCU.Library.Internal.MemberPreferencesApiModels.Responses;
namespace LCU.API.Internal.MemberPreferencesApi.Services.DnaAuditServices;
public class DNADataAccountAuditCheckService : DNAAuditCheckService, IDNAAuditCheckService
{
private readonly ICoreApiWrapperService _coreApiWrapperService;
private readonly IDNAAuditHelperService _auditHelperService;
public DNADataAccountAuditCheckService(ServicesFactoryConfiguration servicesFactoryConfiguration,
ICoreApiWrapperService coreApiWrapperService,
IDNAAuditHelperService auditHelperService)
: base(servicesFactoryConfiguration)
{
_coreApiWrapperService = coreApiWrapperService;
_auditHelperService = auditHelperService;
}
public async Task<RequestResponse> ProcessRequest(DnaAuditProcessRequest request, DnaAuditProcess dnaAuditProcess)
{
try
{
var accountAuditRecords = await AuditDNAAccountsForTimePeriod(dnaAuditProcess.LastUpdated.AddMinutes(request.LookBackMinutes));
await HandleAccountAuditCheck(accountAuditRecords);
return new RequestResponse(request, true, new List<string>() { $"DNAAccountAudit ran successfully for {accountAuditRecords.Count} records" });
}
catch (Exception ex)
{
var error = $"Failure During ProcessRequest in DNADataAccountAuditCheckService. Exception Message: {ex.Message}";
return new RequestResponse(request, false, new List<string>() { error });
}
}
public async Task HandleAccountAuditCheck(List<long> accountAuditRecords)
{
try
{
foreach (var record in accountAuditRecords)
{
var account = await _coreApiWrapperService.GetAgreementAccountByAccountId(record);
if (account == null)
{
Log.Information($"During audit process account with ID: {record} could not be found, and will not be processed.");
continue;
}
await _auditHelperService.UpdateAccountDeliveryMethodIfNotEqualToMemberPreference(account);
}
}
catch (Exception ex)
{
Log.Error(ex, $"Failed to process DNA Audit for member preferences Account.");
throw new ServiceException(ex.Message);
}
}
public async Task<List<long>> AuditDNAAccountsForTimePeriod(DateTime timeToSearchFrom)
{
try
{
var dnaAccountAuditRecords = await _coreApiWrapperService.GetAuditAccountsFromDateLastMaintained(timeToSearchFrom);
return dnaAccountAuditRecords.ToList();
}
catch (Exception ex)
{
throw new ServiceException(ex.Message);
}
}
}
@@ -0,0 +1,90 @@
using LCU.API.Internal.MemberPreferencesApi.MicroApiServices;
using LCU.Library.Internal.CoreApiWrapperModel.CoreModels.Agreements;
using LCU.Library.Internal.LCUServiceFactory.Configurations;
using LCU.Library.Internal.MemberPreferencesApiModels.Entities;
using LCU.Library.Internal.MemberPreferencesApiModels.Responses;
namespace LCU.API.Internal.MemberPreferencesApi.Services.DnaAuditServices;
public class DNADataAgreementAuditCheckService : DNAAuditCheckService, IDNAAuditCheckService
{
private readonly ICoreApiWrapperService _coreApiWrapperService;
private readonly IDNAAuditHelperService _auditHelperService;
public DNADataAgreementAuditCheckService(ServicesFactoryConfiguration servicesFactoryConfiguration,
ICoreApiWrapperService coreApiWrapperService,
IDNAAuditHelperService auditHelperService)
: base(servicesFactoryConfiguration)
{
_coreApiWrapperService = coreApiWrapperService;
_auditHelperService = auditHelperService;
}
public async Task<RequestResponse> ProcessRequest(DnaAuditProcessRequest request, DnaAuditProcess dnaAuditProcess)
{
try
{
var agreementAuditRecords = await AuditDNAAgreementForTimePeriod(dnaAuditProcess.LastUpdated.AddMinutes(request.LookBackMinutes));
await HandleAgreementAuditCheck(agreementAuditRecords);
return new RequestResponse(request, true, new List<string>() { $"DNAAgreementAudit ran successfully for {agreementAuditRecords.Count} records" });
}
catch (Exception ex)
{
var error = $"Failure During ProcessRequest in DNADataAgreementAuditCheckService. Exception Message: {ex.Message}";
return new RequestResponse(request, false, new List<string>() { error });
}
}
public async Task HandleAgreementAuditCheck(List<long> agreementAuditRecords)
{
try
{
foreach (var record in agreementAuditRecords)
{
var agreement = await _coreApiWrapperService.GetAgreementByAgreementId(record);
if (agreement == null)
{
Log.Information($"During audit process agreement with ID: {record} could not be found, and will not be processed.");
continue;
}
IEnumerable<AgreementAccount> agreementAccounts;
if (agreement.ByOrgNbr != 0)
{
agreementAccounts = await _coreApiWrapperService.GetAgreementAccountsByOrganizationId(agreement.ByOrgNbr);
}
else
{
agreementAccounts = await _coreApiWrapperService.GetAgreementAccountsByUserId(agreement.UserId);
agreementAccounts = agreementAccounts.Where(account => account.TaxReportForPersonNumber != null && account.AccountOwner.AgreementNumber == agreement.AgreementNumber);
}
foreach (var agreementAccount in agreementAccounts)
{
await _auditHelperService.UpdateAccountDeliveryMethodIfNotEqualToMemberPreference(agreementAccount);
}
}
}
catch (Exception ex)
{
Log.Error(ex, $"Failed to process DNA Audit for member preferences Agreement.");
throw new ServiceException(ex.Message);
}
}
public async Task<List<long>> AuditDNAAgreementForTimePeriod(DateTime timeToSearchFrom)
{
try
{
var dnaAgreementAuditRecords = await _coreApiWrapperService.GetAuditAgreementFromDateLastMaintained(timeToSearchFrom);
return dnaAgreementAuditRecords.ToList();
}
catch (Exception ex)
{
throw new ServiceException(ex.Message);
}
}
}
@@ -1,9 +1,10 @@
using LCU.API.Internal.MemberPreferencesApi.Interfaces; using LCU.API.Internal.MemberPreferencesApi.Interfaces;
using LCU.API.Internal.MemberPreferencesApi.MicroApiServices; using LCU.API.Internal.MemberPreferencesApi.MicroApiServices;
using LCU.API.Internal.MemberPreferencesApi.Services.QueueServices;
using LCU.API.Internal.MemberPreferencesApiLib.Repositories; using LCU.API.Internal.MemberPreferencesApiLib.Repositories;
using LCU.Library.Internal.ApiResponse.Services;
using LCU.Library.Internal.LCUServiceFactory.Services;
using LCU.Library.Internal.MemberPreferencesApiModels.Entities; using LCU.Library.Internal.MemberPreferencesApiModels.Entities;
using LCU.Library.Internal.MemberPreferencesApiModels.Enums; using LCU.Library.Internal.MemberPreferencesApiModels.Responses;
namespace LCU.API.Internal.MemberPreferencesApi.Services.DnaAuditServices; namespace LCU.API.Internal.MemberPreferencesApi.Services.DnaAuditServices;
@@ -11,135 +12,86 @@ public class DNADataAuditProcessService : IDNADataAuditProcessService
{ {
private readonly IDateTime _dateTime; private readonly IDateTime _dateTime;
private readonly ICoreApiWrapperService _coreApiWrapperService; private readonly ICoreApiWrapperService _coreApiWrapperService;
private readonly IScanBiCoreApiWrapperService _scanBiCoreApiWrapperService;
private readonly IDnaAuditProcessRepository _dnaAuditProcessRepository; private readonly IDnaAuditProcessRepository _dnaAuditProcessRepository;
private readonly DnaAuditProcessConfiguration _dnaAuditProcessConfig; private readonly ILcuServiceFactory<IDNAAuditCheckService> _lcuServiceFactory;
private readonly IQueueDnaAccountAuditService _queueDnaAccountAuditService;
private readonly IQueueDnaAgreementAuditService _queueDnaAgreementAuditService;
private readonly IQueueDnaOrganizationAuditService _queueDnaOrganizationAuditService;
public DNADataAuditProcessService(IQueueDnaAccountAuditService queueDnaAccountAuditService, public DNADataAuditProcessService(ICoreApiWrapperService coreApiWrapperService,
IQueueDnaAgreementAuditService queueDnaAgreementAuditService, IScanBiCoreApiWrapperService scanBiCoreApiWrapperService,
IQueueDnaOrganizationAuditService queueDnaOrganizationAuditService, IDateTime dateTime,
ICoreApiWrapperService coreApiWrapperService, IDateTime dateTime, IDnaAuditProcessRepository dnaAuditProcessRepository,
IDnaAuditProcessRepository dnaAuditProcessRepository, DnaAuditProcessConfiguration dnaAuditProcessConfig) ILcuServiceFactory<IDNAAuditCheckService> lcuServiceFactory)
{ {
_queueDnaAccountAuditService = queueDnaAccountAuditService;
_queueDnaAgreementAuditService = queueDnaAgreementAuditService;
_queueDnaOrganizationAuditService = queueDnaOrganizationAuditService;
_coreApiWrapperService = coreApiWrapperService; _coreApiWrapperService = coreApiWrapperService;
_scanBiCoreApiWrapperService = scanBiCoreApiWrapperService;
_dateTime = dateTime; _dateTime = dateTime;
_dnaAuditProcessRepository = dnaAuditProcessRepository; _dnaAuditProcessRepository = dnaAuditProcessRepository;
_dnaAuditProcessConfig = dnaAuditProcessConfig; _lcuServiceFactory = lcuServiceFactory;
} }
public async Task RunDataAuditProcesses() public async Task HandleDnaAuditProcessRequest(DnaAuditProcessRequest request)
{ {
try try
{ {
var dnaProcesses = await _dnaAuditProcessRepository.GetAllDnaAuditProcesses(); var dnaAuditProcess = await _dnaAuditProcessRepository.GetDnaAuditProcessByDnaProcessType(request.DnaAuditProcessType);
if (dnaAuditProcess == null)
foreach (var dnaProcess in dnaProcesses)
{ {
var timeToSearchFrom = dnaProcess.LastUpdated.AddMinutes(_dnaAuditProcessConfig.LookBackMinutes); throw new Exception($"DnaAuditProcess not found for requested type: {request.DnaAuditProcessType.ToString()}");
switch (dnaProcess.DnaProcessType)
{
case DnaAuditProcessType.DNAOrganization:
await AuditDNAOrganizationForTimePeriod(timeToSearchFrom, dnaProcess);
break;
case DnaAuditProcessType.DNAAgreement:
await AuditDNAAgreementForTimePeriod(timeToSearchFrom, dnaProcess);
break;
case DnaAuditProcessType.DNAAccounts:
await AuditDNAAccountsForTimePeriod(timeToSearchFrom, dnaProcess);
break;
default:
Log.ForContext(Enum.GetName(typeof(PropertyEnum), PropertyEnum.Group),
Enum.GetName(typeof(GroupEnum), GroupEnum.ITDevelopment))
.Error($"DnaAuditProcessType not found for ProcessId: {dnaProcess.ProcessId}. ProcessType: {dnaProcess.DnaProcessType}");
break;
}
} }
var result = await PerformDNAAuditCheck(request, dnaAuditProcess);
// Return successful as True so Dispatcher job never stops running.
result.IsSuccessful = true;
await QueueReturnResponse.QueueResponse(request, result.IsSuccessful, result.MessageStack);
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.ForContext(Enum.GetName(typeof(PropertyEnum), PropertyEnum.Group), Enum.GetName(typeof(GroupEnum), GroupEnum.ITDevelopment)) Log.Error(ex.Message);
.Error(ex, "Failed to Queue Last 5 Minutes of MemberPreference DNA DataAudit Activity"); // Return successful as True so Dispatcher job never stops running.
await QueueReturnResponse.QueueResponse(request, true, new List<string>() { ex.Message });
throw new ServiceException($"Failed to handled Consumed DnaAuditProcessRequest. ExceptionMessage: {ex.Message}");
} }
} }
public async Task AuditDNAOrganizationForTimePeriod(DateTime timeToSearchFrom, DnaAuditProcess dnaProcess) public async Task<RequestResponse> PerformDNAAuditCheck(DnaAuditProcessRequest request, DnaAuditProcess dnaAuditProcess)
{ {
var requestResponse = new RequestResponse(request);
try try
{ {
var dnaOrganizationAuditRecords = await _coreApiWrapperService.GetAuditOrganizationFromDateLastMaintained(timeToSearchFrom); var dnaAuditCheckService = _lcuServiceFactory.GetService(request.DnaAuditProcessType);
var organizationAuditRecords = dnaOrganizationAuditRecords.ToList();
await _queueDnaOrganizationAuditService.QueueDataAuditForOrganizations(organizationAuditRecords, dnaProcess.ConsecutiveFailures);
Log.Information($"Queued {organizationAuditRecords.Count} DataAudit Organization Changes Since Last DNADataAuditProducerService Run."); requestResponse = await dnaAuditCheckService.ProcessRequest(request, dnaAuditProcess);
dnaProcess = HandleDnaAuditProcessSuccess(dnaProcess);
} }
catch (Exception ex) catch (Exception ex)
{ {
dnaProcess = HandleDnaAuditProcessException(dnaProcess, ex); var failureMessage = $"Failed to perform DNA Data Audit Process. Exception Message: {ex.Message}";
Log.Error(failureMessage);
requestResponse.MessageStack.Add(failureMessage);
requestResponse.IsSuccessful = false;
} }
await _dnaAuditProcessRepository.Update(dnaProcess); await _dnaAuditProcessRepository.Update(requestResponse.IsSuccessful ?
HandleDnaAuditProcessSuccess(dnaAuditProcess) :
HandleDnaAuditProcessException(dnaAuditProcess, request));
return requestResponse;
} }
public async Task AuditDNAAgreementForTimePeriod(DateTime timeToSearchFrom, DnaAuditProcess dnaProcess) public DnaAuditProcess HandleDnaAuditProcessException(DnaAuditProcess process, DnaAuditProcessRequest request)
{
try
{
var dnaAgreementAuditRecords = await _coreApiWrapperService.GetAuditAgreementFromDateLastMaintained(timeToSearchFrom);
var agreementAuditRecords = dnaAgreementAuditRecords.ToList();
await _queueDnaAgreementAuditService.QueueDataAuditForAgreements(agreementAuditRecords, dnaProcess.ConsecutiveFailures);
Log.Information($"Queued {agreementAuditRecords.Count} DataAudit Agreement Changes Since Last DNADataAuditProducerService Run.");
dnaProcess = HandleDnaAuditProcessSuccess(dnaProcess);
}
catch (Exception ex)
{
dnaProcess = HandleDnaAuditProcessException(dnaProcess, ex);
}
await _dnaAuditProcessRepository.Update(dnaProcess);
}
public async Task AuditDNAAccountsForTimePeriod(DateTime timeToSearchFrom, DnaAuditProcess dnaProcess)
{
try
{
var dnaAccountAuditRecords = await _coreApiWrapperService.GetAuditAccountsFromDateLastMaintained(timeToSearchFrom);
var accountAuditRecords = dnaAccountAuditRecords.ToList();
await _queueDnaAccountAuditService.QueueDataAuditForAccounts(accountAuditRecords, dnaProcess.ConsecutiveFailures);
Log.Information($"Queued {accountAuditRecords.Count} DataAudit Account Changes Since Last DNADataAuditProducerService Run.");
dnaProcess = HandleDnaAuditProcessSuccess(dnaProcess);
}
catch (Exception ex)
{
dnaProcess = HandleDnaAuditProcessException(dnaProcess, ex);
}
await _dnaAuditProcessRepository.Update(dnaProcess);
}
public DnaAuditProcess HandleDnaAuditProcessException(DnaAuditProcess process, Exception ex)
{ {
process.ConsecutiveFailures++; process.ConsecutiveFailures++;
if (process.ConsecutiveFailures >= _dnaAuditProcessConfig.NumberOfAllowedConsecutiveFailures) if (process.ConsecutiveFailures >= request.NumberOfAllowedConsecutiveFailures)
{ {
Log.ForContext(Enum.GetName(typeof(PropertyEnum), PropertyEnum.Group), Log.ForContext(Enum.GetName(typeof(PropertyEnum), PropertyEnum.Group),
Enum.GetName(typeof(GroupEnum), GroupEnum.ITDevelopment)) Enum.GetName(typeof(GroupEnum), GroupEnum.ITDevelopment))
.Error($"DnaAuditProcess for {process.DnaProcessType} has failed {process.ConsecutiveFailures} consecutive times. " + .Error($"DnaAuditProcess for {process.DnaProcessType} has failed {process.ConsecutiveFailures} consecutive times. " +
$"Last succesful runtime: {process.LastUpdated} CST. " + $"Last successful runtime: {process.LastUpdated} CST. " +
$"This process needs to checked on to determine why failure is occuring."); $"This process needs to be checked on to determine why failure is occurring.");
} }
else else
{ {
Log.Warning($"Exception and Failure occured for DnaAuditProcess: {process.DnaProcessType}. ConsecutiveFailures: {process.ConsecutiveFailures}. " + Log.Warning($"Exception and Failure occurred for DnaAuditProcess: {process.DnaProcessType}. ConsecutiveFailures: {process.ConsecutiveFailures}. " +
$"Last succesful runtime: {process.LastUpdated} CST. Exception: {ex}"); $"Last successful runtime: {process.LastUpdated} CST.");
} }
return process; return process;
@@ -1,161 +0,0 @@
using LCU.API.Internal.MemberPreferencesApi.MicroApiServices;
using LCU.Library.Internal.CoreApiWrapperModel.CoreModels.Agreements;
using LCU.Library.Internal.MemberPreferencesApiModels.Entities;
namespace LCU.API.Internal.MemberPreferencesApi.Services.DnaAuditServices;
public class DNADataAuditService : IDNADataAuditService
{
private readonly ICoreApiWrapperService _coreApiWrapperService;
private readonly IOptinService _optinService;
private const string MemberPreferencePrint = "PRNT";
private const string MemberPreferenceElectronic = "WWW";
public DNADataAuditService(ICoreApiWrapperService coreApiWrapperService, IOptinService optinService)
{
_optinService = optinService;
_coreApiWrapperService = coreApiWrapperService;
}
public async Task HandleAccountAuditCheck(DnaFieldChangeRequest request)
{
try
{
var accountNumber = request.DnaFieldIdInformation;
var account = await _coreApiWrapperService.GetAgreementAccountByAccountId(accountNumber);
if (account == null)
{
Log.Information($"During audit process account with ID: {accountNumber} could not be found, and will not be processed.");
return;
}
await UpdateAccountDeliveryMethodIfNotEqualToMemberPreference(account);
}
catch (Exception ex)
{
Log.Error(ex,
$"Failed to process DNA Audit for member preferences Account.");
}
}
public async Task HandleAgreementAuditCheck(DnaFieldChangeRequest request)
{
try
{
var agreementNumber = request.DnaFieldIdInformation;
var agreement = await _coreApiWrapperService.GetAgreementByAgreementId(agreementNumber);
if (agreement == null)
{
Log.Information($"During audit process agreement with ID: {agreementNumber} could not be found, and will not be processed.");
return;
}
IEnumerable<AgreementAccount> agreementAccounts;
if (agreement.ByOrgNbr != 0)
{
agreementAccounts = await _coreApiWrapperService.GetAgreementAccountsByOrganizationId(agreement.ByOrgNbr);
}
else
{
agreementAccounts = await _coreApiWrapperService.GetAgreementAccountsByUserId(agreement.UserId);
agreementAccounts = agreementAccounts.Where(account => account.TaxReportForPersonNumber != null && account.AccountOwner.AgreementNumber == agreement.AgreementNumber);
}
foreach (var agreementAccount in agreementAccounts)
{
await UpdateAccountDeliveryMethodIfNotEqualToMemberPreference(agreementAccount);
}
}
catch (Exception ex)
{
Log.Error(ex,
$"Failed to process DNA Audit for member preferences Agreement.");
}
}
public async Task HandleOrganizationAuditCheck(DnaFieldChangeRequest request)
{
try
{
var organizationId = request.DnaFieldIdInformation;
var organizationAccounts = await _coreApiWrapperService.GetAgreementAccountsByOrganizationId(organizationId);
if (organizationAccounts == null)
{
Log.Information($"During audit process organization with ID: {organizationId} could not be found, and will not be processed.");
return;
}
foreach (var account in organizationAccounts)
{
await UpdateAccountDeliveryMethodIfNotEqualToMemberPreference(account);
}
}
catch (Exception ex)
{
Log.Error(ex,
$"Failed to process DNA Audit for member preferences Organization.");
}
}
private async Task UpdateAccountDeliveryMethodIfNotEqualToMemberPreference(AgreementAccount account)
{
try
{
if (account.AccountOwner?.UserId == null)
{
await _coreApiWrapperService.UpdateAgreementAccountsDeliveryMethod(new List<long> { account.AccountNumber }, "PRNT", "None Found During Audit");
return;
}
var currentAccountDeliveryMethod = account.OvrDeliveryMethCD;
var memberOptinSettings = await _optinService.GetMemberOptInSettings(account.AccountOwner.UserId);
var memberPreferenceDeliveryMethod = DetermineMemberPreference(memberOptinSettings);
if (!string.Equals(currentAccountDeliveryMethod, memberPreferenceDeliveryMethod, StringComparison.InvariantCultureIgnoreCase))
{
await _coreApiWrapperService.UpdateAgreementAccountsDeliveryMethod(new List<long> { account.AccountNumber }, memberPreferenceDeliveryMethod, account.AccountOwner.UserId);
}
}
catch (Exception ex)
{
Log.Error(ex, $"Failed to UpdateAccountDeliveryMethodIfNotEqualToMemberPreference for account number: {account.AccountNumber}");
}
}
private string DetermineMemberPreference(MemberOptInSettings optinSettings)
{
if (optinSettings == null)
{
return MemberPreferencePrint;
}
if (optinSettings.IsUnifiedElectronicEnrolled())
{
return MemberPreferenceElectronic;
}
if (optinSettings.IsUnifiedPaperEnrolled())
{
return MemberPreferencePrint;
}
if (string.Equals(optinSettings.EStatements, "Paper", StringComparison.InvariantCultureIgnoreCase))
{
return MemberPreferencePrint;
}
if (string.Equals(optinSettings.EStatements, "Electronic", StringComparison.InvariantCultureIgnoreCase))
{
return MemberPreferenceElectronic;
}
return MemberPreferencePrint;
}
}
@@ -0,0 +1,87 @@
using LCU.API.Internal.MemberPreferencesApi.MicroApiServices;
using LCU.API.Internal.MemberPreferencesApi.Services.QueueServices;
using LCU.Library.Internal.LCUServiceFactory.Configurations;
using LCU.Library.Internal.MemberPreferencesApiModels.Entities;
using LCU.Library.Internal.MemberPreferencesApiModels.Responses;
using Microsoft.Extensions.DependencyInjection;
namespace LCU.API.Internal.MemberPreferencesApi.Services.DnaAuditServices;
public class DNADataOrganizationAuditService : DNAAuditCheckService, IDNAAuditCheckService
{
private readonly IScanBiCoreApiWrapperService _scanBiCoreApiWrapperService;
private readonly ICoreApiWrapperService _coreApiWrapperService;
private readonly IServiceScopeFactory _serviceScopeFactory;
private readonly IDNAAuditHelperService _auditHelperService;
public DNADataOrganizationAuditService(ServicesFactoryConfiguration servicesFactoryConfiguration,
ICoreApiWrapperService coreApiWrapperService,
IScanBiCoreApiWrapperService scanBiCoreApiWrapperService,
IServiceScopeFactory serviceScopeFactory,
IDNAAuditHelperService auditHelperService)
: base(servicesFactoryConfiguration)
{
_serviceScopeFactory = serviceScopeFactory;
_coreApiWrapperService = coreApiWrapperService;
_scanBiCoreApiWrapperService = scanBiCoreApiWrapperService;
_auditHelperService = auditHelperService;
}
public async Task<RequestResponse> ProcessRequest(DnaAuditProcessRequest request, DnaAuditProcess dnaAuditProcess)
{
try
{
var organizationAuditRecords = await AuditDNAOrganizationForTimePeriod(dnaAuditProcess.LastUpdated.AddMinutes(request.LookBackMinutes));
await HandleOrganizationAuditCheck(organizationAuditRecords);
return new RequestResponse(request, true, new List<string>() { $"DNAOrganizationAudit ran successfully for {organizationAuditRecords.Count} records" });
}
catch (Exception ex)
{
var error = $"Failure During ProcessRequest in DNADataOrganizationAuditService. Exception Message: {ex.Message}";
return new RequestResponse(request, false, new List<string>() { error });
}
}
public async Task HandleOrganizationAuditCheck(List<long> organizationAuditRecords)
{
try
{
foreach (var record in organizationAuditRecords)
{
var organizationAccounts = await _coreApiWrapperService.GetAgreementAccountsByOrganizationId(record);
var organizationAccountsList = organizationAccounts.ToList();
if (organizationAccountsList == null)
{
Log.Information($"During audit process organization with ID: {record} could not be found, and will not be processed.");
continue;
}
foreach (var account in organizationAccountsList)
{
await _auditHelperService.UpdateAccountDeliveryMethodIfNotEqualToMemberPreference(account);
}
}
}
catch (Exception ex)
{
Log.Error(ex, $"Failed to process DNA Audit for member preferences Organization.");
throw new ServiceException($"Failure in DNADataOrganizationAuditService HandleOrganizationAuditCheck. ExceptionMessage: {ex.Message}");
}
}
public async Task<List<long>> AuditDNAOrganizationForTimePeriod(DateTime timeToSearchFrom)
{
try
{
var dnaOrganizationAuditRecords = await _scanBiCoreApiWrapperService.GetAuditOrganizationFromDateLastMaintained(timeToSearchFrom);
return dnaOrganizationAuditRecords.ToList();
}
catch (Exception ex)
{
throw new ServiceException(ex.Message);
}
}
}
@@ -0,0 +1,10 @@
using LCU.Library.Internal.LCUServiceFactory.Services;
using LCU.Library.Internal.MemberPreferencesApiModels.Entities;
using LCU.Library.Internal.MemberPreferencesApiModels.Responses;
namespace LCU.API.Internal.MemberPreferencesApi.Services.DnaAuditServices;
public interface IDNAAuditCheckService : ILcuService
{
Task<RequestResponse> ProcessRequest(DnaAuditProcessRequest request, DnaAuditProcess dnaAuditProcess);
}
@@ -0,0 +1,8 @@
using LCU.Library.Internal.CoreApiWrapperModel.CoreModels.Agreements;
namespace LCU.API.Internal.MemberPreferencesApi.Services.DnaAuditServices;
public interface IDNAAuditHelperService
{
Task UpdateAccountDeliveryMethodIfNotEqualToMemberPreference(AgreementAccount account);
}
@@ -4,8 +4,5 @@ namespace LCU.API.Internal.MemberPreferencesApi.Services.DnaAuditServices;
public interface IDNADataAuditProcessService public interface IDNADataAuditProcessService
{ {
Task RunDataAuditProcesses(); Task HandleDnaAuditProcessRequest(DnaAuditProcessRequest request);
Task AuditDNAOrganizationForTimePeriod(DateTime timeToSearchFrom, DnaAuditProcess dnaProcess);
Task AuditDNAAgreementForTimePeriod(DateTime timeToSearchFrom, DnaAuditProcess dnaProcess);
Task AuditDNAAccountsForTimePeriod(DateTime timeToSearchFrom, DnaAuditProcess dnaProcess);
} }
@@ -1,8 +0,0 @@
namespace LCU.API.Internal.MemberPreferencesApi.Services.DnaAuditServices;
public interface IDNADataAuditService
{
Task HandleAccountAuditCheck(DnaFieldChangeRequest dnaFieldChange);
Task HandleAgreementAuditCheck(DnaFieldChangeRequest dnaFieldChange);
Task HandleOrganizationAuditCheck(DnaFieldChangeRequest dnaFieldChange);
}
@@ -1,56 +0,0 @@
using LCU.API.Internal.MemberPreferencesApi.Services.DnaAuditServices;
using NCrontab;
namespace LCU.API.Internal.MemberPreferencesApi.HostedServices
{
public class HostedDnaDataAuditProcessService : BackgroundService
{
private readonly IServiceScopeFactory _scopeFactory;
private CancellationToken _cancellationToken;
private ApiConfiguration _memberPreferencesConfig;
private readonly CrontabSchedule _cleanUpJobSchedule;
private DateTime _nextScheduleRun;
public HostedDnaDataAuditProcessService(ApiConfiguration appConfig,
IServiceScopeFactory scopeFactory)
{
_scopeFactory = scopeFactory;
_memberPreferencesConfig = appConfig;
_cleanUpJobSchedule = CrontabSchedule.Parse(_memberPreferencesConfig.DnaDataAuditProcessCronSchedule);
_nextScheduleRun = _cleanUpJobSchedule.GetNextOccurrence(DateTime.Now);
_cancellationToken = new CancellationToken();
}
protected override async Task ExecuteAsync(CancellationToken cancellationToken)
{
Log.Information("Hosted DNADataAuditProcessService is starting, for DNA Member Preferences Audit.");
_cancellationToken = cancellationToken;
try
{
while (!cancellationToken.IsCancellationRequested)
{
if (DateTime.Now > _nextScheduleRun)
{
using (var scope = _scopeFactory.CreateScope())
{
await scope.ServiceProvider.GetRequiredService<IDNADataAuditProcessService>().RunDataAuditProcesses();
}
}
await Task.Delay(UntilNextExecution(), cancellationToken);
}
}
catch (TaskCanceledException ex) when (cancellationToken.IsCancellationRequested)
{
Log.Information(ex, "Hosted DnaDataAuditProcessService was shut down normally.");
}
catch (Exception ex)
{
Log.Error(ex, "Error in main thread for DnaDataAuditProcessService");
}
Log.Information("Hosted DnaDataAuditProcessService is stopping.");
}
private int UntilNextExecution() => Math.Max(0, (int)_nextScheduleRun.Subtract(DateTime.Now).TotalMilliseconds);
}
}
@@ -1,57 +0,0 @@
using LCU.API.Internal.MemberPreferencesApi.Services.XdiServices;
using NCrontab;
namespace LCU.API.Internal.MemberPreferencesApi.HostedServices;
public class HostedXdiBatchProcessService : BackgroundService
{
private readonly IServiceScopeFactory _scopeFactory;
private CancellationToken _cancellationToken;
private ApiConfiguration _apiConfiguration;
private XdiSftpApiConfiguration _xdiSftpApiConfiguration;
private readonly CrontabSchedule _cleanUpJobSchedule;
private DateTime _nextScheduleRun;
public HostedXdiBatchProcessService(ApiConfiguration apiConfiguration, XdiSftpApiConfiguration xdiSftpApiConfiguration, IServiceScopeFactory scopeFactory)
{
_scopeFactory = scopeFactory;
_apiConfiguration = apiConfiguration;
_xdiSftpApiConfiguration = xdiSftpApiConfiguration;
_cleanUpJobSchedule = CrontabSchedule.Parse(_apiConfiguration.XdiBatchProcessCronSchedule);
_nextScheduleRun = _cleanUpJobSchedule.GetNextOccurrence(DateTime.Now);
_cancellationToken = new CancellationToken();
}
protected override async Task ExecuteAsync(CancellationToken cancellationToken)
{
Log.Information("Hosted XDI Batch Service is starting");
_cancellationToken = cancellationToken;
try
{
while (!cancellationToken.IsCancellationRequested)
{
if (DateTime.Now > _nextScheduleRun)
{
using (var scope = _scopeFactory.CreateScope())
{
await scope.ServiceProvider.GetRequiredService<IXdiBatchProcessService>().RunXdiBatchProcess(_xdiSftpApiConfiguration.SftpRootBasePath);
}
_nextScheduleRun = _cleanUpJobSchedule.GetNextOccurrence(DateTime.Now);
}
await Task.Delay(UntilNextExecution(), cancellationToken);
}
}
catch (TaskCanceledException ex) when (cancellationToken.IsCancellationRequested)
{
Log.Information(ex, "Hosted XdiBatchService was shut down normally");
}
catch (Exception ex)
{
Log.Error(ex, "Error in main thread for XdiBatchService");
}
Log.Information("Hosted XdiBatchService is stopping");
}
private int UntilNextExecution() => Math.Max(0, (int)_nextScheduleRun.Subtract(DateTime.Now).TotalMilliseconds);
}
@@ -127,20 +127,6 @@ namespace LCU.API.Internal.MemberPreferencesApi.MicroApiServices
} }
} }
public async Task<IEnumerable<long>> GetAuditOrganizationFromDateLastMaintained(DateTime dateTime)
{
try
{
return await _coreApiWrapperDao.GetAuditOrganizationFromDateLastMaintained(dateTime);
}
catch (Exception ex)
{
var error = $"Failed to GetAuditOrganizationFromDateLastMaintained. DateTime: {dateTime} Exception Message: {ex.Message}";
Log.Error(error);
throw new ServiceException(error);
}
}
public async Task UpdateAgreementAccountsDeliveryMethod(IEnumerable<long> accountIds, string deliveryMethod, string userId) public async Task UpdateAgreementAccountsDeliveryMethod(IEnumerable<long> accountIds, string deliveryMethod, string userId)
{ {
try try
@@ -0,0 +1,32 @@
using LCU.API.Internal.MemberPreferencesApi.DataAccess;
using LCU.Library.Internal.FileOperationsModels.Models;
namespace LCU.API.Internal.MemberPreferencesApi.MicroApiServices
{
public class FileOperationsApiService : IFileOperationsApiService
{
private readonly IFileOperationsApiDao _fileOperationsApiDao;
public FileOperationsApiService(IFileOperationsApiDao fileOperationsApiDao)
{
_fileOperationsApiDao = fileOperationsApiDao;
}
public async Task<RequestResponse> AppendFile(AppendFileRequest request)
{
try
{
var result = await _fileOperationsApiDao.AppendFileAsync(request);
Log.Information($"XDI File Sent, Response: {result.ReturnResponse}");
return result;
}
catch (Exception ex)
{
var error = $"Failed to create XDI Direct File. Exception Message: {ex.Message}";
Log.Error(error);
throw new ServiceException(error);
}
}
}
}
@@ -1,30 +0,0 @@
using LCU.Api.Internal.FTPLib.Models;
using LCU.API.Internal.MemberPreferencesApi.DataAccess;
namespace LCU.API.Internal.MemberPreferencesApi.MicroApiServices
{
public class FtpApiService : IFtpApiService
{
private readonly IFtpApiDao _ftpApiDao;
public FtpApiService(IFtpApiDao ftpApiDao)
{
_ftpApiDao = ftpApiDao;
}
public async Task SendXdiFtpRequest(SshFtpRequest request)
{
try
{
await _ftpApiDao.SendFtpAsync(request);
Log.Information($"XDI Ftp Sent: {request.RemoteFilePath}");
}
catch (Exception ex)
{
var error = $"Failed to send FTP file. Exception Message: {ex.Message}";
Log.Error(error);
throw new ServiceException(error);
}
}
}
}
@@ -12,6 +12,5 @@ public interface ICoreApiWrapperService
public Task<IEnumerable<AgreementAccount>> GetAgreementAccountsByOrganizationId(long organizationId); public Task<IEnumerable<AgreementAccount>> GetAgreementAccountsByOrganizationId(long organizationId);
public Task<IEnumerable<long>> GetAuditAccountsFromDateLastMaintained(DateTime dateTime); public Task<IEnumerable<long>> GetAuditAccountsFromDateLastMaintained(DateTime dateTime);
public Task<IEnumerable<long>> GetAuditAgreementFromDateLastMaintained(DateTime dateTime); public Task<IEnumerable<long>> GetAuditAgreementFromDateLastMaintained(DateTime dateTime);
public Task<IEnumerable<long>> GetAuditOrganizationFromDateLastMaintained(DateTime dateTime);
public Task UpdateAgreementAccountsDeliveryMethod(IEnumerable<long> accountIds, string deliveryMethod, string userId); public Task UpdateAgreementAccountsDeliveryMethod(IEnumerable<long> accountIds, string deliveryMethod, string userId);
} }
@@ -0,0 +1,8 @@
using LCU.Library.Internal.FileOperationsModels.Models;
namespace LCU.API.Internal.MemberPreferencesApi.MicroApiServices;
public interface IFileOperationsApiService
{
public Task<RequestResponse> AppendFile(AppendFileRequest request);
}
@@ -1,8 +0,0 @@
using LCU.Api.Internal.FTPLib.Models;
namespace LCU.API.Internal.MemberPreferencesApi.MicroApiServices;
public interface IFtpApiService
{
public Task SendXdiFtpRequest(SshFtpRequest request);
}
@@ -0,0 +1,7 @@
namespace LCU.API.Internal.MemberPreferencesApi.MicroApiServices
{
public interface IScanBiCoreApiWrapperService
{
public Task<IEnumerable<long>> GetAuditOrganizationFromDateLastMaintained(DateTime dateTime);
}
}
@@ -66,7 +66,7 @@ public class NotificationService : INotificationService
var filteredRecipients = recipients.Distinct(StringComparer.InvariantCultureIgnoreCase).ToList(); var filteredRecipients = recipients.Distinct(StringComparer.InvariantCultureIgnoreCase).ToList();
var subject = "Paper Statement Enrollment"; var subject = "Paper Statement Enrollment";
var message = var message =
$"<div style=\"padding: 2em;\"><p style=\"color: #0054a4;\"><strong>You have enrolled to receive paper for your statements and notices.</strong></p><p>You have selected to receive paper statements and notices. You will no longer be able to view these documents online or on your mobile device.</p><p>With electronic statements through Landmark Credit Union Digital Banking, you&rsquo;ll be able to:</p><ul><li>View your statements and tax documents online or on your mobile device</li><li>Maintain your own secure online archive</li><li>Help the environment by reducing paper and clutter</li></ul><p>Please note, some accounts may have promotional rates or offers that require paperless statements and electing to receive paper may impact offers on your account. Please refer to your account Truth in Savings disclosure for more information. If you need to make changes to any of your preferences, you can visit Manage Delivery Preferences under Statements &amp; Notices.</p><div style=\"color: #959ba6;\"><center><p style=\"margin:0px;\">You are receiving this email because you requested to receive paper statements and notices. If you did not make this selection or believe this is in error, please contact us.</p><p style=\"margin:0px;\"><a href=\"http://www.landmarkcu.com/\">Landmark Credit Union</a> | <a href=\"https://landmarkcu.com/contact-us/\">Contact Us</a></p><p style=\"margin:0px;\">Landmark Credit Union</p><p style=\"margin:0px;\">&copy; 2021 All rights reserved</p></center></div></div>"; $"<div style=\"padding: 2em;\"><p style=\"color: #0054a4;\"><strong>You have enrolled to receive paper for your statements and notices.</strong></p><p>You have selected to receive paper statements and notices. You will no longer be able to view these documents online or on your mobile device.</p><p>With electronic documents through Landmark Credit Union Digital Banking, you&rsquo;ll be able to:</p><ul><li>View your statements and tax documents online or on your mobile device</li><li>Maintain your own secure online archive</li><li>Help the environment by reducing paper and clutter</li></ul><p>Please note that this change in delivery method could impact fees, offers, and earnings tied to some account requirements. Please refer to your recent offers, account Truth in Savings disclosure, and current fee schedule for more information. If you need to make changes to any of your preferences, you can visit Manage Delivery Preferences under Statements &amp; Notices.</p><div style=\"color: #959ba6;\"><center><p style=\"margin:0px;\">You are receiving this email because you requested to receive paper statements and notices. If you did not make this selection or believe this is in error, please contact us.</p><p style=\"margin:0px;\"><a href=\"http://www.landmarkcu.com/\">Landmark Credit Union</a> | <a href=\"https://landmarkcu.com/contact-us/\">Contact Us</a></p><p style=\"margin:0px;\">Landmark Credit Union</p><p style=\"margin:0px;\">&copy; 2021 All rights reserved</p></center></div></div>";
await SendMessageAsync(filteredRecipients, subject, message); await SendMessageAsync(filteredRecipients, subject, message);
} }
@@ -0,0 +1,28 @@
using LCU.API.Internal.MemberPreferencesApi.DataAccess;
namespace LCU.API.Internal.MemberPreferencesApi.MicroApiServices;
public class ScanBiCoreApiWrapperService : IScanBiCoreApiWrapperService
{
private readonly IScanBiCoreApiWrapperDao _scanBiCoreApiWrapperDao;
public ScanBiCoreApiWrapperService(IScanBiCoreApiWrapperDao scanBiCoreApiWrapperDao)
{
_scanBiCoreApiWrapperDao = scanBiCoreApiWrapperDao;
}
public async Task<IEnumerable<long>> GetAuditOrganizationFromDateLastMaintained(DateTime dateTime)
{
try
{
return await _scanBiCoreApiWrapperDao.GetAuditOrganizationFromDateLastMaintained(dateTime);
}
catch (Exception ex)
{
var error = $"Failed to GetAuditOrganizationFromDateLastMaintained. DateTime: {dateTime} Exception Message: {ex.Message}";
Log.Error(error);
throw new ServiceException(error);
}
}
}
@@ -1,6 +0,0 @@
namespace LCU.API.Internal.MemberPreferencesApi.Services.QueueServices;
public interface IQueueDnaAccountAuditService
{
Task QueueDataAuditForAccounts(List<long> accountNumbers, int consecutiveFailures = 0);
}
@@ -1,6 +0,0 @@
namespace LCU.API.Internal.MemberPreferencesApi.Services.QueueServices;
public interface IQueueDnaAgreementAuditService
{
Task QueueDataAuditForAgreements(List<long> agreementAuditRecords, int consecutiveFailures = 0);
}
@@ -0,0 +1,6 @@
namespace LCU.API.Internal.MemberPreferencesApi.Services.QueueServices;
public interface IQueueDnaAuditProcessService
{
Task QueueDnaAuditProcessRequest(DnaAuditProcessRequest request);
}
@@ -1,6 +0,0 @@
namespace LCU.API.Internal.MemberPreferencesApi.Services.QueueServices;
public interface IQueueDnaOrganizationAuditService
{
Task QueueDataAuditForOrganizations(List<long> organizationNumbers, int consecutiveFailures = 0);
}
@@ -0,0 +1,6 @@
namespace LCU.API.Internal.MemberPreferencesApi.Services.QueueServices;
public interface IQueueXdiBatchProcessService
{
Task QueueXdiBatchProcess(XdiBatchProcessRequest request);
}
@@ -1,6 +0,0 @@
namespace LCU.API.Internal.MemberPreferencesApi.Services.QueueServices;
public interface IQueueXdiBatchService
{
Task QueueXdiBatchProcess(XdiBatchRequest request);
}
@@ -1,44 +0,0 @@
using LCU.Library.Internal.LcuMassTransitModels;
using LCU.Library.Internal.MemberPreferencesApiModels.Enums;
using MassTransit;
namespace LCU.API.Internal.MemberPreferencesApi.Services.QueueServices
{
public class QueueDnaAccountAuditService : IQueueDnaAccountAuditService
{
private readonly ISendEndpoint _sendEndpoint;
private readonly ReceiveEndpointConfiguration _dnaAccountAuditReceiveEndpoint;
public QueueDnaAccountAuditService(IBusControl busControl, ReceiveEndpointConfigurations receiveEndpointConfigurations)
{
_dnaAccountAuditReceiveEndpoint = receiveEndpointConfigurations.DnaAccountAuditEndpoint;
_sendEndpoint = busControl.GetSendEndpoint(_dnaAccountAuditReceiveEndpoint.ReceiveEndpointUri).Result;
}
public async Task QueueDataAuditForAccounts(List<long> accountAuditRecords, int consecutiveFailures = 0)
{
try
{
foreach (var account in accountAuditRecords)
{
var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(30));
var request = new DnaFieldChangeRequest()
{
DnaFieldIdInformation = account,
ConsecutiveFailures = consecutiveFailures,
DnaProcessType = DnaAuditProcessType.DNAAccounts,
LastUpdated = DateTime.UtcNow,
ProcessId = 2
};
await _sendEndpoint.Send(request, cancellationTokenSource.Token);
};
}
catch (Exception ex)
{
Log.ForContext(Enum.GetName(typeof(PropertyEnum), PropertyEnum.Group), Enum.GetName(typeof(GroupEnum), GroupEnum.ITDevelopment))
.Error(ex, "Failed to Queue MemberPreference DNA Account Audit records.");
throw;
}
}
}
}
@@ -1,43 +0,0 @@
using LCU.Library.Internal.LcuMassTransitModels;
using LCU.Library.Internal.MemberPreferencesApiModels.Enums;
using MassTransit;
namespace LCU.API.Internal.MemberPreferencesApi.Services.QueueServices;
public class QueueDnaAgreementAuditService : IQueueDnaAgreementAuditService
{
private readonly ISendEndpoint _sendEndpoint;
private readonly ReceiveEndpointConfiguration _dnaAuditAgreementReceiveEndpoint;
public QueueDnaAgreementAuditService(IBusControl busControl, ReceiveEndpointConfigurations receiveEndpointConfigurations)
{
_dnaAuditAgreementReceiveEndpoint = receiveEndpointConfigurations.DnaAgreementAuditEndpoint;
_sendEndpoint = busControl.GetSendEndpoint(_dnaAuditAgreementReceiveEndpoint.ReceiveEndpointUri).Result;
}
public async Task QueueDataAuditForAgreements(List<long> agreementAuditRecords, int consecutiveFailures = 0)
{
try
{
foreach (var agreement in agreementAuditRecords)
{
var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(30));
var request = new DnaFieldChangeRequest()
{
DnaFieldIdInformation = agreement,
ConsecutiveFailures = consecutiveFailures,
DnaProcessType = DnaAuditProcessType.DNAAgreement,
LastUpdated = DateTime.UtcNow,
ProcessId = 1
};
await _sendEndpoint.Send(request, cancellationTokenSource.Token);
}
}
catch (Exception ex)
{
Log.ForContext(Enum.GetName(typeof(PropertyEnum), PropertyEnum.Group), Enum.GetName(typeof(GroupEnum), GroupEnum.ITDevelopment))
.Error(ex, "Failed to Queue MemberPreference DNA Account Audit records.");
throw;
}
}
}
@@ -0,0 +1,31 @@
using LCU.Library.Internal.LcuMassTransitModels;
using MassTransit;
namespace LCU.API.Internal.MemberPreferencesApi.Services.QueueServices;
public class QueueDnaAuditProcessService : IQueueDnaAuditProcessService
{
private readonly ISendEndpoint _sendEndpoint;
public QueueDnaAuditProcessService(IBusControl busControl, ReceiveEndpointConfigurations receiveEndpointConfigurations)
{
_sendEndpoint = busControl.GetSendEndpoint(receiveEndpointConfigurations.DnaAuditProcessEndpoint.ReceiveEndpointUri).Result;
}
public async Task QueueDnaAuditProcessRequest(DnaAuditProcessRequest request)
{
try
{
var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(30));
await _sendEndpoint.Send(request, cancellationTokenSource.Token);
}
catch (Exception ex)
{
Log.ForContext(Enum.GetName(typeof(PropertyEnum), PropertyEnum.Group),
Enum.GetName(typeof(GroupEnum), GroupEnum.ITDevelopment))
.Error(ex, "Failed to Queue DnaAuditProcess Request.");
throw new ServiceException("Failed to Queue DnaAuditProcess Request.");
}
}
}
@@ -1,44 +0,0 @@
using LCU.Library.Internal.LcuMassTransitModels;
using LCU.Library.Internal.MemberPreferencesApiModels.Enums;
using MassTransit;
namespace LCU.API.Internal.MemberPreferencesApi.Services.QueueServices;
public class QueueDnaOrganizationService : IQueueDnaOrganizationAuditService
{
private readonly ISendEndpoint _sendEndpoint;
private readonly ReceiveEndpointConfiguration _dnaAuditOrganizationReceiveEndpoint;
public QueueDnaOrganizationService(IBusControl busControl, ReceiveEndpointConfigurations receiveEndpointConfigurations)
{
_dnaAuditOrganizationReceiveEndpoint = receiveEndpointConfigurations.DnaOrganizationAuditEndpoint;
_sendEndpoint = busControl.GetSendEndpoint(_dnaAuditOrganizationReceiveEndpoint.ReceiveEndpointUri).Result;
}
public async Task QueueDataAuditForOrganizations(List<long> organizationAuditRecords, int consecutiveFailures = 0)
{
try
{
foreach (var organization in organizationAuditRecords)
{
var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(30));
var request = new DnaFieldChangeRequest()
{
DnaFieldIdInformation = organization,
ConsecutiveFailures = consecutiveFailures,
DnaProcessType = DnaAuditProcessType.DNAOrganization,
LastUpdated = DateTime.UtcNow,
ProcessId = 3
};
await _sendEndpoint.Send(request, cancellationTokenSource.Token);
}
}
catch (Exception ex)
{
Log.ForContext(Enum.GetName(typeof(PropertyEnum), PropertyEnum.Group), Enum.GetName(typeof(GroupEnum), GroupEnum.ITDevelopment))
.Error(ex, "Failed to Queue MemberPreference DNA Account Audit records.");
throw;
}
}
}
@@ -3,18 +3,17 @@ using MassTransit;
namespace LCU.API.Internal.MemberPreferencesApi.Services.QueueServices namespace LCU.API.Internal.MemberPreferencesApi.Services.QueueServices
{ {
public class QueueXdiBatchService : IQueueXdiBatchService public class QueueXdiBatchProcessService : IQueueXdiBatchProcessService
{ {
private readonly ISendEndpoint _sendEndpoint; private readonly ISendEndpoint _sendEndpoint;
private readonly ReceiveEndpointConfiguration _xdiServiceEndpoint; private readonly ReceiveEndpointConfiguration _xdiServiceEndpoint;
public QueueXdiBatchService(IBusControl busControl, ReceiveEndpointConfigurations receiveEndpointConfigurations) public QueueXdiBatchProcessService(IBusControl busControl, ReceiveEndpointConfigurations receiveEndpointConfigurations)
{ {
_xdiServiceEndpoint = receiveEndpointConfigurations.XdiBatchProcessEndpoint; _xdiServiceEndpoint = receiveEndpointConfigurations.XdiBatchProcessEndpoint;
_sendEndpoint = busControl.GetSendEndpoint(_xdiServiceEndpoint.ReceiveEndpointUri).Result; _sendEndpoint = busControl.GetSendEndpoint(_xdiServiceEndpoint.ReceiveEndpointUri).Result;
} }
public async Task QueueXdiBatchProcess(XdiBatchProcessRequest request)
public async Task QueueXdiBatchProcess(XdiBatchRequest request)
{ {
try try
{ {
@@ -2,5 +2,5 @@ namespace LCU.API.Internal.MemberPreferencesApi.Services.XdiServices;
public interface IXdiBatchProcessService public interface IXdiBatchProcessService
{ {
Task RunXdiBatchProcess(string sftpRootBasePath); Task HandleXdiBatchProcess(XdiBatchProcessRequest xdiBatchProcessRequest);
} }
@@ -1,17 +1,15 @@
using LCU.API.Internal.MemberPreferencesApi.Models; using LCU.API.Internal.MemberPreferencesApi.Models;
using LCU.Library.Internal.MemberPreferencesApiModels.Entities; using LCU.Library.Internal.MemberPreferencesApiModels.Entities;
using ApiResponse = LCU.Library.Internal.ApiResponse.Models;
namespace LCU.API.Internal.MemberPreferencesApi.Services.XdiServices; namespace LCU.API.Internal.MemberPreferencesApi.Services.XdiServices;
public interface IXdiBatchService public interface IXdiBatchService
{ {
Task AddXdiBatchItem(XdiBatchItem newItem); Task AddXdiBatchItem(XdiBatchItem newItem);
Task SaveRangeAsync(List<XdiBatchItem> xdiBatchItemList);
Task CreateXdiBatchFiles(XdiBatchRequest request); Task CreateXdiBatchFiles(XdiBatchRequest request);
Task<XdiBatchRequest> BuildXdiBatchRequest(XdiBatchRequest request); Task<XdiBatchRequest> BuildXdiBatchRequest(XdiBatchRequest request);
Task HandleFtpProcess(XdiBatchRequest request); Task<List<XdiBatchFileExport>> BuildXdiFiles(XdiBatchFile batchFile, string filePath, XdiBatchProcessInfo xdiBatchProcessInfo);
Task<bool> RequestFtpTransport(IReadOnlyCollection<XdiBatchFile> files); Task<bool> MarkPendingSuccessful(List<XdiBatchFileExport> batchFileExportList);
Task<bool> MarkPendingSuccessful(ApiResponse.Response response);
Task<List<FtpQueuePayloadItem>> CreateFtpPayload(XdiBatchFile xdiBatchFile);
Task<bool> DoesMemberHavePendingXdiChange(string memberId); Task<bool> DoesMemberHavePendingXdiChange(string memberId);
} }
@@ -1,22 +1,22 @@
using LCU.API.Internal.MemberPreferencesApi.Models; using LCU.API.Internal.MemberPreferencesApi.Models;
using LCU.API.Internal.MemberPreferencesApi.Services.QueueServices;
using LCU.API.Internal.MemberPreferencesApiLib.Repositories; using LCU.API.Internal.MemberPreferencesApiLib.Repositories;
using LCU.Library.Internal.ApiResponse.Services;
using LCU.Library.Internal.MemberPreferencesApiModels.Enums; using LCU.Library.Internal.MemberPreferencesApiModels.Enums;
namespace LCU.API.Internal.MemberPreferencesApi.Services.XdiServices; namespace LCU.API.Internal.MemberPreferencesApi.Services.XdiServices;
public class XdiBatchProcessService : IXdiBatchProcessService public class XdiBatchProcessService : IXdiBatchProcessService
{ {
private readonly IXdiBatchItemsRepository _xdiBatchItemsRepository; private readonly IXdiBatchItemsRepository _xdiBatchItemsRepository;
private readonly IQueueXdiBatchService _queueXdiBatchService; private readonly IXdiBatchService _xdiBatchService;
public XdiBatchProcessService(IQueueXdiBatchService queueXdiBatchService, IXdiBatchItemsRepository xdiBatchItemsRepository) public XdiBatchProcessService(IXdiBatchService xdiBatchService, IXdiBatchItemsRepository xdiBatchItemsRepository)
{ {
_xdiBatchItemsRepository = xdiBatchItemsRepository; _xdiBatchItemsRepository = xdiBatchItemsRepository;
_queueXdiBatchService = queueXdiBatchService; _xdiBatchService = xdiBatchService;
} }
public async Task RunXdiBatchProcess(string sftpRootBasePath) public async Task HandleXdiBatchProcess(XdiBatchProcessRequest xdiBatchProcessRequest)
{ {
try try
{ {
@@ -33,17 +33,19 @@ public class XdiBatchProcessService : IXdiBatchProcessService
{ {
XdiBatch = xdiBatch, XdiBatch = xdiBatch,
XdiBatchItems = xdiBatchItems.ToList(), XdiBatchItems = xdiBatchItems.ToList(),
SftpRootBasePath = sftpRootBasePath XdiAppendFileRootBasePath = xdiBatchProcessRequest.XdiAppendFileRootBasePath
}; };
await _queueXdiBatchService.QueueXdiBatchProcess(request); await _xdiBatchService.CreateXdiBatchFiles(request);
await QueueReturnResponse.QueueResponse(xdiBatchProcessRequest, true, new List<string> { $"Requested {xdiBatchItems.Count()} Xdi Batch Items to Process."});
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
var error = $"Failed to Run XdiBatchProcess. Exception Message: {ex.Message}"; var errorMessage = $"Failed to HandleXdiBatchProcess. Exception Message: {ex.Message}";
Log.Error(error); Log.Error(errorMessage);
throw new ServiceException(error); await QueueReturnResponse.QueueResponse(xdiBatchProcessRequest, false, new List<string>() {errorMessage});
throw new ServiceException(errorMessage);
} }
} }
} }
@@ -1,64 +1,64 @@
using ApiResponse = LCU.Library.Internal.ApiResponse.Models;
using LCU.API.Internal.MemberPreferencesApi.MicroApiServices; using LCU.API.Internal.MemberPreferencesApi.MicroApiServices;
using LCU.API.Internal.MemberPreferencesApi.Models;
using LCU.API.Internal.MemberPreferencesApiLib.Repositories; using LCU.API.Internal.MemberPreferencesApiLib.Repositories;
using LCU.Api.Internal.FTPLib.Models; using LCU.Library.Internal.FileOperationsModels.Models;
using LCU.Library.Internal.ApiResponse.Models; using LCU.Library.Internal.LcuClassPatterns.Crud.Services;
using LCU.Library.Internal.LcuMassTransitModels;
using LCU.Library.Internal.MemberPreferencesApiModels.Entities; using LCU.Library.Internal.MemberPreferencesApiModels.Entities;
using LCU.Library.Internal.MemberPreferencesApiModels.Enums; using LCU.Library.Internal.MemberPreferencesApiModels.Enums;
using LCU.API.Internal.MemberPreferencesApi.Models; using System.Data.SqlClient;
using Newtonsoft.Json;
namespace LCU.API.Internal.MemberPreferencesApi.Services.XdiServices namespace LCU.API.Internal.MemberPreferencesApi.Services.XdiServices
{ {
public class XdiBatchService : IXdiBatchService public class XdiBatchService : CrudService<XdiBatchProcessInfo>, IXdiBatchService
{ {
private readonly IXdiBatchProcessInfoRepository _xdiBatchProcessInfoRepository;
private readonly IXdiBatchItemsRepository _xdiBatchItemsRepository; private readonly IXdiBatchItemsRepository _xdiBatchItemsRepository;
private readonly IUnifiedOptInRepository _unifiedOptInRepository; private readonly IUnifiedOptInRepository _unifiedOptInRepository;
private readonly IMemberPreferenceRepository _memberPreferenceRepository; private readonly IMemberPreferenceRepository _memberPreferenceRepository;
private readonly ConnectionConfiguration _connectionConfiguration;
private readonly ReceiveEndpointConfiguration _completionReceiveEndpoint;
private readonly IUnitOfWork _unitOfWork; private readonly IUnitOfWork _unitOfWork;
private readonly XdiSftpApiConfiguration _xdiSftpApiConfiguration; private readonly IFileOperationsApiService _fileOperationsApiService;
private readonly IFtpApiService _ftpApiService;
private const string XdiBatchProcessOperatorName = "XdiBatchProcess"; private const string XdiBatchProcessOperatorName = "XdiBatchProcess";
public XdiBatchService(IXdiBatchItemsRepository xdiBatchItemsRepository, IUnitOfWork unitOfWork, public XdiBatchService(IXdiBatchItemsRepository xdiBatchItemsRepository,
XdiSftpApiConfiguration xdiSftpApiConfiguration, IUnifiedOptInRepository unifiedOptInRepository, IUnitOfWork unitOfWork, IUnifiedOptInRepository unifiedOptInRepository,
IMemberPreferenceRepository memberPreferenceRepository, ConnectionConfiguration connectionConfiguration, IMemberPreferenceRepository memberPreferencesRepository, IFileOperationsApiService fileOperationsApiService,
ReceiveEndpointConfigurations receiveEndpointsConfigurations, IFtpApiService ftpApiService) IXdiBatchProcessInfoRepository xdiBatchProcessInfoRepository) : base(xdiBatchProcessInfoRepository)
{ {
_xdiBatchItemsRepository = xdiBatchItemsRepository; _xdiBatchItemsRepository = xdiBatchItemsRepository;
_unitOfWork = unitOfWork; _unitOfWork = unitOfWork;
_xdiSftpApiConfiguration = xdiSftpApiConfiguration; _memberPreferenceRepository = memberPreferencesRepository;
_unifiedOptInRepository = unifiedOptInRepository; _unifiedOptInRepository = unifiedOptInRepository;
_memberPreferenceRepository = memberPreferenceRepository; _fileOperationsApiService = fileOperationsApiService;
_connectionConfiguration = connectionConfiguration; _xdiBatchProcessInfoRepository = xdiBatchProcessInfoRepository;
_ftpApiService = ftpApiService;
_completionReceiveEndpoint = receiveEndpointsConfigurations.XdiBatchConfirmEndpoint;
} }
public async Task CreateXdiBatchFiles(XdiBatchRequest request) public async Task CreateXdiBatchFiles(XdiBatchRequest request)
{ {
var batchProcessInfo = new XdiBatchProcessInfo();
var batchUserIds = string.Join(",", request.XdiBatchItems.Select(c => c.UserId).ToList());
try try
{ {
if (!request.XdiBatchItems.Any()) var batchProcessInProgress = _xdiBatchProcessInfoRepository.FindBatchProcessInfoByStatus(XdiBatchProcessStatus.InProgress).Result;
if (batchProcessInProgress.Count() == 0)
{ {
return; request = await BuildXdiBatchRequest(request);
} batchProcessInfo = await CreateNewBatchProcessInfo(request.XdiBatchItems.Count());
await CreateXdiExportFileRequest(request, batchProcessInfo);
request = await BuildXdiBatchRequest(request); await UpdateBatchAsync(batchProcessInfo, XdiBatchProcessStatus.Completed, $"Completed XDI Batch Process for UserIds: {batchUserIds}");
await HandleFtpProcess(request); }
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex, $"Failed to Create XDI Batch Files."); Log.Error(ex, $"Failed to Create XDI Batch Files.");
await UpdateBatchAsync(batchProcessInfo, XdiBatchProcessStatus.Failed, $"Failed XDI Batch Process for UserIds: {batchUserIds}");
throw new ServiceException($"Failed to Create XDI Batch Files. Exception Message: {ex.Message}");
} }
} }
public async Task<XdiBatchRequest> BuildXdiBatchRequest(XdiBatchRequest request) public async Task<XdiBatchRequest> BuildXdiBatchRequest(XdiBatchRequest request)
{ {
foreach (var item in request.XdiBatchItems) foreach (var item in request.XdiBatchItems)
{ {
var currentSettings = await _unifiedOptInRepository.GetMemberOptInSettings(item.UserId); var currentSettings = await _unifiedOptInRepository.GetMemberOptInSettings(item.UserId);
if (currentSettings != null) if (currentSettings != null)
@@ -74,11 +74,11 @@ namespace LCU.API.Internal.MemberPreferencesApi.Services.XdiServices
BatchState = BatchState.TransferPending, BatchState = BatchState.TransferPending,
LastUpdated = DateTime.UtcNow LastUpdated = DateTime.UtcNow
}); });
Log.Information($"Hosted XDI Sync processed batch item with UserId: {item.UserId}"); Log.Information($"XdiBatchService processed batch item with UserId: {item.UserId}");
} }
else else
{ {
Log.Error($"Row not processed in XDI Audit for member with UserId: {item.UserId}, marking complete."); Log.Error($"No XdiBatchRow or XDI File was processed based on current member UserId: {item.UserId} Opt In Settings, marking complete.");
_xdiBatchItemsRepository.Delete(item); _xdiBatchItemsRepository.Delete(item);
} }
}; };
@@ -89,71 +89,49 @@ namespace LCU.API.Internal.MemberPreferencesApi.Services.XdiServices
return request; return request;
} }
public async Task HandleFtpProcess(XdiBatchRequest request) public async Task CreateXdiExportFileRequest(XdiBatchRequest request, XdiBatchProcessInfo xdiBatchProcessInfo)
{ {
try try
{ {
IReadOnlyCollection<XdiBatchFile> batchFiles = request.XdiBatch.GetNonEmptyFiles(request.SftpRootBasePath); IReadOnlyCollection<XdiBatchFile> batchFiles = request.XdiBatch.GetNonEmptyFiles();
Log.Information($"Hosted XDI Sync produced {batchFiles.Count} files"); Log.Information($"XdiBatchService produced {batchFiles.Count} files");
bool results = await RequestFtpTransport(batchFiles); foreach (var xdiBatchFile in batchFiles)
string resultDescription = results ? "Success" : "Failure"; {
Log.Information($"Hosted XDI Sync Ftp Results...{resultDescription}"); var xdiBatchFileExport = await BuildXdiFiles(xdiBatchFile, request.XdiAppendFileRootBasePath, xdiBatchProcessInfo);
await MarkPendingSuccessful(xdiBatchFileExport);
}
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex, $"Failed to Handle FTP Process."); Log.Error(ex, $"Failed to Create the XDI File to export.");
} }
} }
public async Task<bool> RequestFtpTransport(IReadOnlyCollection<XdiBatchFile> files) public async Task<List<XdiBatchFileExport>> BuildXdiFiles(XdiBatchFile batchFile, string filePath, XdiBatchProcessInfo xdiBatchProcessInfo)
{ {
SshFtpRequest request = BuildFtpRequest(); AppendFileRequest request = BuildFileOperationsRequest(batchFile, filePath);
var xdiBatchFileExport = await CreateDirectoryXdiFiles(batchFile);
foreach (var xdiBatchFile in files) var result = await _fileOperationsApiService.AppendFile(request);
{
request.LocalFileData = xdiBatchFile.ConvertToDataFile(); return xdiBatchFileExport;
request.RemoteFilePath = xdiBatchFile.GetFileName();
var payload = await CreateFtpPayload(xdiBatchFile);
request.ResponseItems.First().ResponsePayload = JsonConvert.SerializeObject(payload).ToString();
await _ftpApiService.SendXdiFtpRequest(request);
}
return true;
} }
private SshFtpRequest BuildFtpRequest() private AppendFileRequest BuildFileOperationsRequest(XdiBatchFile xdiBatchFile, string filePath)
{ {
var request = new SshFtpRequest() var request = new AppendFileRequest()
{ {
ResponseItems = new List<ResponseItem>() DestinationPath = filePath,
{ Extension = ".txt",
new ResponseItem() FileData = xdiBatchFile.ConvertToDataFile(),
{ FileName = xdiBatchFile.GetFileName()
ResponsePayload = "",
ReturnQueueConnectionConfig = new QueueConnectionConfig()
{
Url = _connectionConfiguration.HostUrl,
Username = _connectionConfiguration.UserName,
Password = _connectionConfiguration.Password
},
ReturnQueueConsumerConfig = new QueueConsumerConfig()
{
ExchangeName = _completionReceiveEndpoint.ReceiveEndpoint
}
}
},
HostName = _xdiSftpApiConfiguration.HostName,
Password = _xdiSftpApiConfiguration.Password,
PortNumber = _xdiSftpApiConfiguration.PortNumber,
UserName = _xdiSftpApiConfiguration.UserName
}; };
return request; return request;
} }
public async Task<List<FtpQueuePayloadItem>> CreateFtpPayload(XdiBatchFile xdiBatchFile) public async Task<List<XdiBatchFileExport>> CreateDirectoryXdiFiles(XdiBatchFile xdiBatchFile)
{ {
List<FtpQueuePayloadItem> payload = new List<FtpQueuePayloadItem>(); List<XdiBatchFileExport> batchFileExportList = new List<XdiBatchFileExport>();
var userIds = xdiBatchFile.Data.Select(x => x.UserId).ToList(); var userIds = xdiBatchFile.Data.Select(x => x.UserId).ToList();
foreach (var userId in userIds) foreach (var userId in userIds)
@@ -161,7 +139,7 @@ namespace LCU.API.Internal.MemberPreferencesApi.Services.XdiServices
var settings = await _unifiedOptInRepository.GetMemberOptInSettingsNoTracking(userId); var settings = await _unifiedOptInRepository.GetMemberOptInSettingsNoTracking(userId);
if (settings != null) if (settings != null)
{ {
payload.Add(new FtpQueuePayloadItem batchFileExportList.Add(new XdiBatchFileExport
{ {
UserId = userId, UserId = userId,
Value = settings.UniversalOptIn == DeliveryPreference.Electronic Value = settings.UniversalOptIn == DeliveryPreference.Electronic
@@ -170,22 +148,43 @@ namespace LCU.API.Internal.MemberPreferencesApi.Services.XdiServices
}); });
} }
} }
return payload; return batchFileExportList;
} }
public async Task AddXdiBatchItem(XdiBatchItem newItem) public async Task AddXdiBatchItem(XdiBatchItem newItem)
{ {
var existing = await _xdiBatchItemsRepository.FindExistingItem(newItem.UserId, BatchState.New); try
if (existing != null)
{ {
existing.LastUpdated = newItem.Created; var existing = await _xdiBatchItemsRepository.FindExistingItem(newItem.UserId, BatchState.New);
_xdiBatchItemsRepository.Update(existing); if (existing != null)
{
existing.LastUpdated = newItem.Created;
_xdiBatchItemsRepository.Update(existing);
}
else
{
await _xdiBatchItemsRepository.SaveAsync(newItem);
}
await _unitOfWork.CompleteAsync();
} }
else catch (Exception ex)
{ {
await _xdiBatchItemsRepository.SaveAsync(newItem); Log.Error($"AddXdiBatchItem userId {newItem.UserId} error: " + ex.Message);
}
}
public async Task SaveRangeAsync(List<XdiBatchItem> xdiBatchItemList)
{
try
{
await _xdiBatchItemsRepository.SaveRangeAsync(xdiBatchItemList);
await _unitOfWork.CompleteAsync();
}
catch (Exception ex)
{
Log.Error($"SaveRangeAsync method error: " + ex.Message);
} }
await _unitOfWork.CompleteAsync();
} }
public async Task<bool> DoesMemberHavePendingXdiChange(string userId) public async Task<bool> DoesMemberHavePendingXdiChange(string userId)
@@ -193,33 +192,21 @@ namespace LCU.API.Internal.MemberPreferencesApi.Services.XdiServices
return await _xdiBatchItemsRepository.FindExistingItem(userId, BatchState.TransferPending) != null; return await _xdiBatchItemsRepository.FindExistingItem(userId, BatchState.TransferPending) != null;
} }
public async Task<bool> MarkPendingSuccessful(ApiResponse.Response response) public async Task<bool> MarkPendingSuccessful(List<XdiBatchFileExport> batchFileExportList)
{ {
try try
{ {
var payloadString = response.ResponsePayload; Log.Information($"Marking {batchFileExportList.Count} Batch Items Successful.");
var payload = JsonConvert.DeserializeObject<List<FtpQueuePayloadItem>>(payloadString); var memberIds = batchFileExportList.Select(x => x.UserId);
if (!response.Successful) var pendingComplete = await _xdiBatchItemsRepository.MarkPendingSuccessful(memberIds.ToList());
{
var errorMessage = string.Join("; ", response.ResponseStack.ToArray());
throw new ServiceException($"XdiBatchItemService Failure occured. Payload response was unsuccessful. Error Message: {errorMessage}");
}
Log.Information($"Marking {payload.Count} Payloads Successful."); if (pendingComplete)
var memberIds = payload.Select(x => x.UserId);
var result = await _xdiBatchItemsRepository.MarkPendingSuccessful(memberIds.ToList());
if (result)
{ {
await UpdateMemberPreferenceEntries(payload); await UpdateMemberPreferenceEntries(batchFileExportList);
} }
await _unitOfWork.CompleteAsync(XdiBatchProcessOperatorName, DateTime.UtcNow, UserType.System); await _unitOfWork.CompleteAsync(XdiBatchProcessOperatorName, DateTime.UtcNow, UserType.System);
return result; return pendingComplete;
}
catch (ServiceException serviceEx)
{
Log.Error($"{serviceEx}");
throw serviceEx;
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -228,9 +215,9 @@ namespace LCU.API.Internal.MemberPreferencesApi.Services.XdiServices
} }
} }
private async Task UpdateMemberPreferenceEntries(List<FtpQueuePayloadItem> payload) private async Task UpdateMemberPreferenceEntries(List<XdiBatchFileExport> batchFileExport)
{ {
foreach (var item in payload) foreach (var item in batchFileExport)
{ {
var settings = await _unifiedOptInRepository.GetOrCreateMemberOptinSettings(item.UserId); var settings = await _unifiedOptInRepository.GetOrCreateMemberOptinSettings(item.UserId);
@@ -269,5 +256,45 @@ namespace LCU.API.Internal.MemberPreferencesApi.Services.XdiServices
} }
} }
} }
public async Task<XdiBatchProcessInfo> CreateNewBatchProcessInfo(int batchTotal)
{
var xdiBatchProcessInfo = new XdiBatchProcessInfo();
xdiBatchProcessInfo.StartTimeStamp = DateTime.Now;
xdiBatchProcessInfo.XdiBatchProcessStatus = XdiBatchProcessStatus.InProgress;
xdiBatchProcessInfo.BatchTotal = batchTotal;
return await _xdiBatchProcessInfoRepository.AddAsync(xdiBatchProcessInfo);
}
public async Task<XdiBatchProcessInfo> UpdateBatchAsync(XdiBatchProcessInfo xdiBatchProcessInfo, XdiBatchProcessStatus xdiBatchStatus, string apiResponse)
{
try
{
var existing = await _xdiBatchProcessInfoRepository.FindByIdAsync(xdiBatchProcessInfo.XdiBatchProcessInfoId);
if (existing == null)
{
throw new ServiceException($"XdiBatchProcessInfo with XdiBatchProcessInfoId {xdiBatchProcessInfo.XdiBatchProcessInfoId} not found");
}
existing.XdiBatchProcessStatus = xdiBatchStatus;
existing.ApiResponse = apiResponse;
existing.EndTimeStamp = DateTime.Now;
await _xdiBatchProcessInfoRepository.UpdateAsync(existing);
await _unitOfWork.CompleteAsync();
return existing;
}
catch (SqlException sqlEx)
{
var message = $"Failure updating XdiBatchProcessInfo with XdiBatchProcessInfoId {xdiBatchProcessInfo.XdiBatchProcessInfoId}";
Log.Error(sqlEx, message);
throw new ServiceException(message);
}
catch (Exception ex)
{
var message = $"Failure updating XdiBatchProcessInfo with XdiBatchProcessInfoId {xdiBatchProcessInfo.XdiBatchProcessInfoId}";
Log.Error(ex, message);
throw new ServiceException(message);
}
}
} }
} }
@@ -3,15 +3,9 @@
"AppName": "Member Preferences Api", "AppName": "Member Preferences Api",
"SeqUrl": "http://localhost:5080", "SeqUrl": "http://localhost:5080",
"SeqKey": "9MQu0vLDwQ1LCFzGixZM", "SeqKey": "9MQu0vLDwQ1LCFzGixZM",
"XdiBatchProcessCronSchedule": "1 5-18 * * *",
"DnaDataAuditProcessCronSchedule": "*/5 3-19 * * *",
"FeatureFlags": { "FeatureFlags": {
"RunHostedServices": true,
"RunXdiBatchProcessConsumer": true, "RunXdiBatchProcessConsumer": true,
"RunXdiSshResponseConsumer": true, "RunDnaAuditProcessConsumer": true
"RunAccountDnaFieldChangeConsumer": true,
"RunAgreementDnaFieldChangeConsumer": true,
"RunOrganizationDnaFieldChangeConsumer": true
}, },
"FeatureGates": { "FeatureGates": {
"EnableControllers": true, "EnableControllers": true,
@@ -43,20 +37,12 @@
"TestEmailList": [ "[email protected]" ], "TestEmailList": [ "[email protected]" ],
"ShouldSendRealEmails": false "ShouldSendRealEmails": false
}, },
"FtpApiConfiguration": { "FileOperationsApiConfiguration": {
"Url": "https://localhost:56641/", "Url": "https://localhost:63532/api/",
"QueueSshFtpRequestEndpoint": "SshFtp/QueueSshFtpRequest" "AppendFile": "DirectFileOperations/AppendFile"
},
"XdiSftpApiConfiguration": {
"SftpRootBasePath": "/home/devops/",
"HostName": "10.147.44.23",
"UserName": "devops",
"PortNumber": 22,
"Password": "vault-value",
"Fingerprint": "ssh-ed25519 255 Yj16sxy1rlbKuNxGnYTNqnDUkPjiV8qFiEAjb6h9Xdk="
}, },
"CoreApiWrapperConfiguration": { "CoreApiWrapperConfiguration": {
"CoreApiBaseUrl": "https://localhost:44355/api/core/", "CoreApiBaseUrl": "https://qa-core-api-wrapper-api.apps.azure.lcu-internal.com/api/core/",
"CoreApiGetAgreementByUserId": "Agree/AgreementByUserId/{userId}", "CoreApiGetAgreementByUserId": "Agree/AgreementByUserId/{userId}",
"CoreApiGetAgreementByAgreementId": "Agree/AgreementByAgreementId/{agreementId}", "CoreApiGetAgreementByAgreementId": "Agree/AgreementByAgreementId/{agreementId}",
"CoreApiGetAgreementsByAccountId": "Agree/AgreementsByAccountId/{accountId}", "CoreApiGetAgreementsByAccountId": "Agree/AgreementsByAccountId/{accountId}",
@@ -65,31 +51,20 @@
"CoreApiGetAgreementAccountsByOrganizationId": "Agree/AgreementAccountsByOrganizationId/{organizationId}", "CoreApiGetAgreementAccountsByOrganizationId": "Agree/AgreementAccountsByOrganizationId/{organizationId}",
"CoreApiGetAuditAccountsFromDateLastMaintained": "Agree/AgreementAccountsAuditFromDateLastMaintained", "CoreApiGetAuditAccountsFromDateLastMaintained": "Agree/AgreementAccountsAuditFromDateLastMaintained",
"CoreApiGetAuditAgreementFromDateLastMaintained": "Agree/AgreementAuditFromDateLastMaintained", "CoreApiGetAuditAgreementFromDateLastMaintained": "Agree/AgreementAuditFromDateLastMaintained",
"CoreApiGetAuditOrganizationFromDateLastMaintained": "Agree/OrganizationAuditFromDateLastMaintained",
"CoreApiUpdateAccountsMaintenanceRequest": "Account/AccountMaintenanceRequest" "CoreApiUpdateAccountsMaintenanceRequest": "Account/AccountMaintenanceRequest"
}, },
"ScanBiCoreApiWrapperConfiguration": {
"ScanBiCoreApiWrapperUrl": "https://qa-scanbi-core-api-wrapper-api.apps.azure.lcu-internal.com/api/core/",
"GetAuditOrganizationFromDateLastMaintainedEndpoint": "Agree/OrganizationAuditFromDateLastMaintained"
},
"XdiBatchProcessEndpoint": { "XdiBatchProcessEndpoint": {
"ReceiveEndpoint": "LCU.MemberPreferencesApi.XdiBatchProcess", "ReceiveEndpoint": "LCU.MemberPreferencesApi.XdiBatchProcess",
"ReceiveEndpointType": "exchange", "ReceiveEndpointType": "exchange",
"PrefetchLimit": 1 "PrefetchLimit": 1
}, },
"XdiBatchConfirmEndpoint": {
"ReceiveEndpoint": "LCU.MemberPreferencesApi.XdiBatchConfirm", "DnaAuditProcessEndpoint": {
"ReceiveEndpointType": "exchange", "ReceiveEndpoint": "LCU.MemberPreferencesApi.DnaAuditProcess",
"PrefetchLimit": 1
},
"DnaAccountAuditEndpoint": {
"ReceiveEndpoint": "LCU.MemberPreferencesApi.DnaAccountAudit",
"ReceiveEndpointType": "exchange",
"PrefetchLimit": 1
},
"DnaOrganizationAuditEndpoint": {
"ReceiveEndpoint": "LCU.MemberPreferencesApi.DnaOrganizationAudit",
"ReceiveEndpointType": "exchange",
"PrefetchLimit": 1
},
"DnaAgreementAuditEndpoint": {
"ReceiveEndpoint": "LCU.MemberPreferencesApi.DnaAgreementAudit",
"ReceiveEndpointType": "exchange", "ReceiveEndpointType": "exchange",
"PrefetchLimit": 1 "PrefetchLimit": 1
}, },
@@ -98,15 +73,32 @@
"UserName": "guest", "UserName": "guest",
"Password": "guest" "Password": "guest"
}, },
"DnaAuditProcessConfiguration": {
"LookBackMinutes": -5,
"NumberOfAllowedConsecutiveFailures": 12
},
"ApiSecurityConfiguration": { "ApiSecurityConfiguration": {
"ApiKeyAuthenticationFailureBehavior": "Error", "ApiKeyAuthenticationFailureBehavior": "Error",
"ExternalApiKeySet": {}, "ExternalApiKeySet": {},
"InternalApiKeySet": { "InternalApiKeySet": {
"MembershipPreferences": "85c3f03b-f412-4f8d-bc1e-438a7a69cbbe" "MembershipPreferences": "85c3f03b-f412-4f8d-bc1e-438a7a69cbbe"
} }
},
"ServicesFactoryConfiguration": {
"ServiceFactoryRegistrations": [
{
"ServiceInterfaceName": "IDNAAuditCheckService",
"ServiceRegistrations": [
{
"ServiceName": "DNADataAgreementAuditCheckService",
"ServiceId": "0"
},
{
"ServiceName": "DNADataAccountAuditCheckService",
"ServiceId": "1"
},
{
"ServiceName": "DNADataOrganizationAuditService",
"ServiceId": "2"
}
]
}
]
} }
} }
@@ -6,6 +6,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="LCU.Library.Internal.LcuClassPatterns.Crud" Version="1.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.5" /> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.5"> <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.5">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
@@ -18,6 +18,7 @@ public class ApplicationDbContext : DbContext, IApplicationDbContext
public DbSet<MemberOptInSettings> MemberOptInSettings { get; set; } public DbSet<MemberOptInSettings> MemberOptInSettings { get; set; }
public DbSet<DnaAuditProcess> DnaAuditProcesses { get; set; } public DbSet<DnaAuditProcess> DnaAuditProcesses { get; set; }
public DbSet<XdiBatchItem> XdiBatchItems { get; set; } public DbSet<XdiBatchItem> XdiBatchItems { get; set; }
public DbSet<XdiBatchProcessInfo> XdiBatchProcessInfos { get; set; }
public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken()) public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken())
{ {
@@ -103,5 +104,8 @@ public class ApplicationDbContext : DbContext, IApplicationDbContext
builder.Entity<DnaAuditProcess>().ToTable("DnaAuditProcess"); builder.Entity<DnaAuditProcess>().ToTable("DnaAuditProcess");
builder.Entity<DnaAuditProcess>().HasKey(p => p.ProcessId); builder.Entity<DnaAuditProcess>().HasKey(p => p.ProcessId);
builder.Entity<XdiBatchProcessInfo>().ToTable("XdiBatchProcessInfo");
builder.Entity<XdiBatchProcessInfo>().HasKey(p => p.XdiBatchProcessInfoId);
} }
} }
@@ -11,6 +11,7 @@ public interface IApplicationDbContext : IAuditableChanges
DbSet<MemberOptInSettings> MemberOptInSettings { get; set; } DbSet<MemberOptInSettings> MemberOptInSettings { get; set; }
public DbSet<XdiBatchItem> XdiBatchItems { get; set; } public DbSet<XdiBatchItem> XdiBatchItems { get; set; }
public DbSet<DnaAuditProcess> DnaAuditProcesses { get; set; } public DbSet<DnaAuditProcess> DnaAuditProcesses { get; set; }
public DbSet<XdiBatchProcessInfo> XdiBatchProcessInfos { get; set; }
Task<int> SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken()); Task<int> SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken());
Task<int> SaveChangesWithOperatorAsync(string operatorId, DateTime dateAdded, UserType userType, CancellationToken cancellationToken); Task<int> SaveChangesWithOperatorAsync(string operatorId, DateTime dateAdded, UserType userType, CancellationToken cancellationToken);
} }
@@ -1,5 +1,6 @@
using LCU.API.Internal.MemberPreferencesApiLib.Persistence; using LCU.API.Internal.MemberPreferencesApiLib.Persistence;
using LCU.Library.Internal.MemberPreferencesApiModels.Entities; using LCU.Library.Internal.MemberPreferencesApiModels.Entities;
using LCU.Library.Internal.MemberPreferencesApiModels.Enums;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
namespace LCU.API.Internal.MemberPreferencesApiLib.Repositories; namespace LCU.API.Internal.MemberPreferencesApiLib.Repositories;
@@ -15,6 +16,11 @@ public class DnaAuditProcessRepository : BaseRepository, IDnaAuditProcessReposit
return await _context.DnaAuditProcesses.ToListAsync(); return await _context.DnaAuditProcesses.ToListAsync();
} }
public async Task<DnaAuditProcess> GetDnaAuditProcessByDnaProcessType(DnaAuditProcessType type)
{
return await _context.DnaAuditProcesses.Where(d => d.DnaProcessType == type).FirstOrDefaultAsync();
}
public async Task Update(DnaAuditProcess existing) public async Task Update(DnaAuditProcess existing)
{ {
_context.DnaAuditProcesses.Update(existing); _context.DnaAuditProcesses.Update(existing);
@@ -1,9 +1,11 @@
using LCU.Library.Internal.MemberPreferencesApiModels.Entities; using LCU.Library.Internal.MemberPreferencesApiModels.Entities;
using LCU.Library.Internal.MemberPreferencesApiModels.Enums;
namespace LCU.API.Internal.MemberPreferencesApiLib.Repositories; namespace LCU.API.Internal.MemberPreferencesApiLib.Repositories;
public interface IDnaAuditProcessRepository public interface IDnaAuditProcessRepository
{ {
Task<IReadOnlyCollection<DnaAuditProcess>> GetAllDnaAuditProcesses(); Task<IReadOnlyCollection<DnaAuditProcess>> GetAllDnaAuditProcesses();
Task<DnaAuditProcess> GetDnaAuditProcessByDnaProcessType(DnaAuditProcessType type);
Task Update(DnaAuditProcess existing); Task Update(DnaAuditProcess existing);
} }
@@ -8,6 +8,7 @@ public interface IXdiBatchItemsRepository
Task<IReadOnlyCollection<XdiBatchItem>> GetXdiBatchItems(); Task<IReadOnlyCollection<XdiBatchItem>> GetXdiBatchItems();
Task<IReadOnlyCollection<XdiBatchItem>> GetNewXdiBatchItems(); Task<IReadOnlyCollection<XdiBatchItem>> GetNewXdiBatchItems();
Task<XdiBatchItem> SaveAsync(XdiBatchItem batchItem); Task<XdiBatchItem> SaveAsync(XdiBatchItem batchItem);
Task<List<XdiBatchItem>> SaveRangeAsync(List<XdiBatchItem> batchItemList);
Task<XdiBatchItem> FindExistingItem(string memberId, BatchState batchState); Task<XdiBatchItem> FindExistingItem(string memberId, BatchState batchState);
void Update(XdiBatchItem existing); void Update(XdiBatchItem existing);
void Delete(XdiBatchItem item); void Delete(XdiBatchItem item);
@@ -0,0 +1,10 @@
using LCU.Library.Internal.LcuClassPatterns.Crud.Repositories;
using LCU.Library.Internal.MemberPreferencesApiModels.Entities;
using LCU.Library.Internal.MemberPreferencesApiModels.Enums;
namespace LCU.API.Internal.MemberPreferencesApiLib.Repositories;
public interface IXdiBatchProcessInfoRepository: ICrudRepository<XdiBatchProcessInfo>
{
Task<IEnumerable<XdiBatchProcessInfo>> FindBatchProcessInfoByStatus(XdiBatchProcessStatus xdiProcessStatus);
}
@@ -27,6 +27,12 @@ public class XdiBatchItemsRepository : BaseRepository, IXdiBatchItemsRepository
return batchItem; return batchItem;
} }
public async Task<List<XdiBatchItem>> SaveRangeAsync(List<XdiBatchItem> batchItemList)
{
await _context.XdiBatchItems.AddRangeAsync(batchItemList);
return batchItemList;
}
public async Task<XdiBatchItem> FindExistingItem(string userId, BatchState batchState) public async Task<XdiBatchItem> FindExistingItem(string userId, BatchState batchState)
{ {
return await _context.XdiBatchItems.Where(p => p.UserId == userId && p.BatchState == batchState) return await _context.XdiBatchItems.Where(p => p.UserId == userId && p.BatchState == batchState)
@@ -0,0 +1,21 @@
using LCU.API.Internal.MemberPreferencesApiLib.Persistence;
using LCU.Library.Internal.LcuClassPatterns.Crud.Repositories;
using LCU.Library.Internal.MemberPreferencesApiModels.Entities;
using LCU.Library.Internal.MemberPreferencesApiModels.Enums;
using Microsoft.EntityFrameworkCore;
namespace LCU.API.Internal.MemberPreferencesApiLib.Repositories;
public class XdiBatchProcessInfoRepository : CrudRepository<XdiBatchProcessInfo>, IXdiBatchProcessInfoRepository
{
private readonly IApplicationDbContext _context;
public XdiBatchProcessInfoRepository(ApplicationDbContext context) : base(context)
{
_context = context;
}
public async Task<IEnumerable<XdiBatchProcessInfo>> FindBatchProcessInfoByStatus(XdiBatchProcessStatus xdiProcessStatus)
{
return await _context.XdiBatchProcessInfos.Where(p => p.XdiBatchProcessStatus == xdiProcessStatus).ToListAsync();
}
}
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<Operations Version="1.0" xmlns="http://schemas.microsoft.com/sqlserver/dac/Serialization/2012/02">
<Operation Name="Rename Refactor" Key="5c3556a6-05fd-442f-a0af-06c6e69d6a9d" ChangeDateTime="03/24/2026 00:12:28">
<Property Name="ElementName" Value="[dbo].[XdiBatchProcessInfo].[Id]" />
<Property Name="ElementType" Value="SqlSimpleColumn" />
<Property Name="ParentElementName" Value="[dbo].[XdiBatchProcessInfo]" />
<Property Name="ParentElementType" Value="SqlTable" />
<Property Name="NewName" Value="XdiBatchProcessInfoId" />
</Operation>
</Operations>
@@ -63,5 +63,9 @@
<Build Include="MemberOptInSettings.sql" /> <Build Include="MemberOptInSettings.sql" />
<Build Include="MemberPreference.sql" /> <Build Include="MemberPreference.sql" />
<Build Include="XdiBatchItems.sql" /> <Build Include="XdiBatchItems.sql" />
<Build Include="XdiBatchProcessInfo.sql" />
</ItemGroup>
<ItemGroup>
<RefactorLog Include="LCU.API.Internal.MemberPreferencesApiSql.refactorlog" />
</ItemGroup> </ItemGroup>
</Project> </Project>
@@ -4,4 +4,5 @@ CREATE TABLE [dbo].[XdiBatchItems]
[BatchState] [int] NOT NULL, [BatchState] [int] NOT NULL,
[Created] [datetime2](7) NOT NULL, [Created] [datetime2](7) NOT NULL,
[LastUpdated] [datetime2](7) NOT NULL, [LastUpdated] [datetime2](7) NOT NULL,
CONSTRAINT [UQ_XdiBatchItems_UserId] UNIQUE (UserId)
) )
@@ -0,0 +1,9 @@
CREATE TABLE [dbo].[XdiBatchProcessInfo]
(
[XdiBatchProcessInfoId] [int] NOT NULL PRIMARY KEY IDENTITY,
[StartTimeStamp] DATETIME2 NOT NULL,
[EndTimeStamp] DATETIME2 NULL,
[BatchTotal] INT NOT NULL DEFAULT 0,
[ApiResponse] NVARCHAR(MAX) NULL,
[XdiBatchProcessStatus] INT NOT NULL
)
@@ -1,15 +1,16 @@
using LCU.Library.Internal.MemberPreferencesApiModels.Entities; using LCU.Library.Internal.MemberPreferencesApiModels.Entities;
namespace LCU.Library.Internal.MemberPreferencesApiModels.DataTransfer; namespace LCU.Library.Internal.MemberPreferencesApiModels.DataTransfer
public class MemberOptInInformation
{ {
public MemberOptInInformation(MemberOptInSettings settings, bool hasPendingUpdates) public class MemberOptInInformation
{ {
MemberOptinSettings = settings; public MemberOptInInformation(MemberOptInSettings settings, bool hasPendingUpdates)
HasPendingUpdates = hasPendingUpdates; {
} MemberOptinSettings = settings;
HasPendingUpdates = hasPendingUpdates;
}
public MemberOptInSettings MemberOptinSettings { get; set; } public MemberOptInSettings MemberOptinSettings { get; set; }
public bool HasPendingUpdates { get; set; } public bool HasPendingUpdates { get; set; }
}
} }
@@ -1,9 +1,10 @@
using LCU.Library.Internal.MemberPreferencesApiModels.Enums; using LCU.Library.Internal.MemberPreferencesApiModels.Enums;
namespace LCU.Library.Internal.MemberPreferencesApiModels.Entities; namespace LCU.Library.Internal.MemberPreferencesApiModels.Entities
public class ApplicationUser
{ {
public string UserName { get; set; } public class ApplicationUser
public UserType UserType { get; set; } {
public string UserName { get; set; }
public UserType UserType { get; set; }
}
} }
@@ -1,26 +1,27 @@
namespace LCU.Library.Internal.MemberPreferencesApiModels.Entities; namespace LCU.Library.Internal.MemberPreferencesApiModels.Entities
public static class DeliveryPreference
{ {
public const string Paper = "Paper"; public static class DeliveryPreference
public const string Electronic = "Electronic";
public const string Hold = "Hold";
public const string Microfiche = "Microfiche";
public static string MapMailCodeToPreference(string mailCode)
{ {
if (string.IsNullOrWhiteSpace(mailCode)) return ""; public const string Paper = "Paper";
public const string Electronic = "Electronic";
public const string Hold = "Hold";
public const string Microfiche = "Microfiche";
switch (mailCode) public static string MapMailCodeToPreference(string mailCode)
{ {
case "3": if (string.IsNullOrWhiteSpace(mailCode)) return "";
return DeliveryPreference.Hold;
case "4": switch (mailCode)
return DeliveryPreference.Microfiche; {
case "5": case "3":
return DeliveryPreference.Electronic; return DeliveryPreference.Hold;
default: case "4":
return DeliveryPreference.Paper; return DeliveryPreference.Microfiche;
case "5":
return DeliveryPreference.Electronic;
default:
return DeliveryPreference.Paper;
}
} }
} }
} }
@@ -2,13 +2,14 @@ using System;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using LCU.Library.Internal.MemberPreferencesApiModels.Enums; using LCU.Library.Internal.MemberPreferencesApiModels.Enums;
namespace LCU.Library.Internal.MemberPreferencesApiModels.Entities; namespace LCU.Library.Internal.MemberPreferencesApiModels.Entities
public class DnaAuditProcess
{ {
public int ProcessId { get; set; } public class DnaAuditProcess
[JsonConverter(typeof(JsonStringEnumConverter))] {
public DnaAuditProcessType DnaProcessType { get; set; } public int ProcessId { get; set; }
public DateTime LastUpdated { get; set; } [JsonConverter(typeof(JsonStringEnumConverter))]
public int ConsecutiveFailures { get; set; } public DnaAuditProcessType DnaProcessType { get; set; }
public DateTime LastUpdated { get; set; }
public int ConsecutiveFailures { get; set; }
}
} }
@@ -1,8 +1,9 @@
using System.Threading.Tasks; using System.Threading.Tasks;
namespace LCU.Library.Internal.MemberPreferencesApiModels.Entities; namespace LCU.Library.Internal.MemberPreferencesApiModels.Entities
public interface IMemberPreferences
{ {
Task Add(MemberPreference preferenceChange); public interface IMemberPreferences
{
Task Add(MemberPreference preferenceChange);
}
} }
@@ -2,18 +2,19 @@ using LCU.Library.Internal.MemberPreferencesApiModels.Enums;
using LCU.Library.Internal.MemberPreferencesApiModels.Models; using LCU.Library.Internal.MemberPreferencesApiModels.Models;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
namespace LCU.Library.Internal.MemberPreferencesApiModels.Entities; namespace LCU.Library.Internal.MemberPreferencesApiModels.Entities
public class MemberPreference : Auditable
{ {
public MemberPreference() public class MemberPreference : Auditable
{ {
} public MemberPreference()
{
}
public int Id { get; set; } public int Id { get; set; }
public string UserId { get; set; } public string UserId { get; set; }
[JsonConverter(typeof(JsonStringEnumConverter))] [JsonConverter(typeof(JsonStringEnumConverter))]
public PreferenceType Preference { get; set; } public PreferenceType Preference { get; set; }
public string Value { get; set; } public string Value { get; set; }
public string LegalReference { get; set; } public string LegalReference { get; set; }
}
} }
@@ -2,13 +2,14 @@ using System;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using LCU.Library.Internal.MemberPreferencesApiModels.Enums; using LCU.Library.Internal.MemberPreferencesApiModels.Enums;
namespace LCU.Library.Internal.MemberPreferencesApiModels.Entities; namespace LCU.Library.Internal.MemberPreferencesApiModels.Entities
public class XdiBatchItem
{ {
public string UserId { get; set; } public class XdiBatchItem
[JsonConverter(typeof(JsonStringEnumConverter))] {
public BatchState BatchState { get; set; } public string UserId { get; set; }
public DateTime Created { get; set; } [JsonConverter(typeof(JsonStringEnumConverter))]
public DateTime LastUpdated { get; set; } public BatchState BatchState { get; set; }
public DateTime Created { get; set; }
public DateTime LastUpdated { get; set; }
}
} }

Some files were not shown because too many files have changed in this diff Show More