This commit is contained in:
Zeeshaun
2026-04-07 14:21:04 -05:00
parent e37826fe30
commit 75ea216a17
264 changed files with 15920 additions and 0 deletions
+80
View File
@@ -0,0 +1,80 @@
[*.cs]
# CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
dotnet_diagnostic.CS8632.severity = silent
csharp_indent_labels = one_less_than_current
csharp_using_directive_placement = outside_namespace:silent
csharp_prefer_simple_using_statement = true:suggestion
csharp_prefer_braces = true:silent
csharp_style_namespace_declarations = block_scoped:silent
csharp_style_prefer_method_group_conversion = true:silent
csharp_style_prefer_top_level_statements = true:silent
csharp_style_expression_bodied_methods = false:silent
csharp_style_expression_bodied_constructors = false:silent
csharp_style_expression_bodied_operators = false:silent
csharp_style_expression_bodied_properties = true:silent
csharp_style_expression_bodied_indexers = true:silent
csharp_style_expression_bodied_accessors = true:silent
csharp_space_around_binary_operators = before_and_after
csharp_style_expression_bodied_lambdas = true:silent
csharp_style_expression_bodied_local_functions = false:silent
[*.{cs,vb}]
dotnet_style_operator_placement_when_wrapping = beginning_of_line
tab_width = 4
indent_size = 4
end_of_line = crlf
[*.{cs,vb}]
#### Naming styles ####
# Naming rules
dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
# Symbol specifications
dotnet_naming_symbols.interface.applicable_kinds = interface
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.interface.required_modifiers =
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.types.required_modifiers =
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.non_field_members.required_modifiers =
# Naming styles
dotnet_naming_style.begins_with_i.required_prefix = I
dotnet_naming_style.begins_with_i.required_suffix =
dotnet_naming_style.begins_with_i.word_separator =
dotnet_naming_style.begins_with_i.capitalization = pascal_case
dotnet_naming_style.pascal_case.required_prefix =
dotnet_naming_style.pascal_case.required_suffix =
dotnet_naming_style.pascal_case.word_separator =
dotnet_naming_style.pascal_case.capitalization = pascal_case
dotnet_naming_style.pascal_case.required_prefix =
dotnet_naming_style.pascal_case.required_suffix =
dotnet_naming_style.pascal_case.word_separator =
dotnet_naming_style.pascal_case.capitalization = pascal_case
dotnet_style_coalesce_expression = true:suggestion
dotnet_style_null_propagation = true:suggestion
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
dotnet_style_prefer_auto_properties = true:silent
dotnet_style_object_initializer = true:suggestion
dotnet_style_collection_initializer = true:suggestion
dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
+363
View File
@@ -0,0 +1,363 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
.idea/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd
+41
View File
@@ -0,0 +1,41 @@
# .NET Core SDK
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS aspnetcore-build
# Copy Projects
COPY LCU.API.Internal.LoanRate/LCU.API.Internal.LoanRate.csproj ./source/LCU.API.Internal.LoanRate/
COPY LCU.API.Internal.LoanRateLib/LCU.API.Internal.LoanRateLib.csproj ./source/LCU.API.Internal.LoanRateLib/
COPY LCU.Library.Internal.LoanRateModels/LCU.Library.Internal.LoanRateModels.csproj ./source/LCU.Library.Internal.LoanRateModels/
# Install Credential Provider and set env variables to enable Nuget restore with auth
ARG PAT=bh2lq3jibktw67b2wdbqyfln7cd3je6lk52kijntpj43v6kimpgq
RUN curl -L https://raw.githubusercontent.com/Microsoft/artifacts-credprovider/master/helpers/installcredprovider.sh | sh
#RUN wget -qO- https://raw.githubusercontent.com/Microsoft/artifacts-credprovider/master/helpers/installcredprovider.sh | bash
ENV NUGET_CREDENTIALPROVIDER_SESSIONTOKENCACHE_ENABLED true
ENV VSS_NUGET_EXTERNAL_FEED_ENDPOINTS "{\"endpointCredentials\": [{\"endpoint\":\"https://landmarkcu.pkgs.visualstudio.com/_packaging/LCU-Internal/nuget/v3/index.json\", \"password\":\"${PAT}\"}]}"
# .NET Core Restore, use auth'd feed
RUN dotnet restore -s "https://landmarkcu.pkgs.visualstudio.com/_packaging/LCU-Internal/nuget/v3/index.json" -s "https://api.nuget.org/v3/index.json" ./source/LCU.API.Internal.LoanRate/LCU.API.Internal.LoanRate.csproj
# Copy All Files
COPY . ./source/
FROM aspnetcore-build AS test
LABEL test=true
COPY LCU.API.Internal.LoanRateTests/LCU.API.Internal.LoanRateTests.csproj ./source/LCU.API.Internal.LoanRateTests/
RUN dotnet restore ./source/LCU.API.Internal.LoanRateTests/LCU.API.Internal.LoanRateTests.csproj
RUN dotnet test -c Release --results-directory /testresults --logger "trx;LogFileName=test_results.trx" ./source/LCU.API.Internal.LoanRateTests/LCU.API.Internal.LoanRateTests.csproj
# .NET Core Publish
FROM aspnetcore-build as publish
RUN dotnet publish ./source/LCU.API.Internal.LoanRate/LCU.API.Internal.LoanRate.csproj -c Release -o /dist
# ASP.NET Core
FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine3.20
RUN apk add --no-cache icu-libs && apk add --no-cache tzdata;
ENV TZ America/Chicago
ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false
ENV ASPNETCORE_ENVIRONMENT=Development
WORKDIR /app
COPY --from=publish /dist .
ENTRYPOINT ["dotnet", "LCU.API.Internal.LoanRate.dll"]
@@ -0,0 +1,65 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.4.33205.214
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LCU.API.Internal.LoanRate", "LCU.API.Internal.LoanRate\LCU.API.Internal.LoanRate.csproj", "{CFB340C3-F73D-4552-801D-6B8CFA1FD70A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LCU.API.Internal.LoanRateTests", "LCU.API.Internal.LoanRateTests\LCU.API.Internal.LoanRateTests.csproj", "{08ED9646-3A26-4ECF-AC34-39AABF46F78A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LCU.Library.Internal.LoanRateModels", "LCU.Library.Internal.LoanRateModels\LCU.Library.Internal.LoanRateModels.csproj", "{1BAA207B-92F5-4DAB-B3B8-A7887451720D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LCU.API.Internal.LoanRateLib", "LCU.API.Internal.LoanRateLib\LCU.API.Internal.LoanRateLib.csproj", "{6FE9201A-EAE6-49FA-8F4A-D0B10022F985}"
EndProject
Project("{00D1A9C2-B5F0-4AF3-8072-F6C62B433612}") = "LCU.API.Internal.LoanRateSql", "LCU.API.Internal.LoanRateSql\LCU.API.Internal.LoanRateSql.sqlproj", "{33CBC5AD-1B92-4D5F-A79F-4464C79C5F0C}"
EndProject
Project("{00D1A9C2-B5F0-4AF3-8072-F6C62B433612}") = "LCU.API.Internal.LoanRateLoadTestingSql", "LCU.API.Internal.LoanRateLoadTestingSql\LCU.API.Internal.LoanRateLoadTestingSql.sqlproj", "{0687C40B-33B7-48FD-9611-C3AF96987CBE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LCU.API.Internal.LoanRateLoadTestingLib", "LCU.API.Internal.LoanRateLoadTestingLib\LCU.API.Internal.LoanRateLoadTestingLib.csproj", "{F9374890-27F2-4155-9781-674929ECE779}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{CFB340C3-F73D-4552-801D-6B8CFA1FD70A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CFB340C3-F73D-4552-801D-6B8CFA1FD70A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CFB340C3-F73D-4552-801D-6B8CFA1FD70A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CFB340C3-F73D-4552-801D-6B8CFA1FD70A}.Release|Any CPU.Build.0 = Release|Any CPU
{08ED9646-3A26-4ECF-AC34-39AABF46F78A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{08ED9646-3A26-4ECF-AC34-39AABF46F78A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{08ED9646-3A26-4ECF-AC34-39AABF46F78A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{08ED9646-3A26-4ECF-AC34-39AABF46F78A}.Release|Any CPU.Build.0 = Release|Any CPU
{1BAA207B-92F5-4DAB-B3B8-A7887451720D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1BAA207B-92F5-4DAB-B3B8-A7887451720D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1BAA207B-92F5-4DAB-B3B8-A7887451720D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1BAA207B-92F5-4DAB-B3B8-A7887451720D}.Release|Any CPU.Build.0 = Release|Any CPU
{6FE9201A-EAE6-49FA-8F4A-D0B10022F985}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6FE9201A-EAE6-49FA-8F4A-D0B10022F985}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6FE9201A-EAE6-49FA-8F4A-D0B10022F985}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6FE9201A-EAE6-49FA-8F4A-D0B10022F985}.Release|Any CPU.Build.0 = Release|Any CPU
{33CBC5AD-1B92-4D5F-A79F-4464C79C5F0C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{33CBC5AD-1B92-4D5F-A79F-4464C79C5F0C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{33CBC5AD-1B92-4D5F-A79F-4464C79C5F0C}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{33CBC5AD-1B92-4D5F-A79F-4464C79C5F0C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{33CBC5AD-1B92-4D5F-A79F-4464C79C5F0C}.Release|Any CPU.Build.0 = Release|Any CPU
{33CBC5AD-1B92-4D5F-A79F-4464C79C5F0C}.Release|Any CPU.Deploy.0 = Release|Any CPU
{0687C40B-33B7-48FD-9611-C3AF96987CBE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0687C40B-33B7-48FD-9611-C3AF96987CBE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0687C40B-33B7-48FD-9611-C3AF96987CBE}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{0687C40B-33B7-48FD-9611-C3AF96987CBE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0687C40B-33B7-48FD-9611-C3AF96987CBE}.Release|Any CPU.Build.0 = Release|Any CPU
{0687C40B-33B7-48FD-9611-C3AF96987CBE}.Release|Any CPU.Deploy.0 = Release|Any CPU
{F9374890-27F2-4155-9781-674929ECE779}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F9374890-27F2-4155-9781-674929ECE779}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F9374890-27F2-4155-9781-674929ECE779}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F9374890-27F2-4155-9781-674929ECE779}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {5F5E7D18-CECB-4D1B-87A7-071F1037BDD6}
EndGlobalSection
EndGlobal
@@ -0,0 +1,10 @@
namespace LCU.API.Internal.LoanRate.Configurations;
public class ApiConfiguration
{
public string AppName { get; set; }
public string SeqUrl { get; set; }
public string SeqApiKey { get; set; }
public string[] CorsAllowedOrigins { get; set; }
public FeatureFlags FeatureFlags { get; set; }
}
@@ -0,0 +1,8 @@
namespace LCU.API.Internal.LoanRate.Configurations;
public class FeatureFlags
{
public bool RunLoadTestInitiateConsumer { get; set; }
public bool RunLoadTestProcessRateConsumer { get; set; }
public bool RunLoadTestRateCompletionConsumer { get; set; }
}
@@ -0,0 +1,11 @@
using System.ComponentModel.DataAnnotations.Schema;
namespace LCU.API.Internal.LoanRate.Configurations;
public class FileOperationsApiConfiguration
{
public string Url { get; set; }
public string ExtractExcelWorkBookDataEndpoint { get; set; }
[NotMapped]
public Uri ExtractExcelWorkBookDataEndpointUri => new Uri(Url + ExtractExcelWorkBookDataEndpoint);
}
@@ -0,0 +1,8 @@
namespace LCU.API.Internal.LoanRate.Configurations;
public class LoanRateLoadTestingSqlConnectionConfiguration
{
public string ConnectionString { get; set; }
public int MaxRetryCount { get; set; }
public TimeSpan MaxRetryDelay { get; set; }
}
@@ -0,0 +1,8 @@
namespace LCU.API.Internal.LoanRate.Configurations;
public class LoanRateSqlConnectionConfiguration
{
public string ConnectionString { get; set; }
public int MaxRetryCount { get; set; }
public TimeSpan MaxRetryDelay { get; set; }
}
@@ -0,0 +1,9 @@
using LCU.Library.Internal.LcuMassTransitModels;
namespace LCU.API.Internal.LoanRate.Configurations;
public class ReceiveEndpointConfigurations
{
public ReceiveEndpointConfiguration LoadTestInitiateReceiveEndpoint { get; set; }
public ReceiveEndpointConfiguration LoadTestProcessRateReceiveEndpoint { get; set; }
public ReceiveEndpointConfiguration LoadTestRateCompletionReceiveEndpoint { get; set; }
}
@@ -0,0 +1,42 @@
using MassTransit;
using LCU.Library.Internal.LoanRateModels.Requests.LoadTestRequest;
using LCU.Api.Internal.MaidBotLib.Models;
using LCU.API.Internal.LoanRate.Services.LoadTestingServices;
namespace LCU.API.Internal.LoanRate.Consumers;
public class LoadTestInitiateConsumer : IConsumer<LoadTestInitiateRequest>
{
private readonly IServiceScopeFactory _scopeFactory;
public LoadTestInitiateConsumer(IServiceScopeFactory scopeFactory)
{
_scopeFactory = scopeFactory;
}
public async Task Consume(ConsumeContext<LoadTestInitiateRequest> context)
{
try
{
Log.Debug("Starting HandleLoadTestInitiation.");
using var scope = _scopeFactory.CreateScope();
await Task.Run(async () => await scope.ServiceProvider.GetRequiredService<ILoadTestInitiationService>().HandleLoadTestInitiation(context.Message));
Log.Debug("Starting HandleLoadTestInitiation.");
}
catch (ServiceException serviceException)
{
Log.ForContext(Enum.GetName(typeof(PropertyEnum), PropertyEnum.Group),
Enum.GetName(typeof(GroupEnum), GroupEnum.ITDevelopment))
.Error(serviceException, $"Load Test Initiation Failure. " +
$"The LoadTestInitiateRequest is placed on LCU.LoanRate.LoadTest.Initiate_error.");
throw;
}
catch (Exception exception)
{
Log.ForContext(Enum.GetName(typeof(PropertyEnum), PropertyEnum.Group),
Enum.GetName(typeof(GroupEnum), GroupEnum.ITDevelopment))
.Fatal(exception, $"Unexpected Load Test Initiation Failure. " +
$"The LoadTestInitiateRequest is placed on LCU.LoanRate.LoadTest.Initiate_error.");
throw;
}
}
}
@@ -0,0 +1,42 @@
using MassTransit;
using LCU.Library.Internal.LoanRateModels.Requests.LoadTestRequest;
using LCU.API.Internal.LoanRate.Services.LoadTestingServices;
using LCU.Api.Internal.MaidBotLib.Models;
namespace LCU.API.Internal.LoanRate.Consumers;
public class LoadTestProcessRateConsumer : IConsumer<LoadTestProcessRateRequest>
{
private readonly IServiceScopeFactory _scopeFactory;
public LoadTestProcessRateConsumer(IServiceScopeFactory scopeFactory)
{
_scopeFactory = scopeFactory;
}
public async Task Consume(ConsumeContext<LoadTestProcessRateRequest> context)
{
try
{
Log.Debug("Starting HandleLoadTestProcessRate.");
using var scope = _scopeFactory.CreateScope();
await Task.Run(async () => await scope.ServiceProvider.GetRequiredService<ILoadTestProcessRateService>().HandleLoadTestProcessRate(context.Message));
Log.Debug("Starting HandleLoadTestProcessRate.");
}
catch (ServiceException serviceException)
{
Log.ForContext(Enum.GetName(typeof(PropertyEnum), PropertyEnum.Group),
Enum.GetName(typeof(GroupEnum), GroupEnum.ITDevelopment))
.Error(serviceException, $"Load Test Process Rate Failure. " +
$"The LoadTestProcessRateRequest is placed on LCU.LoanRate.LoadTest.ProcessRate_error.");
throw;
}
catch (Exception exception)
{
Log.ForContext(Enum.GetName(typeof(PropertyEnum), PropertyEnum.Group),
Enum.GetName(typeof(GroupEnum), GroupEnum.ITDevelopment))
.Fatal(exception, $"Unexpected Load Test Process Rate Failure. " +
$"The LoadTestProcessRateRequest is placed on LCU.LoanRate.LoadTest.ProcessRate_error.");
throw;
}
}
}
@@ -0,0 +1,50 @@
using MassTransit;
using LCU.Library.Internal.LoanRateModels.Requests.LoadTestRequest;
using LCU.Api.Internal.MaidBotLib.Models;
using LCU.API.Internal.LoanRate.Services.LoadTestingServices;
namespace LCU.API.Internal.LoanRate.Consumers;
public class LoadTestRateCompletionConsumer : IConsumer<Batch<LoadTestRateCompletionRequest>>
{
private readonly IServiceScopeFactory _scopeFactory;
public LoadTestRateCompletionConsumer(IServiceScopeFactory scopeFactory)
{
_scopeFactory = scopeFactory;
}
public async Task Consume(ConsumeContext<Batch<LoadTestRateCompletionRequest>> context)
{
try
{
Log.Debug("Starting HandleLoadTestRateCompletion.");
using var scope = _scopeFactory.CreateScope();
var loadTestRateCompletionRequests = new List<LoadTestRateCompletionRequest>();
for (int index = 0; index < context.Message.Length; index++)
{
ConsumeContext<LoadTestRateCompletionRequest> messageContext = context.Message[index];
loadTestRateCompletionRequests.Add(messageContext.Message);
}
await Task.Run(async () => await scope.ServiceProvider.GetRequiredService<ILoadTestRateCompletionService>().HandleLoadTestRateCompletion(loadTestRateCompletionRequests));
Log.Debug("Starting HandleLoadTestRateCompletion.");
}
catch (ServiceException serviceException)
{
Log.ForContext(Enum.GetName(typeof(PropertyEnum), PropertyEnum.Group),
Enum.GetName(typeof(GroupEnum), GroupEnum.ITDevelopment))
.Error(serviceException, $"Load Test Rate Completion Failure. " +
$"The LoadTestRateCompletionRequest is placed on LCU.LoanRate.LoadTest.RateCompletion_error.");
throw;
}
catch (Exception exception)
{
Log.ForContext(Enum.GetName(typeof(PropertyEnum), PropertyEnum.Group),
Enum.GetName(typeof(GroupEnum), GroupEnum.ITDevelopment))
.Fatal(exception, $"Unexpected Load Test Rate Completion Failure. " +
$"The LoadTestRateCompletionRequest is placed on LCU.LoanRate.LoadTest.RateCompletion_error.");
throw;
}
}
}
@@ -0,0 +1,126 @@
using LCU.API.Internal.LoanRate.Services;
using LCU.Library.Internal.LcuEvaluationModels.Entities;
using LCU.Library.Internal.LcuEvaluationModels.Requests;
using Microsoft.AspNetCore.Mvc;
namespace LCU.API.Internal.LoanRate.Controllers;
[ApiController]
[Route("api/[controller]")]
public class ComplexEvaluationDetailController : ControllerBase
{
private readonly IComplexEvaluationDetailService _complexEvaluationDetailService;
public ComplexEvaluationDetailController(IComplexEvaluationDetailService complexEvaluationDetailService)
{
_complexEvaluationDetailService = complexEvaluationDetailService;
}
[HttpPost("")]
[ProducesResponseType(201)]
[ProducesResponseType(typeof(EvaluationDetail), 400)]
[ProducesResponseType(500)]
public async Task<IActionResult> LoanRatePostComplex([FromBody] EvaluationDetailRequest request)
{
try
{
if (request is null)
{
return BadRequest("Request cannot be null.");
}
var result = await _complexEvaluationDetailService.SaveComplexAsync(request);
return CreatedAtAction("GetById", new { controller = "EvaluationDetail", id = result.EvaluationDetailId }, result);
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
/// <summary>
/// Updates the EvaluationDetail, as well as the Create/Edit/Delete of the EvaluationParameter child collection.
/// </summary>
/// <param name="evaluationDetail"></param>
/// <returns></returns>
[HttpPut("")]
[ProducesResponseType(200)]
[ProducesResponseType(400)]
[ProducesResponseType(404)]
[ProducesResponseType(500)]
public async Task<IActionResult> LoanRatePutComplex([FromBody] EvaluationDetail evaluationDetail)
{
try
{
if (evaluationDetail is null)
{
return BadRequest("EvaluationDetail cannot be null.");
}
if (evaluationDetail.EvaluationDetailId == 0)
{
return BadRequest("EvaluationDetailId cannot be empty.");
}
if (!evaluationDetail.EvaluationParameters.Any())
{
return BadRequest("EvaluationParameters cannot be empty.");
}
var result = await _complexEvaluationDetailService.UpdateComplexAsync(evaluationDetail);
if (result is null)
{
return StatusCode(StatusCodes.Status406NotAcceptable);
}
return Ok(result);
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
/// <summary>
/// Deletes the EvaluationDetail, as well as removes the end date of the previous version.
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpDelete("{id:int}")]
[ProducesResponseType(200)]
[ProducesResponseType(400)]
[ProducesResponseType(500)]
public async Task<IActionResult> LoanRateDeleteComplex(int id)
{
try
{
if (id <= 0)
{
return BadRequest($"EvaluationDetailId {id} is invalid.");
}
await _complexEvaluationDetailService.DeleteComplexAsync(id);
return Ok();
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
}
@@ -0,0 +1,37 @@
using Microsoft.AspNetCore.Mvc;
using LCU.Library.Internal.LoanRateModels.Requests.LoadTestRequest;
using LCU.API.Internal.LoanRate.Services.QueueServices;
namespace LCU.API.Internal.LoanRate.Controllers;
[ApiController]
[Route("api/[controller]")]
public class LoadTestInitiateController : ControllerBase
{
private readonly IQueueLoadTestInitiateService _queueLoadTestInitiateService;
public LoadTestInitiateController(IQueueLoadTestInitiateService queueLoadTestInitiateService)
{
_queueLoadTestInitiateService = queueLoadTestInitiateService;
}
[HttpPost("QueueLoadTestInitiateRequest")]
[ProducesResponseType(200)]
[ProducesResponseType(500)]
public async Task<IActionResult> QueueLoadTestInitiateRequest([FromBody] LoadTestInitiateRequest request)
{
try
{
await _queueLoadTestInitiateService.QueueLoadTestInitiateRequest(request);
return Accepted();
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
}
@@ -0,0 +1,312 @@
using Microsoft.AspNetCore.Mvc;
using LCU.API.Internal.LoanRate.Services;
using LCU.Library.Internal.LCUFilterModels.Pagination;
using LCU.Library.Internal.LoanRateModels.Entities.LoadTestingEntities;
namespace LCU.API.Internal.LoanRate.Controllers;
[ApiController]
[Route("api/[controller]")]
public class LoadTestRunInfoController : ControllerBase
{
private readonly ILoadTestRunInfoService _loadTestRunInfoService;
public LoadTestRunInfoController(ILoadTestRunInfoService loadTestRunInfoService)
{
_loadTestRunInfoService = loadTestRunInfoService;
}
[HttpGet]
[ProducesResponseType(200)]
[ProducesResponseType(204)]
[ProducesResponseType(500)]
public async Task<IActionResult> Get()
{
try
{
var result = await _loadTestRunInfoService.GetAsync();
if (result is null || !result.Any())
{
return NoContent();
}
return Ok(result);
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpGet("{id:int}")]
[ProducesResponseType(200)]
[ProducesResponseType(204)]
[ProducesResponseType(typeof(LoadTestRunInfo), 400)]
[ProducesResponseType(500)]
public async Task<IActionResult> GetById(int id)
{
try
{
if (id <= 0)
{
return BadRequest($"Id {id} is invalid.");
}
var result = await _loadTestRunInfoService.GetByIdAsync(id);
if (result is null)
{
return NoContent();
}
return Ok(result);
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpPost("GetListById")]
[ProducesResponseType(200)]
[ProducesResponseType(204)]
[ProducesResponseType(typeof(IEnumerable<LoadTestRunInfo>), 400)]
[ProducesResponseType(500)]
public async Task<IActionResult> GetListById([FromBody] List<int> ids)
{
try
{
if (ids is null || !ids.Any())
{
return BadRequest("List of ids are invalid.");
}
var result = await _loadTestRunInfoService.GetRangeByIdAsync(ids);
if (result == null)
{
return NoContent();
}
return Ok(result);
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpPost("GetFilteredLoadTestRunInfo")]
[ProducesResponseType(typeof(PagedResponse<LoadTestRunInfo>), 200)]
[ProducesResponseType(500)]
public async Task<IActionResult> GetFilteredLoadTestRunInfo([FromBody] LoadTestRunInfoFilter loadTestRunInfoFilter)
{
try
{
var filterResult = await _loadTestRunInfoService.GetFilteredLoadTestRunInfo(loadTestRunInfoFilter);
var result = new PagedResponse<LoadTestRunInfo>(filterResult, loadTestRunInfoFilter);
return Ok(result);
}
catch (ServiceException)
{
return StatusCode(StatusCodes.Status500InternalServerError);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpPost]
[ProducesResponseType(201)]
[ProducesResponseType(typeof(LoadTestRunInfo), 400)]
[ProducesResponseType(500)]
public async Task<IActionResult> Post([FromBody] LoadTestRunInfo loadTestRunInfo)
{
try
{
if (loadTestRunInfo is null)
{
return BadRequest("LoadTestRunInfo cannot be null.");
}
var result = await _loadTestRunInfoService.SaveAsync(loadTestRunInfo);
return CreatedAtAction(nameof(GetById), new { id = result.LoadTestRunInfoId }, result);
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpPost("SaveRange")]
[ProducesResponseType(200)]
[ProducesResponseType(typeof(IEnumerable<LoadTestRunInfo>), 400)]
[ProducesResponseType(500)]
public async Task<IActionResult> SaveRange([FromBody] List<LoadTestRunInfo> loadTestRunInfos)
{
try
{
if (loadTestRunInfos is null || !loadTestRunInfos.Any())
{
return BadRequest("LoadTestRunInfos cannot be null or empty.");
}
await _loadTestRunInfoService.SaveRangeAsync(loadTestRunInfos);
return Ok();
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpPut]
[ProducesResponseType(200)]
[ProducesResponseType(400)]
[ProducesResponseType(404)]
[ProducesResponseType(500)]
public async Task<IActionResult> Put([FromBody] LoadTestRunInfo loadTestRunInfo)
{
try
{
if (loadTestRunInfo is null)
{
return BadRequest("LoadTestRunInfo cannot be null.");
}
if (loadTestRunInfo.LoadTestRunInfoId == 0)
{
return BadRequest("LoadTestRunInfoId cannot be empty.");
}
var result = await _loadTestRunInfoService.UpdateAsync(loadTestRunInfo);
if (result is null)
{
return StatusCode(StatusCodes.Status406NotAcceptable);
}
return Ok(result);
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpPut("UpdateRange")]
[ProducesResponseType(200)]
[ProducesResponseType(400)]
[ProducesResponseType(404)]
[ProducesResponseType(500)]
public async Task<IActionResult> UpdateRange([FromBody] List<LoadTestRunInfo> loadTestRunInfos)
{
try
{
if (loadTestRunInfos is null || !loadTestRunInfos.Any())
{
return BadRequest("LoadTestRunInfos cannot be null or empty.");
}
if (loadTestRunInfos.Any(loadTestRunInfo => loadTestRunInfo.LoadTestRunInfoId == 0))
{
return BadRequest("LoadTestRunInfoIds cannot be empty.");
}
var result = await _loadTestRunInfoService.UpdateRangeAsync(loadTestRunInfos);
return Ok(result);
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpDelete("{id:int}")]
[ProducesResponseType(200)]
[ProducesResponseType(400)]
[ProducesResponseType(500)]
public async Task<IActionResult> Delete(int id)
{
try
{
if (id <= 0)
{
return BadRequest($"LoadTestRunInfoId {id} is invalid.");
}
await _loadTestRunInfoService.DeleteAsync(id);
return Ok();
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpDelete("DeleteRange")]
[ProducesResponseType(200)]
[ProducesResponseType(400)]
[ProducesResponseType(500)]
public async Task<IActionResult> DeleteRange([FromBody] List<int> ids)
{
try
{
if (ids is null || !ids.Any())
{
return BadRequest("List of ids are invalid.");
}
await _loadTestRunInfoService.DeleteRangeAsync(ids);
return Ok();
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
}
@@ -0,0 +1,341 @@
using Microsoft.AspNetCore.Mvc;
using LCU.API.Internal.LoanRate.Services;
namespace LCU.API.Internal.LoanRate.Controllers;
[ApiController]
[Route("api/[controller]")]
public class RateController : ControllerBase
{
private readonly IRateService _rateService;
public RateController(IRateService rateService)
{
_rateService = rateService;
}
[HttpGet]
[ProducesResponseType(200)]
[ProducesResponseType(204)]
[ProducesResponseType(500)]
public async Task<IActionResult> Get()
{
try
{
var result = await _rateService.GetAsync();
if (result is null || !result.Any())
{
return NoContent();
}
return Ok(result);
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpGet("{id:int}")]
[ProducesResponseType(200)]
[ProducesResponseType(204)]
[ProducesResponseType(typeof(Rate), 400)]
[ProducesResponseType(500)]
public async Task<IActionResult> GetById(int id)
{
try
{
if (id <= 0)
{
return BadRequest($"Id {id} is invalid.");
}
var result = await _rateService.GetByIdAsync(id);
if (result is null)
{
return NoContent();
}
return Ok(result);
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpPost("GetListById")]
[ProducesResponseType(200)]
[ProducesResponseType(204)]
[ProducesResponseType(typeof(IEnumerable<Rate>), 400)]
[ProducesResponseType(500)]
public async Task<IActionResult> GetListById([FromBody] List<int> ids)
{
try
{
if (ids is null || !ids.Any())
{
return BadRequest("List of ids are invalid.");
}
var result = await _rateService.GetRangeByIdAsync(ids);
if (result == null)
{
return NoContent();
}
return Ok(result);
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpGet("GetByLoadTestRunInfo/{loadTestRunInfoId:int}")]
[ProducesResponseType(200)]
[ProducesResponseType(204)]
[ProducesResponseType(typeof(IEnumerable<Rate>), 400)]
[ProducesResponseType(500)]
public async Task<IActionResult> GetByLoadTestRunInfo([FromRoute] int loadTestRunInfoId)
{
try
{
if (loadTestRunInfoId == 0)
{
return BadRequest("Id is required");
}
var result = await _rateService.GetByLoadTestRunInfoId(loadTestRunInfoId);
if (result == null)
{
return NoContent();
}
return Ok(result);
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpPost]
[ProducesResponseType(201)]
[ProducesResponseType(typeof(Rate), 400)]
[ProducesResponseType(500)]
public async Task<IActionResult> Post([FromBody] Rate rate)
{
try
{
if (rate is null)
{
return BadRequest("Rate cannot be null.");
}
var result = await _rateService.SaveAsync(rate);
return CreatedAtAction(nameof(GetById), new { id = result.RateId }, result);
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpPost("SaveRange")]
[ProducesResponseType(200)]
[ProducesResponseType(typeof(IEnumerable<Rate>), 400)]
[ProducesResponseType(500)]
public async Task<IActionResult> SaveRange([FromBody] List<Rate> rates)
{
try
{
if (rates is null || !rates.Any())
{
return BadRequest("Rates cannot be null or empty.");
}
await _rateService.SaveRangeAsync(rates);
return Ok();
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpPut]
[ProducesResponseType(200)]
[ProducesResponseType(400)]
[ProducesResponseType(404)]
[ProducesResponseType(500)]
public async Task<IActionResult> Put([FromBody] Rate rate)
{
try
{
if (rate is null)
{
return BadRequest("Rate cannot be null.");
}
if (rate.RateId == 0)
{
return BadRequest("RateId cannot be empty.");
}
var result = await _rateService.UpdateAsync(rate);
if (result is null)
{
return StatusCode(StatusCodes.Status406NotAcceptable);
}
return Ok(result);
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpPut("UpdateRange")]
[ProducesResponseType(200)]
[ProducesResponseType(400)]
[ProducesResponseType(404)]
[ProducesResponseType(500)]
public async Task<IActionResult> UpdateRange([FromBody] List<Rate> rates)
{
try
{
if (rates is null || !rates.Any())
{
return BadRequest("Rates cannot be null or empty.");
}
if (rates.Any(rate => rate.RateId == 0))
{
return BadRequest("RateIds cannot be empty.");
}
var result = await _rateService.UpdateRangeAsync(rates);
return Ok(result);
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpDelete("{id:int}")]
[ProducesResponseType(200)]
[ProducesResponseType(400)]
[ProducesResponseType(500)]
public async Task<IActionResult> Delete(int id)
{
try
{
if (id <= 0)
{
return BadRequest($"RateId {id} is invalid.");
}
await _rateService.DeleteAsync(id);
return Ok();
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpDelete("DeleteRange")]
[ProducesResponseType(200)]
[ProducesResponseType(400)]
[ProducesResponseType(500)]
public async Task<IActionResult> DeleteRange([FromBody] List<int> ids)
{
try
{
if (ids is null || !ids.Any())
{
return BadRequest("List of ids are invalid.");
}
await _rateService.DeleteRangeAsync(ids);
return Ok();
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpDelete("ClearCache")]
[ProducesResponseType(200)]
[ProducesResponseType(500)]
public IActionResult ClearCache()
{
try
{
_rateService.ClearCache();
return Ok();
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
}
@@ -0,0 +1,313 @@
using Microsoft.AspNetCore.Mvc;
using LCU.API.Internal.LoanRate.Services;
namespace LCU.API.Internal.LoanRate.Controllers;
[ApiController]
[Route("api/[controller]")]
public class RateEvaluationController : ControllerBase
{
private readonly IRateEvaluationService _rateEvaluationService;
public RateEvaluationController(IRateEvaluationService rateEvaluationService)
{
_rateEvaluationService = rateEvaluationService;
}
[HttpGet]
[ProducesResponseType(200)]
[ProducesResponseType(204)]
[ProducesResponseType(500)]
public async Task<IActionResult> Get()
{
try
{
var result = await _rateEvaluationService.GetAsync();
if (result is null || !result.Any())
{
return NoContent();
}
return Ok(result);
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpGet("{id:int}")]
[ProducesResponseType(200)]
[ProducesResponseType(204)]
[ProducesResponseType(typeof(RateEvaluation), 400)]
[ProducesResponseType(500)]
public async Task<IActionResult> GetById(int id)
{
try
{
if (id <= 0)
{
return BadRequest($"Id {id} is invalid.");
}
var result = await _rateEvaluationService.GetByIdAsync(id);
if (result is null)
{
return NoContent();
}
return Ok(result);
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpPost("GetListById")]
[ProducesResponseType(200)]
[ProducesResponseType(204)]
[ProducesResponseType(typeof(IEnumerable<RateEvaluation>), 400)]
[ProducesResponseType(500)]
public async Task<IActionResult> GetListById([FromBody] List<int> ids)
{
try
{
if (ids is null || !ids.Any())
{
return BadRequest("List of ids are invalid.");
}
var result = await _rateEvaluationService.GetRangeByIdAsync(ids);
if (result == null)
{
return NoContent();
}
return Ok(result);
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpPost]
[ProducesResponseType(201)]
[ProducesResponseType(typeof(RateEvaluation), 400)]
[ProducesResponseType(500)]
public async Task<IActionResult> Post([FromBody] RateEvaluation rateEvaluation)
{
try
{
if (rateEvaluation is null)
{
return BadRequest("RateEvaluation cannot be null.");
}
var result = await _rateEvaluationService.SaveAsync(rateEvaluation);
return CreatedAtAction(nameof(GetById), new { id = result.RateEvaluationId }, result);
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpPost("SaveRange")]
[ProducesResponseType(200)]
[ProducesResponseType(typeof(IEnumerable<RateEvaluation>), 400)]
[ProducesResponseType(500)]
public async Task<IActionResult> SaveRange([FromBody] List<RateEvaluation> rateEvaluations)
{
try
{
if (rateEvaluations is null || !rateEvaluations.Any())
{
return BadRequest("RateEvaluations cannot be null or empty.");
}
await _rateEvaluationService.SaveRangeAsync(rateEvaluations);
return Ok();
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpPut]
[ProducesResponseType(200)]
[ProducesResponseType(400)]
[ProducesResponseType(404)]
[ProducesResponseType(500)]
public async Task<IActionResult> Put([FromBody] RateEvaluation rateEvaluation)
{
try
{
if (rateEvaluation is null)
{
return BadRequest("RateEvaluation cannot be null.");
}
if (rateEvaluation.RateEvaluationId == 0)
{
return BadRequest("RateEvaluationId cannot be empty.");
}
var result = await _rateEvaluationService.UpdateAsync(rateEvaluation);
if (result is null)
{
return StatusCode(StatusCodes.Status406NotAcceptable);
}
return Ok(result);
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpPut("UpdateRange")]
[ProducesResponseType(200)]
[ProducesResponseType(400)]
[ProducesResponseType(404)]
[ProducesResponseType(500)]
public async Task<IActionResult> UpdateRange([FromBody] List<RateEvaluation> rateEvaluations)
{
try
{
if (rateEvaluations is null || !rateEvaluations.Any())
{
return BadRequest("RateEvaluations cannot be null or empty.");
}
if (rateEvaluations.Any(rateEvaluation => rateEvaluation.RateEvaluationId == 0))
{
return BadRequest("RateEvaluationIds cannot be empty.");
}
var result = await _rateEvaluationService.UpdateRangeAsync(rateEvaluations);
return Ok(result);
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpDelete("{id:int}")]
[ProducesResponseType(200)]
[ProducesResponseType(400)]
[ProducesResponseType(500)]
public async Task<IActionResult> Delete(int id)
{
try
{
if (id <= 0)
{
return BadRequest($"RateEvaluationId {id} is invalid.");
}
await _rateEvaluationService.DeleteAsync(id);
return Ok();
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpDelete("DeleteRange")]
[ProducesResponseType(200)]
[ProducesResponseType(400)]
[ProducesResponseType(500)]
public async Task<IActionResult> DeleteRange([FromBody] List<int> ids)
{
try
{
if (ids is null || !ids.Any())
{
return BadRequest("List of ids are invalid.");
}
await _rateEvaluationService.DeleteRangeAsync(ids);
return Ok();
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpGet("CountByEvaluationDetailId/{evaluationDetailId:int}")]
[ProducesResponseType(200)]
[ProducesResponseType(400)]
[ProducesResponseType(500)]
public async Task<IActionResult> CountByEvaluationDetailId(int evaluationDetailId)
{
try
{
if (evaluationDetailId <= 0)
{
return BadRequest($"EvaluationDetailId {evaluationDetailId} is invalid.");
}
return Ok(await _rateEvaluationService.CountByEvaluationDetailIdAsync(evaluationDetailId));
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
}
@@ -0,0 +1,56 @@
using Microsoft.AspNetCore.Mvc;
using LCU.Library.Internal.LoanRateModels.Requests;
using LCU.API.Internal.LoanRate.Services.LoanRateOperationServices;
namespace LCU.API.Internal.LoanRate.Controllers;
[ApiController]
[Route("api/[controller]")]
public class RateFinderController : ControllerBase
{
private readonly IRateFinderService _rateFinderService;
public RateFinderController(IRateFinderService rateFinderService)
{
_rateFinderService = rateFinderService;
}
[HttpPost("FindRate")]
[ProducesResponseType(200)]
[ProducesResponseType(500)]
public async Task<IActionResult> FindRate([FromBody] RateRequest request)
{
try
{
return Ok(await _rateFinderService.FindRate(request));
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpPost("FindRateObject")]
[ProducesResponseType(200)]
[ProducesResponseType(500)]
public async Task<IActionResult> FindRateObject([FromBody] RateRequest request)
{
try
{
return Ok(await _rateFinderService.FindRateObject(request));
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
}
@@ -0,0 +1,288 @@
using Microsoft.AspNetCore.Mvc;
using LCU.API.Internal.LoanRate.Services;
using LCU.Library.Internal.LoanRateModels.Entities.LoadTestingEntities;
namespace LCU.API.Internal.LoanRate.Controllers;
[ApiController]
[Route("api/[controller]")]
public class RateProcessingInfoController : ControllerBase
{
private readonly IRateProcessingInfoService _rateProcessingInfoService;
public RateProcessingInfoController(IRateProcessingInfoService rateProcessingInfoService)
{
_rateProcessingInfoService = rateProcessingInfoService;
}
[HttpGet]
[ProducesResponseType(200)]
[ProducesResponseType(204)]
[ProducesResponseType(500)]
public async Task<IActionResult> Get()
{
try
{
var result = await _rateProcessingInfoService.GetAsync();
if (result is null || !result.Any())
{
return NoContent();
}
return Ok(result);
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpGet("{id:int}")]
[ProducesResponseType(200)]
[ProducesResponseType(204)]
[ProducesResponseType(typeof(RateProcessingInfo), 400)]
[ProducesResponseType(500)]
public async Task<IActionResult> GetById(int id)
{
try
{
if (id <= 0)
{
return BadRequest($"Id {id} is invalid.");
}
var result = await _rateProcessingInfoService.GetByIdAsync(id);
if (result is null)
{
return NoContent();
}
return Ok(result);
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpPost("GetListById")]
[ProducesResponseType(200)]
[ProducesResponseType(204)]
[ProducesResponseType(typeof(IEnumerable<RateProcessingInfo>), 400)]
[ProducesResponseType(500)]
public async Task<IActionResult> GetListById([FromBody] List<int> ids)
{
try
{
if (ids is null || !ids.Any())
{
return BadRequest("List of ids are invalid.");
}
var result = await _rateProcessingInfoService.GetRangeByIdAsync(ids);
if (result == null)
{
return NoContent();
}
return Ok(result);
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpPost]
[ProducesResponseType(201)]
[ProducesResponseType(typeof(RateProcessingInfo), 400)]
[ProducesResponseType(500)]
public async Task<IActionResult> Post([FromBody] RateProcessingInfo rateProcessingInfo)
{
try
{
if (rateProcessingInfo is null)
{
return BadRequest("RateProcessingInfo cannot be null.");
}
var result = await _rateProcessingInfoService.SaveAsync(rateProcessingInfo);
return CreatedAtAction(nameof(GetById), new { id = result.RateProcessingInfoId }, result);
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpPost("SaveRange")]
[ProducesResponseType(200)]
[ProducesResponseType(typeof(IEnumerable<RateProcessingInfo>), 400)]
[ProducesResponseType(500)]
public async Task<IActionResult> SaveRange([FromBody] List<RateProcessingInfo> rateProcessingInfos)
{
try
{
if (rateProcessingInfos is null || !rateProcessingInfos.Any())
{
return BadRequest("RateProcessingInfos cannot be null or empty.");
}
await _rateProcessingInfoService.SaveRangeAsync(rateProcessingInfos);
return Ok();
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpPut]
[ProducesResponseType(200)]
[ProducesResponseType(400)]
[ProducesResponseType(404)]
[ProducesResponseType(500)]
public async Task<IActionResult> Put([FromBody] RateProcessingInfo rateProcessingInfo)
{
try
{
if (rateProcessingInfo is null)
{
return BadRequest("RateProcessingInfo cannot be null.");
}
if (rateProcessingInfo.RateProcessingInfoId == 0)
{
return BadRequest("RateProcessingInfoId cannot be empty.");
}
var result = await _rateProcessingInfoService.UpdateAsync(rateProcessingInfo);
if (result is null)
{
return StatusCode(StatusCodes.Status406NotAcceptable);
}
return Ok(result);
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpPut("UpdateRange")]
[ProducesResponseType(200)]
[ProducesResponseType(400)]
[ProducesResponseType(404)]
[ProducesResponseType(500)]
public async Task<IActionResult> UpdateRange([FromBody] List<RateProcessingInfo> rateProcessingInfos)
{
try
{
if (rateProcessingInfos is null || !rateProcessingInfos.Any())
{
return BadRequest("RateProcessingInfos cannot be null or empty.");
}
if (rateProcessingInfos.Any(rateProcessingInfo => rateProcessingInfo.RateProcessingInfoId == 0))
{
return BadRequest("RateProcessingInfoIds cannot be empty.");
}
var result = await _rateProcessingInfoService.UpdateRangeAsync(rateProcessingInfos);
return Ok(result);
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpDelete("{id:int}")]
[ProducesResponseType(200)]
[ProducesResponseType(400)]
[ProducesResponseType(500)]
public async Task<IActionResult> Delete(int id)
{
try
{
if (id <= 0)
{
return BadRequest($"RateProcessingInfoId {id} is invalid.");
}
await _rateProcessingInfoService.DeleteAsync(id);
return Ok();
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpDelete("DeleteRange")]
[ProducesResponseType(200)]
[ProducesResponseType(400)]
[ProducesResponseType(500)]
public async Task<IActionResult> DeleteRange([FromBody] List<int> ids)
{
try
{
if (ids is null || !ids.Any())
{
return BadRequest("List of ids are invalid.");
}
await _rateProcessingInfoService.DeleteRangeAsync(ids);
return Ok();
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
}
@@ -0,0 +1,17 @@
using LCU.API.Internal.LoanRate.Services;
using LCU.Library.Internal.LcuClassPatterns.Crud.Controllers;
using Microsoft.AspNetCore.Mvc;
namespace LCU.API.Internal.LoanRate.Controllers;
[ApiController]
[Route("api/[controller]")]
public class RateSheetCellController : CrudController<RateSheetCell>
{
private readonly IRateSheetCellService _rateSheetCellService;
public RateSheetCellController(IRateSheetCellService rateSheetCellService) : base(rateSheetCellService)
{
_rateSheetCellService = rateSheetCellService;
}
}
@@ -0,0 +1,48 @@
using Microsoft.AspNetCore.Mvc;
using LCU.Library.Internal.LoanRateModels.Requests;
using LCU.API.Internal.LoanRate.Services.LoanRateOperationServices;
namespace LCU.API.Internal.LoanRate.Controllers;
[ApiController]
[Route("api/[controller]")]
public class RateSheetCellUploaderController : ControllerBase
{
private readonly IRateSheetCellUploaderService _rateSheetCellUploaderService;
public RateSheetCellUploaderController(IRateSheetCellUploaderService rateSheetCellUploaderService)
{
_rateSheetCellUploaderService = rateSheetCellUploaderService;
}
[HttpPost("UploadRateSheetCells")]
[ProducesResponseType(200)]
[ProducesResponseType(400)]
[ProducesResponseType(500)]
public async Task<IActionResult> UploadRateSheetCells(RateSheetCellUploadRequest request)
{
try
{
if (request is null)
{
return BadRequest("RateSheetCellUploadRequest is required.");
}
var result = await _rateSheetCellUploaderService.UploadRateSheetCellsAsync(request);
if (result is null)
{
return NoContent();
}
return Ok(result);
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
}
@@ -0,0 +1,72 @@
using LCU.API.Internal.LoanRate.Services;
using LCU.Library.Internal.LcuClassPatterns.Crud.Controllers;
using LCU.Library.Internal.LoanRateModels.Requests;
using Microsoft.AspNetCore.Mvc;
namespace LCU.API.Internal.LoanRate.Controllers;
[ApiController]
[Route("api/[controller]")]
public class RateSheetController : CrudController<RateSheet>
{
private readonly IRateSheetService _rateSheetService;
public RateSheetController(IRateSheetService rateSheetService) : base(rateSheetService)
{
_rateSheetService = rateSheetService;
}
[HttpPost("GetByDateAndRateType")]
[ProducesResponseType(200)]
[ProducesResponseType(204)]
[ProducesResponseType(typeof(Rate), 400)]
[ProducesResponseType(500)]
public async Task<IActionResult> GetByDateAndRateType([FromBody] RateSheetRequest request)
{
try
{
if (request is null)
{
return BadRequest("Request cannot be null.");
}
var result = await _rateSheetService.GetByDateAndRateTypeAsync( request.EffectiveDate, request.RateType);
if (result is null)
{
return NoContent();
}
return Ok(result);
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpDelete("ClearCache")]
[ProducesResponseType(200)]
[ProducesResponseType(500)]
public IActionResult ClearCache()
{
try
{
_rateSheetService.ClearCache();
return Ok();
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
}
@@ -0,0 +1,123 @@
using LCU.API.Internal.LoanRate.Services;
using LCU.Library.Internal.LcuClassPatterns.Crud.Controllers;
using LCU.Library.Internal.LoanRateModels.Requests;
using LCU.Library.Internal.LoanRateModels.Responses;
using Microsoft.AspNetCore.Mvc;
namespace LCU.API.Internal.LoanRate.Controllers;
[ApiController]
[Route("api/[controller]")]
public class RateUploadInfoController : CrudController<RateUploadInfo>
{
private readonly IRateUploadInfoService _rateUploadInfoService;
public RateUploadInfoController(IRateUploadInfoService rateUploadInfoService) : base(rateUploadInfoService)
{
_rateUploadInfoService = rateUploadInfoService;
}
[HttpGet("GetLatest")]
[ProducesResponseType(typeof(RateUploadInfo), 200)]
[ProducesResponseType(204)]
[ProducesResponseType(500)]
public async Task<IActionResult> GetLatest()
{
try
{
var result = await _rateUploadInfoService.GetLatestAsync();
if (result is null)
{
return NoContent();
}
return Ok(result);
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpPost("GetFilteredRateUploadInfo")]
[ProducesResponseType(typeof(RateUploadInfoFilterResponse), 200)]
[ProducesResponseType(500)]
public async Task<IActionResult> GetFilteredRateUploadInfo([FromBody] RateUploadInfoFilter rateUploadInfoFilter)
{
try
{
var filterResult = await _rateUploadInfoService.GetFilteredRateUploadInfo(rateUploadInfoFilter);
var result = new RateUploadInfoFilterResponse(filterResult, rateUploadInfoFilter);
return Ok(result);
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpDelete("ComplexDelete/{id:int}")]
[ProducesResponseType(200)]
[ProducesResponseType(400)]
[ProducesResponseType(500)]
public async Task<IActionResult> ComplexDelete(int id)
{
try
{
if (id == 0)
{
return BadRequest("RateProcessingInfoId is required.");
}
await _rateUploadInfoService.ComplexDelete(id);
return Ok();
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpPost("ComplexSave")]
[ProducesResponseType(200)]
[ProducesResponseType(400)]
[ProducesResponseType(500)]
public async Task<IActionResult> ComplexSave(RateUploadInfoRequest request)
{
try
{
if (request is null)
{
return BadRequest("RateProcessingInfoRequest is required.");
}
var result = await _rateUploadInfoService.ComplexSave(request);
return Ok(result);
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
}
@@ -0,0 +1,92 @@
using Microsoft.AspNetCore.Mvc;
using LCU.Library.Internal.LoanRateModels.Requests;
using LCU.API.Internal.LoanRate.Services.LoanRateOperationServices;
using LCU.Api.Internal.FileOperationsLib.Models.ExcelModels.Requests;
namespace LCU.API.Internal.LoanRate.Controllers;
[ApiController]
[Route("api/[controller]")]
public class RateUploaderController : ControllerBase
{
private readonly IRateUploaderService _rateUploaderService;
public RateUploaderController(IRateUploaderService rateUploaderService)
{
_rateUploaderService = rateUploaderService;
}
[HttpPost("UploadRates")]
[ProducesResponseType(200)]
[ProducesResponseType(400)]
[ProducesResponseType(500)]
public async Task<IActionResult> UploadRates(RateUploadRequest request)
{
try
{
if (request is null)
{
return BadRequest("RateUploadRequest is required.");
}
await _rateUploaderService.UploadRates(request);
return Ok();
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpPost("UploadRatesByExcelDataRequest")]
[ProducesResponseType(200)]
[ProducesResponseType(500)]
public async Task<IActionResult> UploadRates([FromBody] RateUploadExcelDataRequest request)
{
try
{
await _rateUploaderService.UploadRates(request);
return Ok();
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpPost("InitiateRatesRulesRequest")]
[ProducesResponseType(200)]
[ProducesResponseType(400)]
[ProducesResponseType(500)]
public async Task<IActionResult> InitiateRatesRulesRequest([FromBody] IEnumerable<InitiateRatesEvaluationsRequest> requests)
{
try
{
if (requests is null || !requests.Any())
{
return BadRequest("Request can't be null.");
}
var result = await _rateUploaderService.InitiateRatesEvaluations(requests);
return Ok(result);
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
}
@@ -0,0 +1,54 @@
using LCU.API.Internal.LoanRate.Services;
using LCU.API.Internal.LoanRate.Services.LoanRateOperationServices;
using LCU.Library.Internal.LcuClassPatterns.Crud.Controllers;
using LCU.Library.Internal.LoanRateModels.Requests;
using LCU.Library.Internal.LoanRateModels.Responses.Validation;
using LCU.Library.Internal.LoanRateModels.Responses.Validation.RateSheetValidations;
using Microsoft.AspNetCore.Mvc;
namespace LCU.API.Internal.LoanRate.Controllers;
[ApiController]
[Route("api/[controller]")]
public class RateValidationController : ControllerBase
{
private readonly IRateValidationService _rateValidationService;
public RateValidationController(IRateValidationService rateValidationService)
{
_rateValidationService = rateValidationService;
}
[HttpPost("Validate")]
[ProducesResponseType(200)]
[ProducesResponseType(204)]
[ProducesResponseType(typeof(RateSheetValidationResult), 400)]
[ProducesResponseType(500)]
public async Task<IActionResult> Validate([FromBody] List<Rate> rates)
{
try
{
if (rates is null || rates.Count == 0)
{
return BadRequest("Rates cannot be null.");
}
var result = await _rateValidationService.ValidateAsync(rates);
if (result is null)
{
return NoContent();
}
return Ok(result);
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
}
@@ -0,0 +1,34 @@
using LCU.API.Internal.LoanRate.Services;
using Microsoft.AspNetCore.Mvc;
namespace LCU.API.Internal.LoanRate.Controllers;
[ApiController]
[Route("api/[controller]")]
public class StatusController : ControllerBase
{
private readonly IStatusService _statusService;
public StatusController(IStatusService statusService)
{
_statusService = statusService;
}
[HttpGet]
[ProducesResponseType(200)]
[ProducesResponseType(500)]
public IActionResult Get()
{
try
{
return Ok(_statusService.GetEnviromentView());
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
}
@@ -0,0 +1,106 @@
using Microsoft.AspNetCore.Mvc;
using LCU.Library.Internal.LoanRateModels.Requests;
using LCU.Library.Internal.LcuEvaluation.Services.EvaluationServices;
using LCU.API.Internal.LoanRate.Services.ValidateLoanRateServices;
using LCU.API.Internal.LoanRate.Services.LoanRateOperationServices;
using LCU.Library.Internal.LcuEvaluationModels.Enums;
namespace LCU.API.Internal.LoanRate.Controllers;
[ApiController]
[Route("api/[controller]")]
public class ValidateRateEvaluationsController : ControllerBase
{
private readonly IValidateRateEvaluationsService _validateRateEvaluationsService;
private readonly IRateFinderService _rateFinderService;
private readonly IExecuteEvaluationService _executeEvaluationService;
public ValidateRateEvaluationsController(IValidateRateEvaluationsService validateRateEvaluationsService,
IRateFinderService rateFinderService,
IExecuteEvaluationService executeEvaluationService)
{
_validateRateEvaluationsService = validateRateEvaluationsService;
_rateFinderService = rateFinderService;
_executeEvaluationService = executeEvaluationService;
}
[HttpPost("ValidateRatePassesEvaluation")]
[ProducesResponseType(200)]
[ProducesResponseType(500)]
public async Task<IActionResult> ValidateRatePassesEvaluation([FromBody] RateRequest request, int rateId, int evaluationDetailId)
{
try
{
return Ok(await _validateRateEvaluationsService.ValidateRatePassesEvaluation(request, rateId, evaluationDetailId));
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpPost("ValidateRatePassesEvaluations")]
[ProducesResponseType(200)]
[ProducesResponseType(500)]
public async Task<IActionResult> ValidateRatePassesEvaluations([FromBody] RateRequest request, int rateId)
{
try
{
return Ok(await _validateRateEvaluationsService.ValidateRatePassesEvaluations(request, rateId));
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpPost("DetermineRatePassedRules")]
[ProducesResponseType(200)]
[ProducesResponseType(500)]
public async Task<IActionResult> DetermineVehicleRatePassedRules([FromBody] RateRequest request)
{
try
{
return Ok(await _rateFinderService.DeterminePassedRules(request));
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
[HttpPost("RawEvaluationTest")]
[ProducesResponseType(200)]
[ProducesResponseType(500)]
public IActionResult RawEvaluationTest(string evaluationCondition, EvaluationReturnTypes evaluationReturnType)
{
try
{
return Ok(_executeEvaluationService.ExecuteCondition(evaluationCondition, evaluationReturnType));
}
catch (ServiceException exception)
{
return StatusCode(StatusCodes.Status500InternalServerError, exception.Message);
}
catch (Exception exception)
{
Log.Error(exception, "Unexpected Exception");
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
}
@@ -0,0 +1,23 @@
using LCU.Library.Internal.LcuHttpClient.HttpRequest;
using LCU.Api.Internal.FileOperationsLib.Models.ExcelModels.Requests;
using LCU.Api.Internal.FileOperationsLib.Models.ExcelModels.Responses;
using LCU.API.Internal.LoanRate.Configurations;
namespace LCU.API.Internal.LoanRate.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<ExcelDataResponse> DirectExtractExcelWorkBookData(ExcelDataRequest request)
{
return await _postRequest.Async<ExcelDataRequest, ExcelDataResponse>(_fileOperationsApiConfiguration.ExtractExcelWorkBookDataEndpointUri,
request);
}
}
@@ -0,0 +1,8 @@
using LCU.Api.Internal.FileOperationsLib.Models.ExcelModels.Requests;
using LCU.Api.Internal.FileOperationsLib.Models.ExcelModels.Responses;
namespace LCU.API.Internal.LoanRate.DataAccess;
public interface IFileOperationsApiDao
{
Task<ExcelDataResponse> DirectExtractExcelWorkBookData(ExcelDataRequest request);
}
@@ -0,0 +1,42 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<IsPackable>true</IsPackable>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<NoWarn>1701;1702;8618;1591</NoWarn>
<TreatWarningsAsErrors>False</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<NoWarn>1701;1702;8618;1591</NoWarn>
<TreatWarningsAsErrors>False</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<Compile Remove="HostedServices\**" />
<Content Remove="HostedServices\**" />
<EmbeddedResource Remove="HostedServices\**" />
<None Remove="HostedServices\**" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="LCU.Api.Internal.FileOperationsLib" Version="3.30.6" />
<PackageReference Include="LCU.Api.Internal.MaidBotLib" Version="1.0.2" />
<PackageReference Include="LCU.Library.Internal.Configuration" Version="1.0.0" />
<PackageReference Include="LCU.Library.Internal.Exceptions" Version="1.1.0" />
<PackageReference Include="LCU.Library.Internal.LcuClassPatterns.Crud" Version="1.0.2" />
<PackageReference Include="LCU.Library.Internal.LcuEvaluation" Version="2.0.3" />
<PackageReference Include="LCU.Library.Internal.LcuHttpClient" Version="1.12.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.Logging" Version="1.1.0" />
<PackageReference Include="LCU.Library.Internal.Status" Version="1.2.0" />
<PackageReference Include="Microsoft.Data.SqlClient" Version="5.2.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.8" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LCU.API.Internal.LoanRateLib\LCU.API.Internal.LoanRateLib.csproj" />
<ProjectReference Include="..\LCU.API.Internal.LoanRateLoadTestingLib\LCU.API.Internal.LoanRateLoadTestingLib.csproj" />
<ProjectReference Include="..\LCU.Library.Internal.LoanRateModels\LCU.Library.Internal.LoanRateModels.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,328 @@
using System.Text.Json.Serialization;
using Microsoft.OpenApi.Models;
using Microsoft.EntityFrameworkCore;
using MassTransit;
using Newtonsoft.Json;
using LCU.Library.Internal.Configuration;
using LCU.Library.Internal.Logging;
using LCU.Library.Internal.Logging.Middleware;
using LCU.Library.Internal.Logging.Models;
using LCU.Library.Internal.Status;
using LCU.Library.Internal.LcuMassTransitModels;
using LCU.Library.Internal.LcuMassTransit;
using LCU.Library.Internal.LcuHttpClient;
using LCU.API.Internal.LoanRate.Configurations;
using LoadTestingLibAppDbContext = LCU.API.Internal.LoanRateLoadTestingLib.Persistence.AppDbContext;
using LoadTestingLibRepository = LCU.API.Internal.LoanRateLoadTestingLib.Repositories;
using LCU.API.Internal.LoanRateLoadTestingLib.Repositories;
using LCU.API.Internal.LoanRate.Services;
using LCU.API.Internal.LoanRate.Services.LoanRateOperationServices;
using LoanRateLibRepository = LCU.API.Internal.LoanRateLib.Repositories;
using LoanRateLibPersistence = LCU.API.Internal.LoanRateLib.Persistence;
using LCU.API.Internal.LoanRateLib.Repositories;
using LCU.API.Internal.LoanRate.Services.ValidateLoanRateServices;
using LCU.API.Internal.LoanRate.Consumers;
using LCU.API.Internal.LoanRate.Services.LoadTestingServices;
using LCU.API.Internal.LoanRate.Services.QueueServices;
using LCU.API.Internal.LoanRate.DataAccess;
using LCU.API.Internal.LoanRate.Services.MicroApiServices;
using LCU.API.Internal.LoanRateLib.Configurations;
using LCU.Library.Internal.LcuClassPatterns.Crud;
using LCU.Library.Internal.LcuEvaluation;
string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
var builder = BuildBuilder(args);
BuildServicesAndConfigurations(builder);
BuildAppAndRun(builder);
WebApplicationBuilder BuildBuilder(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
builder.Configuration.AddJsonFile("/app/config/environment-appsettings/appsettings.json", optional: true, reloadOnChange: true);
builder.Configuration.AddJsonFile("/app/config/mapped-appsettings/appsettings.json", optional: true, reloadOnChange: true);
builder.Configuration.AddJsonFile("/vault/secrets/loan-rate-queue-password.json", optional: true, reloadOnChange: true);
builder.Configuration.AddJsonFile("/vault/secrets/loan-rate-queue-username.json", optional: true, reloadOnChange: true);
builder.Configuration.AddJsonFile("/vault/secrets/loan-rate-evaluation-connection-string.json", optional: true, reloadOnChange: true);
builder.Configuration.AddJsonFile("/vault/secrets/loan-rate-load-test-connection-string.json", optional: true, reloadOnChange: true);
builder.Configuration.AddJsonFile("/vault/secrets/loan-rate-loan-rate-connection-string.json", optional: true, reloadOnChange: true);
builder.Configuration.AddJsonFile("/vault/secrets/loan-rate-seq-api-key.json", optional: true, reloadOnChange: true);
builder.Host.UseSerilog();
return builder;
}
void BuildServicesAndConfigurations(WebApplicationBuilder builder)
{
var services = builder.Services;
var configuration = builder.Configuration;
var apiConfiguration = configuration.Bind<ApiConfiguration>(services, "Primary");
configuration.Bind<FileOperationsApiConfiguration>(services);
configuration.Bind<RateCacheConfiguration>(services);
configuration.Bind<RateSheetCacheConfiguration>(services);
var connectionConfiguration = MassTransitConfigurationSetUp.AddConnectionConfiguration(ref services, configuration);
//debugging
Console.WriteLine(JsonConvert.SerializeObject(connectionConfiguration));
var receiveEndpointConfigurations = new ReceiveEndpointConfigurations()
{
LoadTestInitiateReceiveEndpoint = MassTransitConfigurationSetUp.GetReceiveEndpointConfiguration(configuration,
"LoadTestInitiateReceiveEndpoint"),
LoadTestProcessRateReceiveEndpoint = MassTransitConfigurationSetUp.GetReceiveEndpointConfiguration(configuration,
"LoadTestProcessRateReceiveEndpoint"),
LoadTestRateCompletionReceiveEndpoint = MassTransitConfigurationSetUp.GetReceiveEndpointConfiguration(configuration,
"LoadTestRateCompletionReceiveEndpoint")
};
services.AddSingleton(receiveEndpointConfigurations);
//debugging
Console.WriteLine(JsonConvert.SerializeObject(receiveEndpointConfigurations));
var loggerConfiguration = new LoggingConfiguration(apiConfiguration.AppName,
apiConfiguration.SeqApiKey,
apiConfiguration.SeqUrl);
var lcuLogging = new LcuLogging(loggerConfiguration);
lcuLogging.UseLcuLogging();
var loanRateSqlConnectionConfiguration = configuration.Bind<LoanRateSqlConnectionConfiguration>(services);
services.AddDbContext<LoanRateLibPersistence.AppDbContext>(options =>
{
options.UseSqlServer
(
loanRateSqlConnectionConfiguration.ConnectionString,
sql => sql.EnableRetryOnFailure(loanRateSqlConnectionConfiguration.MaxRetryCount,
loanRateSqlConnectionConfiguration.MaxRetryDelay,
null)
);
});
var loanRateLoadTestingSqlConnectionConfiguration = configuration.Bind<LoanRateLoadTestingSqlConnectionConfiguration>(services);
services.AddDbContext<LoadTestingLibAppDbContext>(options =>
{
options.UseSqlServer
(
loanRateLoadTestingSqlConnectionConfiguration.ConnectionString,
sql => sql.EnableRetryOnFailure(loanRateLoadTestingSqlConnectionConfiguration.MaxRetryCount,
loanRateLoadTestingSqlConnectionConfiguration.MaxRetryDelay,
null)
);
});
services.AddCors(options =>
{
options.AddPolicy(MyAllowSpecificOrigins,
builder =>
{
builder.WithOrigins(
apiConfiguration.CorsAllowedOrigins
).AllowAnyHeader().AllowAnyMethod();
});
});
AddMassTransitServices(ref services, connectionConfiguration, receiveEndpointConfigurations, apiConfiguration);
services.AddLCUHttpServices();
AddLoanRateLib(services);
AddLoanRateLoadTestingLib(services);
AddDataAccess(services);
AddApiServices(services);
services.AddLcuEvaluationServices();
services.AddLcuEvaluationCrudServices(configuration);
services.AddLCUStatusServicesWithApiHealthCheck(configuration);
services.AddLcuCrudServices();
services.AddHttpClient();
services.AddMemoryCache();
services.AddControllers().AddJsonOptions(options => options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()));
services.AddEndpointsApiExplorer();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = $"{apiConfiguration.AppName}", Version = "v1" });
});
}
void AddMassTransitServices(ref IServiceCollection services,
ConnectionConfiguration connectionConfiguration,
ReceiveEndpointConfigurations receiveEndpointConfigurations,
ApiConfiguration apiConfiguration)
{
services.AddMassTransit(x =>
{
x.AddConsumer<LoadTestInitiateConsumer>();
x.AddConsumer<LoadTestProcessRateConsumer>();
x.AddConsumer<LoadTestRateCompletionConsumer>();
x.UsingRabbitMq((context, cfg) =>
{
cfg.Host(connectionConfiguration.HostUrl, "/", host =>
{
host.Username(connectionConfiguration.UserName);
host.Password(connectionConfiguration.Password);
});
cfg.UseTimeout(t => t.Timeout = TimeSpan.FromSeconds(420));
if (apiConfiguration.FeatureFlags.RunLoadTestInitiateConsumer)
{
cfg.ReceiveEndpoint(receiveEndpointConfigurations.LoadTestInitiateReceiveEndpoint.ReceiveEndpoint, e =>
{
e.ConfigureConsumer<LoadTestInitiateConsumer>(context);
e.SetQuorumQueue();
e.PrefetchCount = receiveEndpointConfigurations.LoadTestInitiateReceiveEndpoint.PrefetchLimit;
e.UseTimeout(t => t.Timeout = TimeSpan.FromSeconds(420));
});
}
if (apiConfiguration.FeatureFlags.RunLoadTestProcessRateConsumer)
{
cfg.ReceiveEndpoint(receiveEndpointConfigurations.LoadTestProcessRateReceiveEndpoint.ReceiveEndpoint, e =>
{
e.ConfigureConsumer<LoadTestProcessRateConsumer>(context);
e.SetQuorumQueue();
e.PrefetchCount = receiveEndpointConfigurations.LoadTestProcessRateReceiveEndpoint.PrefetchLimit;
e.UseTimeout(t => t.Timeout = TimeSpan.FromSeconds(420));
});
}
if (apiConfiguration.FeatureFlags.RunLoadTestRateCompletionConsumer)
{
cfg.ReceiveEndpoint(receiveEndpointConfigurations.LoadTestRateCompletionReceiveEndpoint.ReceiveEndpoint, e =>
{
e.ConfigureConsumer<LoadTestRateCompletionConsumer>(context, cons =>
{
//TODO: Will need to add optional configuration in our LCU Masstransit Library for these configurables.
cons.Options<BatchOptions>(options => options
.SetMessageLimit(100)
.SetTimeLimit(5000)
.SetConcurrencyLimit(1));
});
e.SetQuorumQueue();
e.PrefetchCount = receiveEndpointConfigurations.LoadTestRateCompletionReceiveEndpoint.PrefetchLimit;
e.UseTimeout(t => t.Timeout = TimeSpan.FromSeconds(420));
});
}
});
});
services.AddMassTransitHostedService();
}
void AddApiServices(IServiceCollection services)
{
services.AddScoped<IStatusService, StatusService>();
AddLoadTestingServices(services);
AddLoanRateOperationServices(services);
AddValidateLoanRateServices(services);
AddMicroApiServices(services);
AddQueueServices(services);
services.AddScoped<IRateUploadInfoService, RateUploadInfoService>();
services.AddScoped<IRateSheetService, RateSheetService>();
services.AddScoped<IRateSheetCellService, RateSheetCellService>();
services.AddScoped<IRateService, RateService>();
services.AddScoped<IRateEvaluationService, RateEvaluationService>();
services.AddScoped<IComplexEvaluationDetailService, ComplexEvaluationDetailService>();
services.AddScoped<ILoadTestRunInfoService, LoadTestRunInfoService>();
services.AddScoped<IRateProcessingInfoService, RateProcessingInfoService>();
}
void AddLoadTestingServices(IServiceCollection services)
{
services.AddScoped<ILoadTestInitiationService, LoadTestInitiationService>();
services.AddScoped<ILoadTestProcessRateService, LoadTestProcessRateService>();
services.AddScoped<ILoadTestRateCompletionService, LoadTestRateCompletionService>();
}
void AddLoanRateOperationServices(IServiceCollection services)
{
services.AddScoped<IRateFinderService, RateFinderService>();
services.AddScoped<IRateValidationService, RateValidationService>();
services.AddScoped<IRateSheetCellUploaderService, RateSheetCellUploaderService>();
}
void AddValidateLoanRateServices(IServiceCollection services)
{
services.AddScoped<IValidateRateEvaluationsService, ValidateRateEvaluationsService>();
}
void AddMicroApiServices(IServiceCollection services)
{
services.AddScoped<IFileOperationsApiService, FileOperationsApiService>();
}
void AddQueueServices(IServiceCollection services)
{
services.AddScoped<IQueueLoadTestInitiateService, QueueLoadTestInitiateService>();
services.AddScoped<IQueueLoadTestProcessRateService, QueueLoadTestProcessRateService>();
services.AddScoped<IQueueLoadTestRateCompletionService, QueueLoadTestRateCompletionService>();
}
void AddDataAccess(IServiceCollection services)
{
services.AddScoped<IFileOperationsApiDao, FileOperationsApiDao>();
}
void AddLoanRateLib(IServiceCollection services)
{
services.AddScoped<LoanRateLibRepository.IUnitOfWork, LoanRateLibRepository.UnitOfWork>();
services.AddScoped<IRateSheetRepository, RateSheetRepository>();
services.AddScoped<IRateSheetCellRepository, RateSheetCellRepository>();
services.AddScoped<IRateUploadInfoRepository, RateUploadInfoRepository>();
services.AddScoped<IRateRepository, RateRepository>();
services.AddScoped<IRateEvaluationRepository, RateEvaluationRepository>();
}
void AddLoanRateLoadTestingLib(IServiceCollection services)
{
services.AddScoped<LoadTestingLibRepository.IUnitOfWork, LoadTestingLibRepository.UnitOfWork>();
services.AddScoped<ILoadTestRunInfoRepository, LoadTestRunInfoRepository>();
services.AddScoped<IRateProcessingInfoRepository, RateProcessingInfoRepository>();
}
void BuildAppAndRun(WebApplicationBuilder builder)
{
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseSwagger(c =>
{
c.PreSerializeFilters.Add((swaggerDoc, request) =>
{
const string prefixHeader = "X-Forwarded-Prefix";
if (!request.Headers.ContainsKey(prefixHeader)) return;
var serverUrl = request.Headers[prefixHeader];
if (!string.IsNullOrWhiteSpace(serverUrl))
{
swaggerDoc.Servers = new List<OpenApiServer>
{
new() { Description = serverUrl, Url = serverUrl }
};
}
});
});
app.UseSwaggerUI(c =>
{
c.RoutePrefix = "swagger";
c.SwaggerEndpoint("v1/swagger.json", "LCU.API.Internal.LoanRate v1");
});
app.UseMiddleware<RequestResponseLoggingMiddleware>();
app.UseSerilogRequestLogging(options =>
{
options.EnrichDiagnosticContext = RequestResponseLoggingMiddleware.RequestDataParser.EnrichFromRequest;
});
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseCors(MyAllowSpecificOrigins);
app.UseHttpsRedirection();
app.MapControllers();
app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
app.Run();
}
@@ -0,0 +1,31 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:28863",
"sslPort": 44350
}
},
"profiles": {
"API": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "https://localhost:7068;http://localhost:5159",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
@@ -0,0 +1,90 @@
using LCU.Library.Internal.LcuEvaluation.Services;
using LCU.Library.Internal.LcuEvaluationModels.Entities;
using LCU.Library.Internal.LcuEvaluationModels.Requests;
using Newtonsoft.Json;
namespace LCU.API.Internal.LoanRate.Services;
public class ComplexEvaluationDetailService : IComplexEvaluationDetailService
{
private readonly IRateEvaluationService _rateEvaluationService;
private readonly IEvaluationDetailService _evaluationDetailService;
public ComplexEvaluationDetailService(IRateEvaluationService rateEvaluationService,
IEvaluationDetailService evaluationDetailService)
{
_rateEvaluationService = rateEvaluationService;
_evaluationDetailService = evaluationDetailService;
}
public async Task<EvaluationDetail> UpdateComplexAsync(EvaluationDetail evaluationDetail)
{
try
{
return await _evaluationDetailService.UpdateComplexAsync(evaluationDetail);
}
catch (Exception exception)
{
var message = $"Failure completing complex update for EvaluationDetail. EvaluationDetailId: {evaluationDetail.EvaluationDetailId}";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task<EvaluationDetail> SaveComplexAsync(EvaluationDetailRequest request)
{
try
{
var newEvaluationDetail = await _evaluationDetailService.SaveComplexAsync(request);
var previousVersionId = request.PreviousVersionEvaluationDetailId ?? 0;
if (previousVersionId <= 0)
{
return newEvaluationDetail;
}
var rateEvaluations =
(await _rateEvaluationService.GetRangeByEvaluationDetailIdAsync(previousVersionId)).ToList();
if (rateEvaluations is null || !rateEvaluations.Any())
{
return newEvaluationDetail;
}
var newRateEvaluations = rateEvaluations.Select(rateEvaluation =>
new RateEvaluation
{
RateId = rateEvaluation.RateId,
EvaluationDetailId = newEvaluationDetail.EvaluationDetailId
}).ToList();
await _rateEvaluationService.SaveRangeAsync(newRateEvaluations);
return newEvaluationDetail;
}
catch (Exception exception)
{
var message = "Failure on SaveComplexAsync. " +
$"EvaluationDetailRequest: ({JsonConvert.SerializeObject(request)})";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task DeleteComplexAsync(int evaluationDetailId)
{
try
{
await _rateEvaluationService.DeleteRangeByEvaluationDetailIdAsync(evaluationDetailId);
await _evaluationDetailService.DeleteComplexAsync(evaluationDetailId);
}
catch (Exception exception)
{
var message = "Failure on DeleteComplexAsync. " +
$"EvaluationDetailId: ({evaluationDetailId})";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
}
@@ -0,0 +1,11 @@
using LCU.Library.Internal.LcuEvaluationModels.Entities;
using LCU.Library.Internal.LcuEvaluationModels.Requests;
namespace LCU.API.Internal.LoanRate.Services;
public interface IComplexEvaluationDetailService
{
Task<EvaluationDetail> UpdateComplexAsync(EvaluationDetail evaluationDetail);
Task<EvaluationDetail> SaveComplexAsync(EvaluationDetailRequest request);
Task DeleteComplexAsync(int evaluationDetailId);
}
@@ -0,0 +1,19 @@
using LCU.Library.Internal.LCUFilterModels.Pagination;
using LCU.Library.Internal.LoanRateModels.Entities.LoadTestingEntities;
namespace LCU.API.Internal.LoanRate.Services;
public interface ILoadTestRunInfoService
{
Task<IEnumerable<LoadTestRunInfo>> GetAsync();
Task<LoadTestRunInfo?> GetByIdAsync(int id);
Task<IEnumerable<LoadTestRunInfo>> GetRangeByIdAsync(List<int> ids);
Task<PagedResult<LoadTestRunInfo>> GetFilteredLoadTestRunInfo(LoadTestRunInfoFilter loadTestRunInfoFilter);
Task<LoadTestRunInfo> SaveAsync(LoadTestRunInfo loadTestRunInfo);
Task SaveRangeAsync(IEnumerable<LoadTestRunInfo> loadTestRunInfos);
Task<LoadTestRunInfo> IncreaseRateProcessingInfosCompleteCountAsync(int loadTestRunInfoId, int countCompleted);
Task<LoadTestRunInfo> UpdateAsync(LoadTestRunInfo loadTestRunInfo);
Task<IEnumerable<LoadTestRunInfo>> UpdateRangeAsync(IEnumerable<LoadTestRunInfo> loadTestRunInfos);
Task DeleteAsync(int id);
Task DeleteRangeAsync(List<int> ids);
}
@@ -0,0 +1,20 @@
using LCU.Library.Internal.LoanRateModels.Enums;
namespace LCU.API.Internal.LoanRate.Services;
public interface IRateEvaluationService
{
Task<IEnumerable<RateEvaluation>> GetAsync();
Task<RateEvaluation?> GetByIdAsync(int id);
Task<IEnumerable<RateEvaluation>> GetRangeByIdAsync(List<int> ids);
Task<IEnumerable<RateEvaluation>> GetRangeByEvaluationDetailIdAsync(int evaluationDetailId);
Task<IEnumerable<RateEvaluation>> GetByRateSheetIdsAsync(List<int> rateSheetIds);
Task<RateEvaluation> SaveAsync(RateEvaluation rateEvaluation);
Task SaveRangeAsync(IEnumerable<RateEvaluation> rateEvaluations);
Task<RateEvaluation> UpdateAsync(RateEvaluation rateEvaluation);
Task<IEnumerable<RateEvaluation>> UpdateRangeAsync(IEnumerable<RateEvaluation> rateEvaluations);
Task DeleteAsync(int id);
Task DeleteRangeAsync(List<int> ids);
Task DeleteRangeByEvaluationDetailIdAsync(int evaluationDetailId);
Task<int> CountByEvaluationDetailIdAsync(int evaluationDetailId);
}
@@ -0,0 +1,16 @@
using LCU.Library.Internal.LoanRateModels.Entities.LoadTestingEntities;
namespace LCU.API.Internal.LoanRate.Services;
public interface IRateProcessingInfoService
{
Task<IEnumerable<RateProcessingInfo>> GetAsync();
Task<RateProcessingInfo?> GetByIdAsync(int id);
Task<IEnumerable<RateProcessingInfo>> GetRangeByIdAsync(List<int> ids);
Task<IEnumerable<RateProcessingInfo>?> GetByLoadTestRunInfoId(int loadTestRunInfoId);
Task<RateProcessingInfo> SaveAsync(RateProcessingInfo rateProcessingInfo);
Task SaveRangeAsync(IEnumerable<RateProcessingInfo> rateProcessingInfos);
Task<RateProcessingInfo> UpdateAsync(RateProcessingInfo rateProcessingInfo);
Task<IEnumerable<RateProcessingInfo>> UpdateRangeAsync(IEnumerable<RateProcessingInfo> rateProcessingInfos);
Task DeleteAsync(int id);
Task DeleteRangeAsync(List<int> ids);
}
@@ -0,0 +1,23 @@
using LCU.Library.Internal.LcuEvaluationModels.Enums;
namespace LCU.API.Internal.LoanRate.Services;
public interface IRateService
{
Task<IEnumerable<Rate>> GetAsync();
Task<Rate?> GetByIdAsync(int id);
Task<IEnumerable<Rate>?> GetByClosingRateUploadInfoIdAsync(int id);
Task<IEnumerable<Rate>?> GetByDateAsync(DateTime date);
Task<IEnumerable<Rate>?> GetRateHistory(Rate rate);
Task<IEnumerable<Rate>> GetRangeByIdAsync(List<int> ids);
Task<IEnumerable<Rate>?> GetByDateEvaluationIdAndEvaluationTypeAsync(DateTime date,
List<int> evaluationIds,
EvaluationTypes evaluationType);
Task<Dictionary<DateTime, List<Rate>>?> GetByLoadTestRunInfoId(int loadTestRunInfoId);
Task<Rate> SaveAsync(Rate rate);
Task SaveRangeAsync(IEnumerable<Rate> rates);
Task<Rate> UpdateAsync(Rate rate);
Task<IEnumerable<Rate>> UpdateRangeAsync(IEnumerable<Rate> rates);
Task DeleteAsync(int id);
Task DeleteRangeAsync(List<int> ids);
void ClearCache();
}
@@ -0,0 +1,6 @@
using LCU.Library.Internal.LcuClassPatterns.Crud.Services;
namespace LCU.API.Internal.LoanRate.Services;
public interface IRateSheetCellService : ICrudService<RateSheetCell>
{
}
@@ -0,0 +1,15 @@
using LCU.Library.Internal.LcuClassPatterns.Crud.Services;
using LCU.Library.Internal.LoanRateModels.Enums;
using LCU.Library.Internal.LoanRateModels.Responses;
namespace LCU.API.Internal.LoanRate.Services;
public interface IRateSheetService : ICrudService<RateSheet>
{
Task<IEnumerable<RateSheet>?> GetIncludeAllAsync();
Task<IEnumerable<RateSheet>?> GetIncludeRateSheetCellsAsync();
Task<IEnumerable<Rate>?> GetRatesByDateAndRateTypeAsync(DateTime date, RateTypes rateType);
Task<RateSheet?> GetByDateAndRateTypeAsync(DateTime date, RateTypes rateType);
Task<IEnumerable<Rate>?> GetRatesByRateTypeAsync(RateTypes rateType);
Task<IEnumerable<int>?> GetRateSheetIdsByRateTypeAsync(RateTypes rateType);
void ClearCache();
}
@@ -0,0 +1,14 @@
using LCU.Library.Internal.LcuClassPatterns.Crud.Services;
using LCU.Library.Internal.LoanRateModels.Requests;
using LCU.Library.Internal.LoanRateModels.Responses;
namespace LCU.API.Internal.LoanRate.Services;
public interface IRateUploadInfoService : ICrudService<RateUploadInfo>
{
Task<RateUploadInfo?> GetLatestAsync();
Task<RateUploadInfo?> GetByVersionAsync(int version, DateTime effectiveDate);
Task<RateUploadInfo?> GetLatestVersionOnDate(DateTime effectiveDate);
Task<RateUploadInfoFilterResult> GetFilteredRateUploadInfo(RateUploadInfoFilter rateUploadInfoFilter);
Task ComplexDelete(int id);
Task<RateUploadInfo> ComplexSave(RateUploadInfoRequest request);
}
@@ -0,0 +1,7 @@
using LCU.Library.Internal.StatusModels.Models;
namespace LCU.API.Internal.LoanRate.Services;
public interface IStatusService
{
EnvironmentView GetEnviromentView();
}
@@ -0,0 +1,260 @@
using Microsoft.Data.SqlClient;
using LCU.Library.Internal.LoanRateModels.Entities.LoadTestingEntities;
using LCU.API.Internal.LoanRateLoadTestingLib.Repositories;
using LCU.Library.Internal.LCUFilterModels.Pagination;
namespace LCU.API.Internal.LoanRate.Services;
public class LoadTestRunInfoService : ILoadTestRunInfoService
{
private readonly IUnitOfWork _unitOfWork;
private readonly ILoadTestRunInfoRepository _loadTestRunInfoRepository;
public LoadTestRunInfoService(IUnitOfWork unitOfWork, ILoadTestRunInfoRepository loadTestRunInfoRepository)
{
_unitOfWork = unitOfWork;
_loadTestRunInfoRepository = loadTestRunInfoRepository;
}
public async Task<IEnumerable<LoadTestRunInfo>> GetAsync()
{
try
{
return await _loadTestRunInfoRepository.FindAsync() ?? new List<LoadTestRunInfo>();
}
catch (Exception exception)
{
var message = "Failure retrieving LoadTestRunInfos.";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task<LoadTestRunInfo?> GetByIdAsync(int id)
{
try
{
return await _loadTestRunInfoRepository.FindByIdAsync(id);
}
catch (Exception exception)
{
var message = $"Failure retrieving LoadTestRunInfo with id: {id}.";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task<IEnumerable<LoadTestRunInfo>> GetRangeByIdAsync(List<int> ids)
{
try
{
return await _loadTestRunInfoRepository.FindRangeByIdAsync(ids) ?? new List<LoadTestRunInfo>();
}
catch (Exception exception)
{
var message = "Failure retrieving LoadTestRunInfos. " +
$"Ids: ({string.Join(",", ids.Select(n => n.ToString()).ToArray())}).";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task<PagedResult<LoadTestRunInfo>> GetFilteredLoadTestRunInfo(LoadTestRunInfoFilter loadTestRunInfoFilter)
{
try
{
return await _loadTestRunInfoRepository.FindFilteredLoadTestRunInfosAsync(loadTestRunInfoFilter);
}
catch (Exception exception)
{
var message = "Failure retrieving filtered LoadTestRunInfos.";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task<LoadTestRunInfo> SaveAsync(LoadTestRunInfo loadTestRunInfo)
{
try
{
var result = await _loadTestRunInfoRepository.AddAsync(loadTestRunInfo);
if (result is null)
{
throw new Exception("Saving a LoadTestRunInfo returned null.");
}
await _unitOfWork.CompleteAsync();
return result;
}
catch (Exception exception)
{
var message = "Failure saving LoadTestRunInfo.";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task SaveRangeAsync(IEnumerable<LoadTestRunInfo> loadTestRunInfos)
{
try
{
await _loadTestRunInfoRepository.AddRangeAsync(loadTestRunInfos);
await _unitOfWork.CompleteAsync();
}
catch (Exception exception)
{
var message = "Failure saving list of LoadTestRunInfos.";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task<LoadTestRunInfo> IncreaseRateProcessingInfosCompleteCountAsync(int loadTestRunInfoId, int countCompleted)
{
try
{
var existing = await GetByIdAsync(loadTestRunInfoId);
if (existing is null)
{
Log.Error($"LoadTestRunInfo with id:{loadTestRunInfoId} was not found.");
return null;
}
existing.RateProcessingInfosCompleteCount = existing.RateProcessingInfosCompleteCount + countCompleted;
if (existing.RateProcessingInfosCount == existing.RateProcessingInfosCompleteCount)
{
existing.EndTimeStamp = DateTime.Now;
}
await _unitOfWork.CompleteAsync();
return existing;
}
catch (SqlException sqlException)
{
var message = $"SQL Failure LoadTestRunInfo Increasing Rate Processing Infos Complete Count. LoadTestRunInfoId: {loadTestRunInfoId}";
Log.Error(sqlException, message);
throw new ServiceException(message);
}
catch (Exception exception)
{
var message = $"Failure LoadTestRunInfo Increasing Rate Processing Infos Complete Count. LoadTestRunInfoId: {loadTestRunInfoId}";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task<LoadTestRunInfo> UpdateAsync(LoadTestRunInfo loadTestRunInfo)
{
try
{
var existing = await GetByIdAsync(loadTestRunInfo.LoadTestRunInfoId);
if (existing is null)
{
Log.Error($"LoadTestRunInfo with id:{loadTestRunInfo.LoadTestRunInfoId} was not found.");
return null;
}
existing.StartTimeStamp = loadTestRunInfo.StartTimeStamp;
existing.EndTimeStamp = loadTestRunInfo.EndTimeStamp;
existing.RateType = loadTestRunInfo.RateType;
existing.RateProcessingInfosCount = loadTestRunInfo.RateProcessingInfosCount;
existing.RateProcessingInfosCompleteCount = loadTestRunInfo.RateProcessingInfosCompleteCount;
await _unitOfWork.CompleteAsync();
return existing;
}
catch (SqlException sqlException)
{
var message = $"SQL Failure updating LoadTestRunInfo. LoadTestRunInfoId: {loadTestRunInfo.LoadTestRunInfoId}";
Log.Error(sqlException, message);
throw new ServiceException(message);
}
catch (Exception exception)
{
var message = $"Failure updating LoadTestRunInfo. LoadTestRunInfoId: {loadTestRunInfo.LoadTestRunInfoId}";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task<IEnumerable<LoadTestRunInfo>> UpdateRangeAsync(IEnumerable<LoadTestRunInfo> loadTestRunInfos)
{
try
{
var records = loadTestRunInfos.ToList();
_loadTestRunInfoRepository.UpdateRange(records);
await _unitOfWork.CompleteAsync();
return records;
}
catch (SqlException sqlException)
{
var message = "SQL Failure updating list of LoadTestRunInfos.";
Log.Error(sqlException, message);
throw new ServiceException(message);
}
catch (Exception exception)
{
var message = "Failure updating list of LoadTestRunInfos.";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task DeleteAsync(int id)
{
try
{
var loadTestRunInfo = await GetByIdAsync(id);
ArgumentNullException.ThrowIfNull(loadTestRunInfo);
_loadTestRunInfoRepository.Remove(loadTestRunInfo);
await _unitOfWork.CompleteAsync();
}
catch (SqlException sqlException)
{
var message = $"SQL failure removing LoadTestRunInfo. LoadTestRunInfoId: {id}";
Log.Error(sqlException, message);
throw new ServiceException(message);
}
catch (Exception exception)
{
var message = $"Failure removing LoadTestRunInfo. LoadTestRunInfoId: {id}";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task DeleteRangeAsync(List<int> ids)
{
try
{
var loadTestRunInfos = await GetRangeByIdAsync(ids);
if (loadTestRunInfos is null || !loadTestRunInfos.Any())
{
throw new Exception("GetRangeByIdAsync returned no LoadTestRunInfos to remove.");
}
_loadTestRunInfoRepository.RemoveRange(loadTestRunInfos);
await _unitOfWork.CompleteAsync();
}
catch (SqlException sqlException)
{
var message = "SQL failure removing list of LoadTestRunInfos. " +
$"LoadTestRunInfoIds: ({string.Join(",", ids.Select(n => n.ToString()).ToArray())})";
Log.Error(sqlException, message);
throw new ServiceException(message);
}
catch (Exception exception)
{
var message = "Failure removing list of LoadTestRunInfos. " +
$"LoadTestRunInfoIds: ({string.Join(",", ids.Select(n => n.ToString()).ToArray())})";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
}
@@ -0,0 +1,7 @@
using LCU.Library.Internal.LoanRateModels.Requests.LoadTestRequest;
namespace LCU.API.Internal.LoanRate.Services.LoadTestingServices;
public interface ILoadTestInitiationService
{
Task HandleLoadTestInitiation(LoadTestInitiateRequest request);
}
@@ -0,0 +1,7 @@
using LCU.Library.Internal.LoanRateModels.Requests.LoadTestRequest;
namespace LCU.API.Internal.LoanRate.Services.LoadTestingServices;
public interface ILoadTestProcessRateService
{
Task HandleLoadTestProcessRate(LoadTestProcessRateRequest request);
}
@@ -0,0 +1,7 @@
using LCU.Library.Internal.LoanRateModels.Requests.LoadTestRequest;
namespace LCU.API.Internal.LoanRate.Services.LoadTestingServices;
public interface ILoadTestRateCompletionService
{
Task HandleLoadTestRateCompletion(List<LoadTestRateCompletionRequest> requests);
}
@@ -0,0 +1,180 @@
using Newtonsoft.Json;
using LCU.Library.Internal.LoanRateModels.Requests.LoadTestRequest;
using LCU.Library.Internal.LoanRateModels.Requests;
using LCU.API.Internal.LoanRate.Services.QueueServices;
using LCU.Library.Internal.LoanRateModels.Entities.LoadTestingEntities;
using LCU.Library.Internal.LoanRateModels.Enums;
using LCU.Library.Internal.LoanRateModels.Enums.LoadTestingEnums;
namespace LCU.API.Internal.LoanRate.Services.LoadTestingServices;
public class LoadTestInitiationService : ILoadTestInitiationService
{
private readonly ILoadTestRunInfoService _loadTestRunInfoService;
private readonly IRateProcessingInfoService _rateProcessingInfoService;
private readonly IQueueLoadTestProcessRateService _queueLoadTestProcessRateService;
public LoadTestInitiationService(ILoadTestRunInfoService loadTestRunInfoService,
IRateProcessingInfoService rateProcessingInfoService,
IQueueLoadTestProcessRateService queueLoadTestProcessRateService)
{
_loadTestRunInfoService = loadTestRunInfoService;
_rateProcessingInfoService = rateProcessingInfoService;
_queueLoadTestProcessRateService = queueLoadTestProcessRateService;
}
public async Task HandleLoadTestInitiation(LoadTestInitiateRequest request)
{
try
{
var combinations = GenerateModelCombinations<RateRequest>(request.PropertyList);
var loadTestRunInfo = new LoadTestRunInfo
{
StartTimeStamp = DateTime.Now,
RateType = (RateTypes)request.RateType,
RateProcessingInfosCount = combinations.Count
};
combinations = SetRateType(request.RateType, combinations);
loadTestRunInfo = await _loadTestRunInfoService.SaveAsync(loadTestRunInfo);
var rateProcessingInfos = await CreateAndSaveCombinationsRateProcessingInfos(combinations, loadTestRunInfo.LoadTestRunInfoId);
await CreateLoadTestProcessRateRequestAndQueue(rateProcessingInfos);
}
catch (Exception exception)
{
var message = $"Failure during Handle Load Test initiation. Exception Message: {exception.Message}";
Log.Error(message);
throw new ServiceException(message);
}
}
private async Task<List<RateProcessingInfo>> CreateAndSaveCombinationsRateProcessingInfos<TCombination>(List<TCombination> combinations, int loadTestRunInfoId)
{
var rateProcessingInfos = new List<RateProcessingInfo>();
foreach (var combination in combinations)
{
var rateProcessingInfo = new RateProcessingInfo
{
LoadTestRunInfoId = loadTestRunInfoId,
Payload = JsonConvert.SerializeObject(combination),
RateProcessingStatusType = RateProcessingStatusTypes.Processing
};
rateProcessingInfos.Add(rateProcessingInfo);
}
await _rateProcessingInfoService.SaveRangeAsync(rateProcessingInfos);
var newRateProcessingInfos = await _rateProcessingInfoService.GetByLoadTestRunInfoId(loadTestRunInfoId);
return newRateProcessingInfos.ToList();
}
private async Task CreateLoadTestProcessRateRequestAndQueue(List<RateProcessingInfo> rateProcessingInfos)
{
var tasks = new List<Task>();
foreach (var rateProcessingInfo in rateProcessingInfos)
{
var loadTestProcessRateRequest = new LoadTestProcessRateRequest
{
RateProcessingInfo = rateProcessingInfo
};
tasks.Add(_queueLoadTestProcessRateService.QueueLoadTestProcessRateRequest(loadTestProcessRateRequest));
}
await Task.WhenAll(tasks);
}
private static List<RateRequest> SetRateType(RateTypes? rateType, List<RateRequest> combinations)
{
foreach (var combination in combinations)
{
combination.RateType = (RateTypes)rateType;
}
return combinations;
}
private List<TModel> GenerateModelCombinations<TModel>(Dictionary<string, List<string>> propertyLists)
{
var combinations = new List<TModel>();
GenerateModelCombinationsHelper(propertyLists, combinations, Activator.CreateInstance<TModel>(), propertyLists.Keys.ToArray(), 0);
return combinations;
}
private void GenerateModelCombinationsHelper<TModel>(IReadOnlyDictionary<string, List<string>> propertyLists,
ICollection<TModel> combinations,
TModel currentModel,
IReadOnlyList<string> propertyNames,
int currentIndex)
{
if (currentIndex == propertyNames.Count)
{
combinations.Add(CreateNewInstanceOfModel(currentModel));
return;
}
var propertyName = propertyNames[currentIndex];
foreach (var item in propertyLists[propertyName])
{
currentModel = SetModelValueByPropertyName(currentModel, item, propertyName);
GenerateModelCombinationsHelper(propertyLists, combinations, currentModel, propertyNames, currentIndex + 1);
}
}
private TModel CreateNewInstanceOfModel<TModel>(TModel originalObject)
{
var newInstance = Activator.CreateInstance<TModel>();
var properties = typeof(TModel).GetProperties();
foreach (var property in properties)
{
var value = property.GetValue(originalObject);
property.SetValue(newInstance, value);
}
return newInstance;
}
private TModel SetModelValueByPropertyName<TModel>(TModel currentModel, string item, string propertyName)
{
var targetTypes = GetObjectsPropertyTypes(currentModel);
foreach (var type in targetTypes)
{
if (currentModel.GetType().GetProperty(propertyName)?.PropertyType.FullName == type.FullName)
{
var finalItem = ConvertPropertyStringValueToType(item, type);
currentModel.GetType().GetProperty(propertyName)?.SetValue(currentModel, finalItem);
return currentModel;
}
}
return currentModel;
}
private static object ConvertPropertyStringValueToType(string value, Type type)
{
if (type.IsEnum)
{
return Enum.Parse(type, value);
}
return Convert.ChangeType(value, type);
}
static List<Type> GetObjectsPropertyTypes(object obj)
{
var objectType = obj.GetType();
var propertyTypes = new List<Type>();
var properties = objectType.GetProperties();
foreach (var propertyInfo in properties)
{
if (!propertyTypes.Contains(propertyInfo.PropertyType))
{
propertyTypes.Add(propertyInfo.PropertyType);
}
}
return propertyTypes;
}
}
@@ -0,0 +1,78 @@
using Newtonsoft.Json;
using LCU.Library.Internal.LoanRateModels.Requests;
using LCU.Library.Internal.LoanRateModels.Entities.LoadTestingEntities;
using LCU.Library.Internal.LoanRateModels.Requests.LoadTestRequest;
using LCU.API.Internal.LoanRate.Services.QueueServices;
using LCU.API.Internal.LoanRate.Services.LoanRateOperationServices;
using LCU.Library.Internal.LoanRateModels.Enums.LoadTestingEnums;
namespace LCU.API.Internal.LoanRate.Services.LoadTestingServices;
public class LoadTestProcessRateService : ILoadTestProcessRateService
{
private readonly IRateFinderService _rateFinderService;
private readonly IQueueLoadTestRateCompletionService _queueLoadTestRateCompletionService;
public LoadTestProcessRateService(IRateFinderService rateFinderService,
IQueueLoadTestRateCompletionService queueLoadTestRateCompletionService)
{
_rateFinderService = rateFinderService;
_queueLoadTestRateCompletionService = queueLoadTestRateCompletionService;
}
public async Task HandleLoadTestProcessRate(LoadTestProcessRateRequest request)
{
try
{
var rateRequest = JsonConvert.DeserializeObject<RateRequest>(request.RateProcessingInfo.Payload);
var rateProcessingInfo = await FindRateDetails(request.RateProcessingInfo, rateRequest);
rateProcessingInfo.Rate = rateProcessingInfo.Rate > 0 ? rateProcessingInfo.Rate : (decimal)99.0;
var loadTestRateCompletionRequest = new LoadTestRateCompletionRequest
{
RateProcessingInfo = rateProcessingInfo
};
await _queueLoadTestRateCompletionService.QueueLoadTestRateCompletionRequest(loadTestRateCompletionRequest);
}
catch (Exception exception)
{
var message = $"Failure during Handle Load Test Process Rate. Exception Message: {exception.Message}";
Log.Error(message);
throw new ServiceException(message);
}
}
private async Task<RateProcessingInfo> FindRateDetails<TRateRequest>(RateProcessingInfo rateProcessingInfo,
TRateRequest rateRequest)
where TRateRequest : RateRequest
{
try
{
var passedRules = await _rateFinderService.DeterminePassedRules(rateRequest);
var rateResponse = await _rateFinderService.DetermineRate(rateRequest.ApplicationDate, passedRules);
if (rateResponse.rate is null)
{
throw new ServiceException(rateResponse.message);
}
var rateValue = await _rateFinderService.CalculateFinalRateValue(rateRequest, rateResponse.rate);
rateProcessingInfo.Column = rateResponse.rate.Column;
rateProcessingInfo.Row = rateResponse.rate.Row;
rateProcessingInfo.Rate = rateValue;
rateProcessingInfo.RateProcessingResultType = RateProcessingResultTypes.RateFound;
}
catch (Exception exception)
{
rateProcessingInfo.ProcessingMessage = exception.Message;
rateProcessingInfo.RateProcessingResultType = RateProcessingResultTypes.RateFailure;
}
finally
{
rateProcessingInfo.RateProcessingStatusType = RateProcessingStatusTypes.Complete;
}
return rateProcessingInfo;
}
}
@@ -0,0 +1,39 @@
using LCU.Library.Internal.LoanRateModels.Requests.LoadTestRequest;
namespace LCU.API.Internal.LoanRate.Services.LoadTestingServices;
public class LoadTestRateCompletionService : ILoadTestRateCompletionService
{
private readonly IRateProcessingInfoService _rateProcessingInfoService;
private readonly ILoadTestRunInfoService _loadTestRunInfoService;
public LoadTestRateCompletionService(IRateProcessingInfoService rateProcessingInfoService, ILoadTestRunInfoService loadTestRunInfoService)
{
_rateProcessingInfoService = rateProcessingInfoService;
_loadTestRunInfoService = loadTestRunInfoService;
}
public async Task HandleLoadTestRateCompletion(List<LoadTestRateCompletionRequest> requests)
{
try
{
var rateProcessingInfos = requests.Select(request => request.RateProcessingInfo).ToList();
await _rateProcessingInfoService.UpdateRangeAsync(rateProcessingInfos);
var loadTestRunInfoGroups = rateProcessingInfos.GroupBy(
p => p.LoadTestRunInfoId,
p => p.RateProcessingInfoId,
(key, g) => new { LoadTestRunInfoId = key, RateProcessingInfoIds = g.ToList() });
foreach(var loadTestRunInfoGroup in loadTestRunInfoGroups)
{
await _loadTestRunInfoService.IncreaseRateProcessingInfosCompleteCountAsync(loadTestRunInfoGroup.LoadTestRunInfoId,
loadTestRunInfoGroup.RateProcessingInfoIds.Count);
}
}
catch (Exception exception)
{
var message = $"Failure during Handle Load Test Rate Completion. Exception Message: {exception.Message}";
Log.Error(message);
throw new ServiceException(message);
}
}
}
@@ -0,0 +1,14 @@
using LCU.Library.Internal.LcuEvaluationModels.Entities;
using LCU.Library.Internal.LoanRateModels.Requests;
using LCU.Library.Internal.LoanRateModels.Responses;
namespace LCU.API.Internal.LoanRate.Services.LoanRateOperationServices;
public interface IRateFinderService
{
Task<RateResponse> FindRate<TRequest>(TRequest request) where TRequest : RateRequest;
Task<Rate?> FindRateObject<TRequest>(TRequest request) where TRequest : RateRequest;
Task<List<EvaluationDetail>> DeterminePassedRules<TRequest>(TRequest request) where TRequest : RateRequest;
Task<(Rate rate, string message)> DetermineRate(DateTime applicationDate, List<EvaluationDetail> passedRules);
Task<decimal> CalculateFinalRateValue<TRequest>(TRequest request, Rate rate) where TRequest : RateRequest;
}
@@ -0,0 +1,7 @@
using LCU.Library.Internal.LoanRateModels.Requests;
namespace LCU.API.Internal.LoanRate.Services.LoanRateOperationServices;
public interface IRateSheetCellUploaderService
{
public Task<List<RateSheet>> UploadRateSheetCellsAsync(RateSheetCellUploadRequest request);
}
@@ -0,0 +1,12 @@
using LCU.Library.Internal.LoanRateModels.Requests;
using LCU.Api.Internal.FileOperationsLib.Models.ExcelModels.Requests;
using LCU.Library.Internal.LoanRateModels.Responses;
namespace LCU.API.Internal.LoanRate.Services.LoanRateOperationServices;
public interface IRateUploaderService
{
Task UploadRates(RateUploadRequest request);
Task UploadRates(RateUploadExcelDataRequest request);
Task<IEnumerable<InitiateRatesEvaluationsResponse>> InitiateRatesEvaluations(IEnumerable<InitiateRatesEvaluationsRequest> requests);
}
@@ -0,0 +1,7 @@
using LCU.Library.Internal.LoanRateModels.Responses.Validation.RateSheetValidations;
namespace LCU.API.Internal.LoanRate.Services.LoanRateOperationServices;
public interface IRateValidationService
{
Task<List<RateSheetValidationResult>> ValidateAsync(List<Rate> rates);
}
@@ -0,0 +1,129 @@
using LCU.Library.Internal.LcuEvaluationModels.Enums;
using LCU.Library.Internal.LcuEvaluationModels.Requests;
using LCU.Library.Internal.LcuEvaluation.Services;
using LCU.Library.Internal.LcuEvaluation.Services.EvaluationServices;
using LCU.Library.Internal.LcuEvaluationModels.Entities;
using LCU.Library.Internal.LoanRateModels.Requests;
using LCU.Library.Internal.LoanRateModels.Responses;
namespace LCU.API.Internal.LoanRate.Services.LoanRateOperationServices;
public class RateFinderService : IRateFinderService
{
private readonly IEvaluationDetailService _evaluationDetailService;
private readonly IRateService _rateService;
private readonly IRateSheetService _rateSheetService;
private readonly IRateEvaluationService _rateEvaluationService;
private readonly IRunRuleService _runRuleService;
private readonly IRunCalculationService _runCalculationService;
public RateFinderService(IEvaluationDetailService evaluationDetailService,
IRateService rateService,
IRateSheetService rateSheetService,
IRateEvaluationService rateEvaluationService,
IRunRuleService runRuleService,
IRunCalculationService runCalculationService)
{
_evaluationDetailService = evaluationDetailService;
_rateService = rateService;
_rateSheetService = rateSheetService;
_rateEvaluationService = rateEvaluationService;
_runRuleService = runRuleService;
_runCalculationService = runCalculationService;
}
public async Task<RateResponse> FindRate<TRequest>(TRequest request) where TRequest : RateRequest
{
try
{
var passedRules = await DeterminePassedRules(request);
var rate = await DetermineRate(request.ApplicationDate, passedRules);
return rate.rate is not null
? new RateResponse { Rate = await CalculateFinalRateValue(request, rate.rate) }
: new RateResponse().SetDefault().AddErrorMessage(rate.message);
}
catch (Exception exception)
{
var message = $"Failure during FindRate. ExceptionMessage: {exception.Message}";
Log.Error(message, exception);
throw new ServiceException(message);
}
}
public async Task<Rate?> FindRateObject<TRequest>(TRequest request) where TRequest : RateRequest
{
try
{
var passedRules = await DeterminePassedRules(request);
return (await DetermineRate(request.ApplicationDate, passedRules)).rate;
}
catch (Exception exception)
{
var message = $"Failure during FindRateObject. ExceptionMessage: {exception.Message}";
Log.Error(message, exception);
throw new ServiceException(message);
}
}
public async Task<List<EvaluationDetail>> DeterminePassedRules<TRequest>(TRequest request) where TRequest : RateRequest
{
var rateSheetIds = (await _rateSheetService.GetRateSheetIdsByRateTypeAsync(request.RateType))?.ToList();
if (rateSheetIds is null || rateSheetIds.Count == 0)
{
throw new ServiceException("No RateSheets were found to help determine rates.");
}
var rateEvaluations = await _rateEvaluationService.GetByRateSheetIdsAsync(rateSheetIds);
var ratesEvaluationDetailIds = rateEvaluations.GroupBy(rateEvaluation => rateEvaluation.EvaluationDetailId)
.Select(group => group.First().EvaluationDetailId)
.ToList();
var rules = (await _evaluationDetailService.GetActiveByEvaluationTypeAndIdsAsync(request.ApplicationDate,
EvaluationTypes.Rule,
ratesEvaluationDetailIds))?.ToList();
if (rules is null || rules.Count == 0)
{
throw new ServiceException("There were no Evaluations to help determine rates.");
}
var passedRules = _runRuleService.ValidateRequestRules(request, rules.ToList());
return passedRules;
}
public async Task<(Rate? rate, string message)> DetermineRate(DateTime applicationDate, List<EvaluationDetail> passedRules)
{
var evaluationIds = passedRules.Select(passedRule => passedRule.EvaluationDetailId).ToList();
var matchingRates = (await _rateService.GetByDateEvaluationIdAndEvaluationTypeAsync(applicationDate, evaluationIds, EvaluationTypes.Rule))?.ToList();
if (matchingRates?.FirstOrDefault() == null)
{
return ( null, "There were no Rates that matched the evaluations that have passed.");
}
if (matchingRates.Count > 1)
{
return ( null, "There were more then one Rate that matched the evaluations that passed. " +
"This should not happen and the evaluations to rates needs to be confirmed.");
}
return ( matchingRates.FirstOrDefault(), string.Empty );
}
public async Task<decimal> CalculateFinalRateValue<TRequest>(TRequest request, Rate rate) where TRequest : RateRequest
{
var possibleCalculationIds = rate.RateEvaluations.Select(rateEvaluation => rateEvaluation.EvaluationDetailId).ToList();
var calculations = await _evaluationDetailService.GetActiveByEvaluationTypeAndIdsAsync(request.ApplicationDate, EvaluationTypes.Calculation, possibleCalculationIds);
foreach (var calculation in calculations)
{
var calculationRequest = new RateCalculationRequest
{
CurrentRate = rate.Value
};
var requests = new List<EvaluationRequest> { request, calculationRequest };
var calculatedRate = _runCalculationService.CalculateEvaluationWithSetOfRequests(requests, calculation);
rate.Value = calculatedRate == null ? rate.Value : (decimal)calculatedRate;
}
return rate.Value;
}
}
@@ -0,0 +1,160 @@
using LCU.Api.Internal.FileOperationsLib.Models.ExcelModels.Requests;
using LCU.Api.Internal.FileOperationsLib.Models.ExcelModels.Responses;
using LCU.API.Internal.LoanRate.Services.MicroApiServices;
using LCU.Library.Internal.LoanRateModels.Enums;
using LCU.Library.Internal.LoanRateModels.Requests;
using LCU.Library.Internal.TypeExtensions.EnumExtensions;
using LCU.Library.Internal.TypeExtensions.ObjectExtensions;
using RateSheetCell = LCU.Library.Internal.LoanRateModels.Entities.RateSheetCell;
namespace LCU.API.Internal.LoanRate.Services.LoanRateOperationServices;
public class RateSheetCellUploaderService : IRateSheetCellUploaderService
{
private readonly IRateSheetService _rateSheetService;
private readonly IFileOperationsApiService _fileOperationsApiService;
public RateSheetCellUploaderService(IRateSheetService rateSheetService, IFileOperationsApiService fileOperationsApiService)
{
_rateSheetService = rateSheetService;
_fileOperationsApiService = fileOperationsApiService;
}
public async Task<List<RateSheet>> UploadRateSheetCellsAsync(RateSheetCellUploadRequest uploadRequest)
{
try
{
var excelDataRequest = new ExcelDataRequest
{
FileContent = uploadRequest.FileContent,
SheetRequests = BuildSheetRequests(uploadRequest)
};
var excelDataResponse = await _fileOperationsApiService.DirectExtractExcelWorkBookData(excelDataRequest);
var rateSheetCells = await GetRateSheetCells(excelDataResponse, uploadRequest);
return rateSheetCells;
}
catch (Exception ex)
{
var message = $"Failure during UploadRateSheetCellsAsync. Exception Message: {ex.Message}";
Log.Error(message);
throw new ServiceException(message);
}
}
private List<SheetRequest> BuildSheetRequests(RateSheetCellUploadRequest uploadRequest)
{
var sheetRequests = new List<SheetRequest>();
foreach (var request in uploadRequest.Requests)
{
var rows = request.HeaderTopRows.DeepCopy();
rows.AddRange(request.HeaderLeftRows);
rows = rows.Distinct().ToList();
var columns = request.HeaderTopColumns.DeepCopy();
columns.AddRange(request.HeaderLeftColumns);
columns = columns.Distinct().ToList();
sheetRequests.Add(
new()
{
SheetName = request.RateType.GetNameFromValue(),
Columns = columns,
Rows = rows
}
);
}
return sheetRequests;
}
private async Task<List<RateSheet>> GetRateSheetCells(ExcelDataResponse excelDataResponse, RateSheetCellUploadRequest uploadRequest)
{
var rateSheets = (await _rateSheetService.GetIncludeRateSheetCellsAsync())?.ToList();
foreach (var sheetResponse in excelDataResponse.WorkBook.SheetResponses)
{
var request = uploadRequest.Requests.FirstOrDefault(x => x.RateType.GetNameFromValue() == sheetResponse.SheetName);
if (request == null)
{
continue;
}
var rateSheet = rateSheets?.FirstOrDefault(rateSheet => rateSheet.RateType == request.RateType);
if (rateSheet == null)
{
continue;
}
foreach (var cell in sheetResponse.CellResponses)
{
if (!(request.HeaderTopRows.Contains(cell.Row) &&
request.HeaderTopColumns.Contains(cell.ColumnName))
&& !(request.HeaderLeftRows.Contains(cell.Row) &&
request.HeaderLeftColumns.Contains(cell.ColumnName)))
{
continue;
}
var existingCell = rateSheet.RateSheetCells.FirstOrDefault(rateSheetCell => int.Parse(rateSheetCell.Row) == cell.Row
&& rateSheetCell.Column == cell.ColumnName);
RateSheetCell rateSheetCell;
if (existingCell != null)
{
rateSheetCell = existingCell;
rateSheetCell.Value = FormatValue(cell.Value);
}
else
{
rateSheetCell = new RateSheetCell
{
RateSheetId = rateSheet.RateSheetId,
RateSheetCellType = RateSheetCellTypes.TopHeader,
Column = cell.ColumnName,
ColumnSpan = GetColumnSpan(sheetResponse.CellResponses, cell),
Row = cell.Row.ToString(),
RowSpan = GetRowSpan(sheetResponse.CellResponses, cell),
Value = FormatValue(cell.Value)
};
rateSheet.RateSheetCells.Add(rateSheetCell);
}
}
}
return (await _rateSheetService.UpdateRangeAsync(rateSheets)).ToList();
}
private int GetColumnSpan(List<CellResponse> cellResponses, CellResponse cell)
{
var rowCells = cellResponses.Where(cellResponse => cellResponse.Row == cell.Row).ToList();
var one = rowCells.Where(rowCell => string.Compare(rowCell.ColumnName, cell.ColumnName, StringComparison.InvariantCulture) > 0)
.ToList()
.Min(rc => rc.ColumnName);
if (one is null || !one.Any())
{
return 1;
}
var two = cell.ColumnName.ToCharArray().First();
return one.ToCharArray().FirstOrDefault() - two;
}
private int GetRowSpan(List<CellResponse> cellResponses, CellResponse cell)
{
var columnCells = cellResponses.Where(cellResponse => cellResponse.ColumnName == cell.ColumnName).ToList();
var one = columnCells.OrderBy(x => x.Row).FirstOrDefault(rc => rc.Row > cell.Row)?.Row ?? cell.Row + 1;
var two = cell.Row;
return one - two;
}
private string FormatValue(string value)
{
value = value.Trim();
value = value.Replace("\n", "<br>");
return value;
}
}
@@ -0,0 +1,305 @@
using LCU.Library.Internal.LoanRateModels.Requests;
using LCU.Library.Internal.LcuEvaluation.Services;
using LCU.Api.Internal.FileOperationsLib.Models.ExcelModels.Requests;
using LCU.Api.Internal.FileOperationsLib.Models.ExcelModels.Responses;
using LCU.API.Internal.LoanRate.Services.MicroApiServices;
using LCU.Library.Internal.LoanRateModels.Enums;
using LCU.Library.Internal.LoanRateModels.Responses;
using LCU.Library.Internal.TypeExtensions.EnumExtensions;
namespace LCU.API.Internal.LoanRate.Services.LoanRateOperationServices;
public class RateUploaderService : IRateUploaderService
{
private readonly IRateService _rateService;
private readonly IRateSheetService _rateSheetService;
private readonly IEvaluationDetailService _evaluationDetailService;
private readonly IRateEvaluationService _rateEvaluationService;
private readonly IRateUploadInfoService _rateUploadInfoService;
private readonly IFileOperationsApiService _fileOperationsApiService;
public RateUploaderService(IRateService rateService,
IRateSheetService rateSheetService,
IEvaluationDetailService evaluationDetailService,
IRateEvaluationService rateEvaluationService,
IRateUploadInfoService rateUploadInfoService,
IFileOperationsApiService fileOperationsApiService)
{
_rateService = rateService;
_rateSheetService = rateSheetService;
_evaluationDetailService = evaluationDetailService;
_rateEvaluationService = rateEvaluationService;
_rateUploadInfoService = rateUploadInfoService;
_fileOperationsApiService = fileOperationsApiService;
}
public async Task UploadRates(RateUploadRequest request)
{
try
{
var rates = (await _rateService.GetByDateAsync(request.EffectiveDate))?.ToList();
if (rates is null || !rates.Any())
{
throw new ServiceException($"No rates were found for the EffectiveDate: ({request.EffectiveDate:MM/dd/yyyy})");
}
var previousVersion = await _rateUploadInfoService.GetLatestVersionOnDate(request.EffectiveDate);
var rateUploadInfo = BuildNewRateUploadInfo(previousVersion?.Version, request.EffectiveDate, request.FileName, request.CreatedBy);
var rateSheets = (await _rateSheetService.GetAsync()).ToList();
var excelDataRequest = BuildExcelDataRequest(request.FileContent, rates, rateSheets);
var excelDataResponse = await _fileOperationsApiService.DirectExtractExcelWorkBookData(excelDataRequest);
var countOfCellValues = 0;
foreach ( var sheet in excelDataResponse.WorkBook.SheetResponses )
{
countOfCellValues += sheet.CellResponses.Count;
}
if (rates.Count != countOfCellValues)
{
var message = $"Rate Count of {rates.Count} does not match the count of cell values returned {countOfCellValues}";
Log.Error(message);
throw new ServiceException(message);
}
await WorkThroughExcelDataResponseAndUpdateRates(excelDataResponse, rateUploadInfo, rates, rateSheets, request.EffectiveDate);
}
catch (Exception exception)
{
var message = $"Failure during UploadRates. RateExcel FileName: '{request.FileName}' Exception Message: {exception.Message}";
Log.Error(message);
throw new ServiceException(message);
}
}
public async Task UploadRates(RateUploadExcelDataRequest request)
{
try
{
var excelDataResponse = await _fileOperationsApiService.DirectExtractExcelWorkBookData(request.ExcelDataRequest);
var previousVersion = await _rateUploadInfoService.GetLatestVersionOnDate(request.EffectiveDate);
var rateUploadInfo = BuildNewRateUploadInfo(previousVersion?.Version, request.EffectiveDate, request.FileName, request.CreatedBy);
var rates = (await _rateService.GetByDateAsync(request.EffectiveDate))?.ToList();
var rateSheets = (await _rateSheetService.GetAsync()).ToList();
await WorkThroughExcelDataResponseAndUpdateRates(excelDataResponse, rateUploadInfo, rates, rateSheets, request.EffectiveDate);
}
catch (Exception exception)
{
var message = $"Failure during UploadRates. Exception Message: {exception.Message}";
Log.Error(message);
throw new ServiceException(message);
}
}
public ExcelDataRequest BuildExcelDataRequest(string rateExcelContent, List<Rate> rates, List<RateSheet> rateSheets)
{
var sheetRequests = new List<SheetRequest>();
foreach (var rate in rates)
{
var rateSheet = rateSheets.FirstOrDefault(x => x.RateSheetId == rate.RateSheetId);
if (rateSheet is null)
{
throw new ServiceException($"Rate Sheet Id {rate.RateSheetId} does not exist");
}
var sheetRequest = sheetRequests.FirstOrDefault(sheet => sheet.SheetName == rateSheet.SheetName);
if (sheetRequest == null)
{
sheetRequest = new SheetRequest();
sheetRequest.Rows = new List<int>();
sheetRequest.Columns = new List<string>();
sheetRequest.SheetName = rateSheet.SheetName;
sheetRequests.Add(sheetRequest);
}
var intRow = Convert.ToInt32(rate.Row);
if (!sheetRequest.Rows.Contains(intRow))
{
sheetRequest.Rows.Add(intRow);
}
if (!sheetRequest.Columns.Contains(rate.Column))
{
sheetRequest.Columns.Add(rate.Column);
}
}
var excelDataRequest = new ExcelDataRequest
{
FileContent = rateExcelContent,
SheetRequests = sheetRequests,
};
return excelDataRequest;
}
public async Task WorkThroughExcelDataResponseAndUpdateRates(ExcelDataResponse excelDataResponse,
RateUploadInfo rateUploadInfo,
List<Rate> rates,
List<RateSheet> rateSheets,
DateTime effectiveDate)
{
if (excelDataResponse.WorkBook?.SheetResponses is null)
{
return;
}
var ratesToCreate = new List<Rate>();
var ratesToClose = new List<Rate>();
foreach (var sheet in excelDataResponse.WorkBook.SheetResponses)
{
var rateSheet = rateSheets.FirstOrDefault(x => x.SheetName == sheet.SheetName);
if (rateSheet is null)
{
var message = $"RateSheet with SheetName: {sheet.SheetName} does not exist.";
Log.Error(message);
throw new ServiceException(message);
}
foreach (var cell in sheet.CellResponses)
{
if (!decimal.TryParse(cell.Value, out decimal newDecimalValue))
{
var message = $"Cell value was not able to be parsed into a decimal. " +
$"Column:{cell.ColumnName}, Row:{cell.Row}, Value:{cell.Value}";
Log.Error(message);
throw new ServiceException(message);
}
var rate = rates.FirstOrDefault(requestedRate => requestedRate.RateSheetId == rateSheet.RateSheetId &&
requestedRate.Row == cell.Row.ToString() &&
string.Equals(requestedRate.Column, cell.ColumnName, StringComparison.OrdinalIgnoreCase));
if (rate is null)
{
var newRate = new Rate
{
Column = cell.ColumnName,
Row = cell.Row.ToString(),
Value = newDecimalValue,
RateStartDate = effectiveDate,
RateSheetId = rateSheet.RateSheetId
};
ratesToCreate.Add(newRate);
continue;
}
var isNewValue = rate.Value != Math.Round(newDecimalValue, 2);
if (!isNewValue)
{
continue;
}
var rateToCreate = rate.DeepCopyNewRate();
rateToCreate.Value = newDecimalValue;
rateToCreate.RateStartDate = effectiveDate;
ratesToCreate.Add(rateToCreate);
if (rate.RateEndDate != null)
{
throw new ServiceException($"Previous rate, with RateId {rate.RateId}, already has an end date " +
$"of {rate.RateEndDate:MM/dd/yyyy}. This should not occur.");
}
rate.RateEndDate = effectiveDate;
ratesToClose.Add(rate);
}
}
if (ratesToCreate.Count > 0)
{
rateUploadInfo.Rates = ratesToCreate;
rateUploadInfo.RateCount = rateUploadInfo.Rates.Count;
}
if (ratesToClose.Count > 0)
{
rateUploadInfo.ClosedRates = ratesToClose;
}
if (rateUploadInfo.ClosedRates?.Count > 0 || rateUploadInfo.Rates?.Count > 0)
{
await _rateUploadInfoService.SaveAsync(rateUploadInfo);
}
}
public async Task<IEnumerable<InitiateRatesEvaluationsResponse>> InitiateRatesEvaluations(IEnumerable<InitiateRatesEvaluationsRequest> requests)
{
try
{
var newRateEvaluations = new List<RateEvaluation>();
var responses = new List<InitiateRatesEvaluationsResponse>();
foreach (var request in requests)
{
var response = new InitiateRatesEvaluationsResponse { Request = request };
var rateType = request.SheetName.GetValueFromName<RateTypes>();
var existingRates = (await _rateSheetService.GetRatesByRateTypeAsync(rateType))?.ToList();
var rule = await _evaluationDetailService.GetByIdAsync(request.EvaluationDetailId);
if (rule is null)
{
response.AddSuccessMessage($"Rule was not found with EvaluationDetailId: {request.EvaluationDetailId}");
responses.Add(response);
continue;
}
foreach (var rowsOrColumns in request.RowsOrColumns)
{
var foundRates = request.IsRowsRule ? existingRates?.Where(rate => rate.Row == rowsOrColumns).ToList()
: existingRates?.Where(rate => rate.Column == rowsOrColumns).ToList();
if (foundRates is null || !foundRates.Any())
{
response.AddFailureMessage($"Rule does not exist with EvaluationDetailId: {request.EvaluationDetailId}");
continue;
}
foreach (var foundRate in foundRates)
{
var rateRuleAlreadyExist = foundRate.RateEvaluations.FirstOrDefault(rate => rate.EvaluationDetailId == request.EvaluationDetailId) is not null;
if (rateRuleAlreadyExist)
{
response.AddSuccessMessage($"RateEvaluation already exists with EvaluationDetailId: {request.EvaluationDetailId}");
continue;
}
var newRateEvaluation = new RateEvaluation
{
EvaluationDetailId = request.EvaluationDetailId,
RateId = foundRate.RateId
};
response.RateEvaluationResults.Add(newRateEvaluation);
newRateEvaluations.Add(newRateEvaluation);
}
}
responses.Add(response);
}
await _rateEvaluationService.SaveRangeAsync(newRateEvaluations);
return responses;
}
catch (Exception exception)
{
var message = "Failure Initiating RatesEvaluations.";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
private RateUploadInfo BuildNewRateUploadInfo(int? previousVersion, DateTime effectiveDate, string fileName, string createdBy)
=> new ()
{
Version = (previousVersion ?? 0) + 1,
EffectiveDate = effectiveDate,
Filename = fileName,
TimeCreated = DateTime.Now,
CreatedBy = createdBy
};
}
@@ -0,0 +1,72 @@
using LCU.Library.Internal.LoanRateModels.Responses.Validation;
using LCU.Library.Internal.LoanRateModels.Responses.Validation.RateSheetValidations;
using Rate = LCU.Library.Internal.LoanRateModels.Entities.Rate;
namespace LCU.API.Internal.LoanRate.Services.LoanRateOperationServices;
public class RateValidationService : IRateValidationService
{
private readonly IRateService _rateService;
public RateValidationService(IRateService rateService)
{
_rateService = rateService;
}
public async Task<List<RateSheetValidationResult>> ValidateAsync(List<Rate> rates)
{
try
{
var result = new List<RateSheetValidationResult>();
foreach (var rate in rates)
{
var validation = new RateSheetValidationResult
{
NewItem = rate
};
var rateHistory = (await _rateService.GetRateHistory(rate))?.ToList();
if (rateHistory is null || rateHistory.Count == 0)
{
validation.Message = "Rate history could not be found.";
result.Add(validation);
validation.Pass = false;
continue;
}
rateHistory = rateHistory.OrderBy(x => x.RateStartDate)
.ThenBy(x => x.RateEndDate)
.ToList();
var originalRate = await _rateService.GetByIdAsync(rate.RateId);
if (originalRate is null)
{
validation.Message = "Original rate could not be found.";
result.Add(validation);
validation.Pass = false;
continue;
}
validation.OriginalItem = originalRate;
validation.Validations = new List<RateSheetValidationItem>
{
RateSheetValidation.IsWithinTrendRange(rate.Value, originalRate.Value, rateHistory.Select(x => x.Value).ToList()),
RateSheetValidation.IsWithinRange(rate.Value, rateHistory.Min(x => x.Value), rateHistory.Max(x => x.Value))
};
validation.CheckValidation();
result.Add(validation);
}
return result;
}
catch (Exception exception)
{
var message = "Failure to validate rates.";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
}
@@ -0,0 +1,28 @@
using LCU.Api.Internal.FileOperationsLib.Models.ExcelModels.Requests;
using LCU.Api.Internal.FileOperationsLib.Models.ExcelModels.Responses;
using LCU.API.Internal.LoanRate.DataAccess;
namespace LCU.API.Internal.LoanRate.Services.MicroApiServices;
public class FileOperationsApiService : IFileOperationsApiService
{
private readonly IFileOperationsApiDao _fileOperationsApiDao;
public FileOperationsApiService(IFileOperationsApiDao fileOperationsApiDao)
{
_fileOperationsApiDao = fileOperationsApiDao;
}
public async Task<ExcelDataResponse> DirectExtractExcelWorkBookData(ExcelDataRequest request)
{
try
{
return await _fileOperationsApiDao.DirectExtractExcelWorkBookData(request);
}
catch (Exception exception)
{
var error = $"Failure during DirectExtractExcelWorkBookData. Exception Message: {exception.Message}";
Log.Error(error);
throw new ServiceException(error);
}
}
}
@@ -0,0 +1,8 @@
using LCU.Api.Internal.FileOperationsLib.Models.ExcelModels.Requests;
using LCU.Api.Internal.FileOperationsLib.Models.ExcelModels.Responses;
namespace LCU.API.Internal.LoanRate.Services.MicroApiServices;
public interface IFileOperationsApiService
{
Task<ExcelDataResponse> DirectExtractExcelWorkBookData(ExcelDataRequest request);
}
@@ -0,0 +1,7 @@
using LCU.Library.Internal.LoanRateModels.Requests.LoadTestRequest;
namespace LCU.API.Internal.LoanRate.Services.QueueServices;
public interface IQueueLoadTestInitiateService
{
Task QueueLoadTestInitiateRequest(LoadTestInitiateRequest request);
}
@@ -0,0 +1,7 @@
using LCU.Library.Internal.LoanRateModels.Requests.LoadTestRequest;
namespace LCU.API.Internal.LoanRate.Services.QueueServices;
public interface IQueueLoadTestProcessRateService
{
Task QueueLoadTestProcessRateRequest(LoadTestProcessRateRequest request);
}
@@ -0,0 +1,7 @@
using LCU.Library.Internal.LoanRateModels.Requests.LoadTestRequest;
namespace LCU.API.Internal.LoanRate.Services.QueueServices;
public interface IQueueLoadTestRateCompletionService
{
Task QueueLoadTestRateCompletionRequest(LoadTestRateCompletionRequest request);
}
@@ -0,0 +1,32 @@
using MassTransit;
using LCU.Library.Internal.LoanRateModels.Requests.LoadTestRequest;
using LCU.Api.Internal.MaidBotLib.Models;
using LCU.API.Internal.LoanRate.Configurations;
namespace LCU.API.Internal.LoanRate.Services.QueueServices;
public class QueueLoadTestInitiateService : IQueueLoadTestInitiateService
{
private readonly ISendEndpoint _sendEndpoint;
public QueueLoadTestInitiateService(IBusControl busControl,
ReceiveEndpointConfigurations receiveEndpointConfigurations)
{
_sendEndpoint = busControl.GetSendEndpoint(receiveEndpointConfigurations.LoadTestInitiateReceiveEndpoint.ReceiveEndpointUri).Result;
}
public async Task QueueLoadTestInitiateRequest(LoadTestInitiateRequest request)
{
try
{
var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(30));
await _sendEndpoint.Send(request, cancellationTokenSource.Token);
}
catch (Exception exception)
{
Log.ForContext(Enum.GetName(typeof(PropertyEnum), PropertyEnum.Group),
Enum.GetName(typeof(GroupEnum), GroupEnum.ITDevelopment))
.Fatal(exception, "Failed to Queue Load Test Initiate Request.");
throw new ServiceException("Failed to Queue Load Test Initiate Request.");
}
}
}
@@ -0,0 +1,32 @@
using MassTransit;
using LCU.Library.Internal.LoanRateModels.Requests.LoadTestRequest;
using LCU.Api.Internal.MaidBotLib.Models;
using LCU.API.Internal.LoanRate.Configurations;
namespace LCU.API.Internal.LoanRate.Services.QueueServices;
public class QueueLoadTestProcessRateService : IQueueLoadTestProcessRateService
{
private readonly ISendEndpoint _sendEndpoint;
public QueueLoadTestProcessRateService(IBusControl busControl,
ReceiveEndpointConfigurations receiveEndpointConfigurations)
{
_sendEndpoint = busControl.GetSendEndpoint(receiveEndpointConfigurations.LoadTestProcessRateReceiveEndpoint.ReceiveEndpointUri).Result;
}
public async Task QueueLoadTestProcessRateRequest(LoadTestProcessRateRequest request)
{
try
{
var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(30));
await _sendEndpoint.Send(request, cancellationTokenSource.Token);
}
catch (Exception exception)
{
Log.ForContext(Enum.GetName(typeof(PropertyEnum), PropertyEnum.Group),
Enum.GetName(typeof(GroupEnum), GroupEnum.ITDevelopment))
.Fatal(exception, "Failed to Queue Load Test Process Rate Request.");
throw new ServiceException("Failed to Queue Load Test Process Rate Request.");
}
}
}
@@ -0,0 +1,32 @@
using MassTransit;
using LCU.Library.Internal.LoanRateModels.Requests.LoadTestRequest;
using LCU.Api.Internal.MaidBotLib.Models;
using LCU.API.Internal.LoanRate.Configurations;
namespace LCU.API.Internal.LoanRate.Services.QueueServices;
public class QueueLoadTestRateCompletionService : IQueueLoadTestRateCompletionService
{
private readonly ISendEndpoint _sendEndpoint;
public QueueLoadTestRateCompletionService(IBusControl busControl,
ReceiveEndpointConfigurations receiveEndpointConfigurations)
{
_sendEndpoint = busControl.GetSendEndpoint(receiveEndpointConfigurations.LoadTestRateCompletionReceiveEndpoint.ReceiveEndpointUri).Result;
}
public async Task QueueLoadTestRateCompletionRequest(LoadTestRateCompletionRequest request)
{
try
{
var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(30));
await _sendEndpoint.Send(request, cancellationTokenSource.Token);
}
catch (Exception exception)
{
Log.ForContext(Enum.GetName(typeof(PropertyEnum), PropertyEnum.Group),
Enum.GetName(typeof(GroupEnum), GroupEnum.ITDevelopment))
.Fatal(exception, "Failed to Queue Load Test Rate Completion Request.");
throw new ServiceException("Failed to Queue Load Test Rate Completion Request.");
}
}
}
@@ -0,0 +1,311 @@
using Microsoft.Data.SqlClient;
using LCU.API.Internal.LoanRateLib.Repositories;
using LCU.Library.Internal.LoanRateModels.Enums;
namespace LCU.API.Internal.LoanRate.Services;
public class RateEvaluationService : IRateEvaluationService
{
private readonly IUnitOfWork _unitOfWork;
private readonly IRateEvaluationRepository _rateEvaluationRepository;
private readonly IRateService _rateService;
public RateEvaluationService(IUnitOfWork unitOfWork,
IRateEvaluationRepository rateEvaluationRepository,
IRateService rateService)
{
_unitOfWork = unitOfWork;
_rateEvaluationRepository = rateEvaluationRepository;
_rateService = rateService;
}
public async Task<IEnumerable<RateEvaluation>> GetAsync()
{
try
{
return await _rateEvaluationRepository.FindAsync() ?? new List<RateEvaluation>();
}
catch (Exception exception)
{
var message = "Failure retrieving RateEvaluations.";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task<RateEvaluation?> GetByIdAsync(int id)
{
try
{
return await _rateEvaluationRepository.FindByIdAsync(id);
}
catch (Exception exception)
{
var message = $"Failure retrieving RateEvaluation with id: {id}.";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task<IEnumerable<RateEvaluation>> GetRangeByIdAsync(List<int> ids)
{
try
{
return await _rateEvaluationRepository.FindRangeByIdAsync(ids) ?? new List<RateEvaluation>();
}
catch (Exception exception)
{
var message = "Failure retrieving RateEvaluations. " +
$"Ids: ({string.Join(",", ids.Select(n => n.ToString()).ToArray())}).";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task<IEnumerable<RateEvaluation>> GetRangeByEvaluationDetailIdAsync(int evaluationDetailId)
{
try
{
return await _rateEvaluationRepository.FindRangeByEvaluationDetailIdAsync(evaluationDetailId) ?? new List<RateEvaluation>();
}
catch (Exception exception)
{
var message = "Failure retrieving RateEvaluations by EvaluationDetailId. " +
$"EvaluationDetailId: {evaluationDetailId}.";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task<IEnumerable<RateEvaluation>> GetByRateSheetIdsAsync(List<int> rateSheetIds)
{
try
{
return await _rateEvaluationRepository.FindByRateSheetIdsAsync(rateSheetIds) ?? new List<RateEvaluation>();
}
catch (Exception exception)
{
var message = "Failure retrieving RateEvaluations in GetByRateSheetIdsAsync. " +
$"RateSheetIds: {string.Join(", ",rateSheetIds)}.";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task<RateEvaluation> SaveAsync(RateEvaluation rateEvaluation)
{
try
{
var result = await _rateEvaluationRepository.AddAsync(rateEvaluation);
if (result is null)
{
throw new Exception("Saving a RateEvaluation returned null.");
}
await _unitOfWork.CompleteAsync();
_rateService.ClearCache();
return result;
}
catch (Exception exception)
{
var message = "Failure saving RateEvaluation.";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task SaveRangeAsync(IEnumerable<RateEvaluation> rateEvaluations)
{
try
{
await _rateEvaluationRepository.AddRangeAsync(rateEvaluations);
_rateService.ClearCache();
await _unitOfWork.CompleteAsync();
}
catch (Exception exception)
{
var message = "Failure saving list of RateEvaluations.";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task<RateEvaluation> UpdateAsync(RateEvaluation rateEvaluation)
{
try
{
var existing = await GetByIdAsync(rateEvaluation.RateEvaluationId);
if (existing is null)
{
Log.Error($"RateEvaluation with id:{rateEvaluation.RateEvaluationId} was not found.");
return null;
}
existing.RateId = rateEvaluation.RateId;
existing.EvaluationDetailId = rateEvaluation.EvaluationDetailId;
await _unitOfWork.CompleteAsync();
_rateService.ClearCache();
return existing;
}
catch (SqlException sqlException)
{
var message = $"SQL Failure updating RateEvaluation. RateEvaluationId: {rateEvaluation.RateEvaluationId}";
Log.Error(sqlException, message);
throw new ServiceException(message);
}
catch (Exception exception)
{
var message = $"Failure updating RateEvaluation. RateEvaluationId: {rateEvaluation.RateEvaluationId}";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task<IEnumerable<RateEvaluation>> UpdateRangeAsync(IEnumerable<RateEvaluation> rateEvaluations)
{
try
{
var records = rateEvaluations.ToList();
_rateEvaluationRepository.UpdateRange(records);
await _unitOfWork.CompleteAsync();
_rateService.ClearCache();
return records;
}
catch (SqlException sqlException)
{
var message = "SQL Failure updating list of RateEvaluations.";
Log.Error(sqlException, message);
throw new ServiceException(message);
}
catch (Exception exception)
{
var message = "Failure updating list of RateEvaluations.";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task DeleteAsync(int id)
{
try
{
var rateEvaluation = await GetByIdAsync(id);
ArgumentNullException.ThrowIfNull(rateEvaluation);
_rateEvaluationRepository.Remove(rateEvaluation);
await _unitOfWork.CompleteAsync();
_rateService.ClearCache();
}
catch (SqlException sqlException)
{
var message = $"SQL failure removing RateEvaluation. RateEvaluationId: {id}";
Log.Error(sqlException, message);
throw new ServiceException(message);
}
catch (Exception exception)
{
var message = $"Failure removing RateEvaluation. RateEvaluationId: {id}";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task DeleteRangeAsync(List<int> ids)
{
try
{
var rateEvaluations = await GetRangeByIdAsync(ids);
if (rateEvaluations is null || !rateEvaluations.Any())
{
throw new Exception("GetRangeByIdAsync returned no RateEvaluations to remove.");
}
_rateEvaluationRepository.RemoveRange(rateEvaluations);
await _unitOfWork.CompleteAsync();
_rateService.ClearCache();
}
catch (SqlException sqlException)
{
var message = "SQL failure removing list of RateEvaluations. " +
$"RateEvaluationIds: ({string.Join(",", ids.Select(n => n.ToString()).ToArray())})";
Log.Error(sqlException, message);
throw new ServiceException(message);
}
catch (Exception exception)
{
var message = "Failure removing list of RateEvaluations. " +
$"RateEvaluationIds: ({string.Join(",", ids.Select(n => n.ToString()).ToArray())})";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task DeleteRangeByEvaluationDetailIdAsync(int evaluationDetailId)
{
try
{
if (evaluationDetailId <= 0)
{
throw new Exception("EvaluationDetailId must be greater than 0.");
}
var rateEvaluations = (await _rateEvaluationRepository.FindRangeByEvaluationDetailIdAsync(evaluationDetailId))?.ToList();
if (rateEvaluations is null || !rateEvaluations.Any())
{
Log.Warning("No RateEvaluations were found for DeleteRangeByEvaluationDetailIdAsync");
return;
}
await DeleteRangeAsync(rateEvaluations.Select( x => x.RateEvaluationId ).ToList());
_rateService.ClearCache();
}
catch (SqlException sqlException)
{
var message = "SQL failure removing list of RateEvaluations. " +
$"EvaluationDetailId: {evaluationDetailId}";
Log.Error(sqlException, message);
throw new ServiceException(message);
}
catch (Exception exception)
{
var message = "Failure removing list of RateEvaluations. " +
$"EvaluationDetailId: {evaluationDetailId}";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task<int> CountByEvaluationDetailIdAsync(int evaluationDetailId)
{
try
{
return await _rateEvaluationRepository.CountByEvaluationDetailIdAsync(evaluationDetailId);
}
catch (SqlException sqlException)
{
var message = "SQL failure on CountByEvaluationDetailIdAsync. " +
$"EvaluationDetailId: ({evaluationDetailId})";
Log.Error(sqlException, message);
throw new ServiceException(message);
}
catch (Exception exception)
{
var message = "Failure on CountByEvaluationDetailIdAsync. " +
$"EvaluationDetailId: ({evaluationDetailId})";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
}
@@ -0,0 +1,226 @@
using Microsoft.Data.SqlClient;
using LCU.Library.Internal.LoanRateModels.Entities.LoadTestingEntities;
using LCU.API.Internal.LoanRateLoadTestingLib.Repositories;
namespace LCU.API.Internal.LoanRate.Services;
public class RateProcessingInfoService : IRateProcessingInfoService
{
private readonly IUnitOfWork _unitOfWork;
private readonly IRateProcessingInfoRepository _rateProcessingInfoRepository;
public RateProcessingInfoService(IUnitOfWork unitOfWork,
IRateProcessingInfoRepository rateProcessingInfoRepository)
{
_unitOfWork = unitOfWork;
_rateProcessingInfoRepository = rateProcessingInfoRepository;
}
public async Task<IEnumerable<RateProcessingInfo>> GetAsync()
{
try
{
return await _rateProcessingInfoRepository.FindAsync() ?? new List<RateProcessingInfo>();
}
catch (Exception exception)
{
var message = "Failure retrieving RateProcessingInfos.";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task<RateProcessingInfo?> GetByIdAsync(int id)
{
try
{
return await _rateProcessingInfoRepository.FindByIdAsync(id);
}
catch (Exception exception)
{
var message = $"Failure retrieving RateProcessingInfo with id: {id}.";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task<IEnumerable<RateProcessingInfo>> GetRangeByIdAsync(List<int> ids)
{
try
{
return await _rateProcessingInfoRepository.FindRangeByIdAsync(ids) ?? new List<RateProcessingInfo>();
}
catch (Exception exception)
{
var message = "Failure retrieving RateProcessingInfos. " +
$"Ids: ({string.Join(",", ids.Select(n => n.ToString()).ToArray())}).";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task<IEnumerable<RateProcessingInfo>?> GetByLoadTestRunInfoId(int loadTestRunInfoId)
{
try
{
return await _rateProcessingInfoRepository.FindByLoadTestRunInfoIdAsync(loadTestRunInfoId) ?? new List<RateProcessingInfo>();
}
catch (Exception exception)
{
var message = $"Failure retrieving RateProcessingInfo with loadTestRunInfoId: {loadTestRunInfoId}.";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task<RateProcessingInfo> SaveAsync(RateProcessingInfo rateProcessingInfo)
{
try
{
var result = await _rateProcessingInfoRepository.AddAsync(rateProcessingInfo);
if (result is null)
{
throw new Exception("Saving a RateProcessingInfo returned null.");
}
await _unitOfWork.CompleteAsync();
return result;
}
catch (Exception exception)
{
var message = "Failure saving RateProcessingInfo.";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task SaveRangeAsync(IEnumerable<RateProcessingInfo> rateProcessingInfos)
{
try
{
await _rateProcessingInfoRepository.AddRangeAsync(rateProcessingInfos);
await _unitOfWork.CompleteAsync();
}
catch (Exception exception)
{
var message = "Failure saving list of RateProcessingInfos.";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task<RateProcessingInfo> UpdateAsync(RateProcessingInfo rateProcessingInfo)
{
try
{
var existing = await GetByIdAsync(rateProcessingInfo.RateProcessingInfoId);
if (existing is null)
{
Log.Error($"RateProcessingInfo with id:{rateProcessingInfo.RateProcessingInfoId} was not found.");
return null;
}
existing.LoadTestRunInfoId = rateProcessingInfo.LoadTestRunInfoId;
existing.Payload = rateProcessingInfo.Payload;
existing.Rate = rateProcessingInfo.Rate;
existing.Column = rateProcessingInfo.Column;
existing.Row = rateProcessingInfo.Row;
existing.RateProcessingStatusType = rateProcessingInfo.RateProcessingStatusType;
existing.RateProcessingResultType = rateProcessingInfo.RateProcessingResultType;
existing.ProcessingMessage = rateProcessingInfo.ProcessingMessage;
await _unitOfWork.CompleteAsync();
return existing;
}
catch (SqlException sqlException)
{
var message = $"SQL Failure updating RateProcessingInfo. RateProcessingInfoId: {rateProcessingInfo.RateProcessingInfoId}";
Log.Error(sqlException, message);
throw new ServiceException(message);
}
catch (Exception exception)
{
var message = $"Failure updating RateProcessingInfo. RateProcessingInfoId: {rateProcessingInfo.RateProcessingInfoId}";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task<IEnumerable<RateProcessingInfo>> UpdateRangeAsync(IEnumerable<RateProcessingInfo> rateProcessingInfos)
{
try
{
var records = rateProcessingInfos.ToList();
_rateProcessingInfoRepository.UpdateRange(records);
await _unitOfWork.CompleteAsync();
return records;
}
catch (SqlException sqlException)
{
var message = "SQL Failure updating list of RateProcessingInfos.";
Log.Error(sqlException, message);
throw new ServiceException(message);
}
catch (Exception exception)
{
var message = "Failure updating list of RateProcessingInfos.";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task DeleteAsync(int id)
{
try
{
var rateProcessingInfo = await GetByIdAsync(id);
ArgumentNullException.ThrowIfNull(rateProcessingInfo);
_rateProcessingInfoRepository.Remove(rateProcessingInfo);
await _unitOfWork.CompleteAsync();
}
catch (SqlException sqlException)
{
var message = $"SQL failure removing RateProcessingInfo. RateProcessingInfoId: {id}";
Log.Error(sqlException, message);
throw new ServiceException(message);
}
catch (Exception exception)
{
var message = $"Failure removing RateProcessingInfo. RateProcessingInfoId: {id}";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task DeleteRangeAsync(List<int> ids)
{
try
{
var rateProcessingInfos = await GetRangeByIdAsync(ids);
if (rateProcessingInfos is null || !rateProcessingInfos.Any())
{
throw new Exception("GetRangeByIdAsync returned no RateProcessingInfos to remove.");
}
_rateProcessingInfoRepository.RemoveRange(rateProcessingInfos);
await _unitOfWork.CompleteAsync();
}
catch (SqlException sqlException)
{
var message = "SQL failure removing list of RateProcessingInfos. " +
$"RateProcessingInfoIds: ({string.Join(",", ids.Select(n => n.ToString()).ToArray())})";
Log.Error(sqlException, message);
throw new ServiceException(message);
}
catch (Exception exception)
{
var message = "Failure removing list of RateProcessingInfos. " +
$"RateProcessingInfoIds: ({string.Join(",", ids.Select(n => n.ToString()).ToArray())})";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
}
@@ -0,0 +1,335 @@
using Microsoft.Data.SqlClient;
using LCU.API.Internal.LoanRateLib.Repositories;
using LCU.Library.Internal.LcuEvaluationModels.Enums;
using LCU.Library.Internal.LoanRateModels.Requests;
using LCU.Library.Internal.TypeExtensions.EnumExtensions;
using Newtonsoft.Json;
namespace LCU.API.Internal.LoanRate.Services;
public class RateService : IRateService
{
private readonly IUnitOfWork _unitOfWork;
private readonly IRateRepository _rateRepository;
private readonly IRateSheetService _rateSheetService;
private readonly ILoadTestRunInfoService _loadTestRunInfoService;
public RateService(IUnitOfWork unitOfWork,
IRateRepository rateRepository,
IRateSheetService rateSheetService,
ILoadTestRunInfoService loadTestRunInfoService)
{
_unitOfWork = unitOfWork;
_rateRepository = rateRepository;
_rateSheetService = rateSheetService;
_loadTestRunInfoService = loadTestRunInfoService;
}
public async Task<IEnumerable<Rate>> GetAsync()
{
try
{
return await _rateRepository.FindAsync() ?? new List<Rate>();
}
catch (Exception exception)
{
var message = "Failure retrieving Rates.";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task<Rate?> GetByIdAsync(int id)
{
try
{
return await _rateRepository.FindByIdAsync(id);
}
catch (Exception exception)
{
var message = $"Failure retrieving Rate with id: {id}.";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task<IEnumerable<Rate>?> GetByDateAsync(DateTime date)
{
try
{
return await _rateRepository.FindByDateAsync(date) ?? new List<Rate>();
}
catch (Exception exception)
{
var message = "Failure retrieving Rates.";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task<IEnumerable<Rate>?> GetRateHistory(Rate rate)
{
try
{
return await _rateRepository.FindRateHistoryAsync(rate) ?? new List<Rate>();
}
catch (Exception exception)
{
var message = "Failure retrieving rate history. " +
$"Rate: {JsonConvert.SerializeObject(rate)}";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task<IEnumerable<Rate>> GetRangeByIdAsync(List<int> ids)
{
try
{
return await _rateRepository.FindRangeByIdAsync(ids) ?? new List<Rate>();
}
catch (Exception exception)
{
var message = "Failure retrieving Rates. " +
$"Ids: ({string.Join(",", ids.Select(n => n.ToString()).ToArray())}).";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task<IEnumerable<Rate>?> GetByClosingRateUploadInfoIdAsync(int id)
{
try
{
return await _rateRepository.FindByClosingRateUploadInfoIdAsync(id) ?? new List<Rate>();
}
catch (Exception exception)
{
var message = $"Failure retrieving Rates by ClosingRateUploadInfoId with id {id}.";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task<IEnumerable<Rate>?> GetByDateEvaluationIdAndEvaluationTypeAsync(DateTime date,
List<int> evaluationIds,
EvaluationTypes evaluationType)
{
try
{
return await _rateRepository.FindByDateEvaluationIdsAndEvaluationTypeAsync(date, evaluationIds, evaluationType) ?? new List<Rate>();
}
catch (Exception exception)
{
var message = "Failure retrieving Rates. " +
$"Ids: ({string.Join(",", evaluationIds.Select(n => n.ToString()).ToArray())})." +
$"EvaluationType: {evaluationType} ";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task<Dictionary<DateTime, List<Rate>>?> GetByLoadTestRunInfoId(int loadTestRunInfoId)
{
try
{
var loadTestRunInfo = await _loadTestRunInfoService.GetByIdAsync(loadTestRunInfoId);
if (loadTestRunInfo is null)
{
return new Dictionary<DateTime, List<Rate>>();
}
var rateRequests = loadTestRunInfo.RateProcessingInfos.Select(x => JsonConvert.DeserializeObject<RateRequest>(x.Payload)).ToList();
var applicationDates = rateRequests.Select(x => x.ApplicationDate).Distinct();
var response = new Dictionary<DateTime, List<Rate>>();
foreach (var date in applicationDates)
{
var rates = (await _rateSheetService.GetRatesByDateAndRateTypeAsync(date, loadTestRunInfo.RateType) ?? new List<Rate>()).ToList();
response.Add(date, rates);
}
return response;
}
catch (Exception exception)
{
var message = "Failure retrieving Rates by LoadTestRunInfoId. " +
$"LoadTestRunInfoId: ({loadTestRunInfoId}).";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task<Rate> SaveAsync(Rate rate)
{
try
{
var result = await _rateRepository.AddAsync(rate);
if (result is null)
{
throw new Exception("Saving a Rate returned null.");
}
await _unitOfWork.CompleteAsync();
ClearCache();
return result;
}
catch (Exception exception)
{
var message = "Failure saving Rate.";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task SaveRangeAsync(IEnumerable<Rate> rates)
{
try
{
await _rateRepository.AddRangeAsync(rates);
await _unitOfWork.CompleteAsync();
ClearCache();
}
catch (Exception exception)
{
var message = "Failure saving list of Rates.";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task<Rate> UpdateAsync(Rate rate)
{
try
{
var existing = await GetByIdAsync(rate.RateId);
if (existing is null)
{
Log.Error($"Rate with id:{rate.RateId} was not found.");
return null;
}
existing.RateUploadInfoId = rate.RateUploadInfoId;
existing.ClosingRateUploadInfoId = rate.ClosingRateUploadInfoId;
existing.Column = rate.Column;
existing.Row = rate.Row;
existing.RateSheetId = rate.RateSheetId;
existing.Value = rate.Value;
existing.RateStartDate = rate.RateStartDate;
existing.RateEndDate = rate.RateEndDate;
await _unitOfWork.CompleteAsync();
ClearCache();
return existing;
}
catch (SqlException sqlException)
{
var message = $"SQL Failure updating Rate. RateId: {rate.RateId}";
Log.Error(sqlException, message);
throw new ServiceException(message);
}
catch (Exception exception)
{
var message = $"Failure updating Rate. RateId: {rate.RateId}";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task<IEnumerable<Rate>> UpdateRangeAsync(IEnumerable<Rate> rates)
{
try
{
var records = rates.ToList();
_rateRepository.UpdateRange(records);
await _unitOfWork.CompleteAsync();
ClearCache();
return records;
}
catch (SqlException sqlException)
{
var message = "SQL Failure updating list of Rates.";
Log.Error(sqlException, message);
throw new ServiceException(message);
}
catch (Exception exception)
{
var message = "Failure updating list of Rates.";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task DeleteAsync(int id)
{
try
{
var rate = await GetByIdAsync(id);
ArgumentNullException.ThrowIfNull(rate);
_rateRepository.Remove(rate);
await _unitOfWork.CompleteAsync();
ClearCache();
}
catch (SqlException sqlException)
{
var message = $"SQL failure removing Rate. RateId: {id}";
Log.Error(sqlException, message);
throw new ServiceException(message);
}
catch (Exception exception)
{
var message = $"Failure removing Rate. RateId: {id}";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task DeleteRangeAsync(List<int> ids)
{
try
{
var rates = await GetRangeByIdAsync(ids);
if (rates is null || !rates.Any())
{
throw new Exception("GetRangeByIdAsync returned no Rates to remove.");
}
_rateRepository.RemoveRange(rates);
await _unitOfWork.CompleteAsync();
ClearCache();
}
catch (SqlException sqlException)
{
var message = "SQL failure removing list of Rates. " +
$"RateIds: ({string.Join(",", ids.Select(n => n.ToString()).ToArray())})";
Log.Error(sqlException, message);
throw new ServiceException(message);
}
catch (Exception exception)
{
var message = "Failure removing list of Rates. " +
$"RateIds: ({string.Join(",", ids.Select(n => n.ToString()).ToArray())})";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public void ClearCache()
{
try
{
_rateRepository.ClearCache();
}
catch (Exception exception)
{
var message = "Failure to clear cache for Rates";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
}
@@ -0,0 +1,14 @@
using LCU.API.Internal.LoanRateLib.Repositories;
using LCU.Library.Internal.LcuClassPatterns.Crud.Services;
namespace LCU.API.Internal.LoanRate.Services;
public class RateSheetCellService : CrudService<RateSheetCell>, IRateSheetCellService
{
private readonly IRateSheetCellRepository _rateSheetCellRepository;
public RateSheetCellService(IRateSheetCellRepository rateSheetCellRepository) : base(rateSheetCellRepository)
{
_rateSheetCellRepository = rateSheetCellRepository;
}
}
@@ -0,0 +1,114 @@
using LCU.API.Internal.LoanRateLib.Repositories;
using LCU.Library.Internal.LcuClassPatterns.Crud.Services;
using LCU.Library.Internal.LoanRateModels.Enums;
namespace LCU.API.Internal.LoanRate.Services;
public class RateSheetService : CrudService<RateSheet>, IRateSheetService
{
private readonly IRateSheetRepository _rateSheetRepository;
public RateSheetService(IRateSheetRepository rateSheetRepository) : base(rateSheetRepository)
{
_rateSheetRepository = rateSheetRepository;
}
public async Task<IEnumerable<RateSheet>?> GetIncludeAllAsync()
{
try
{
return await _rateSheetRepository.FindIncludeAllAsync() ?? new List<RateSheet>();
}
catch (Exception exception)
{
var message = "Failure during GetIncludeAllAsync.";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task<IEnumerable<RateSheet>?> GetIncludeRateSheetCellsAsync()
{
try
{
return await _rateSheetRepository.FindIncludeRateSheetCellsAsync() ?? new List<RateSheet>();
}
catch (Exception exception)
{
var message = "Failure during GetIncludeRateSheetCellsAsync.";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task<IEnumerable<Rate>?> GetRatesByRateTypeAsync(RateTypes rateType)
{
try
{
return await _rateSheetRepository.FindRatesByRateType(rateType) ?? new List<Rate>();
}
catch (Exception exception)
{
var message = $"Failure retrieving Rates with RateType: {rateType}.";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task<IEnumerable<int>?> GetRateSheetIdsByRateTypeAsync(RateTypes rateType)
{
try
{
return await _rateSheetRepository.FindRateSheetIdsByRateType(rateType) ?? new List<int>();
}
catch (Exception exception)
{
var message = $"Failure retrieving RateSheetIds with RateType: {rateType}.";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task<IEnumerable<Rate>?> GetRatesByDateAndRateTypeAsync(DateTime date, RateTypes rateType)
{
try
{
return await _rateSheetRepository.FindRatesByDateAndRateType(date, rateType) ?? new List<Rate>();
}
catch (Exception exception)
{
var message = $"Failure retrieving Rates with RateType ({rateType}) and Date: {date::MM-dd-yyyy HH:mm:ss}.";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task<RateSheet?> GetByDateAndRateTypeAsync(DateTime date, RateTypes rateType)
{
try
{
return await _rateSheetRepository.FindByDateAndRateType(date, rateType);
}
catch (Exception exception)
{
var message = $"Failure retrieving RateSheet with RateType ({rateType}) and Date: {date::MM-dd-yyyy HH:mm:ss}.";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public void ClearCache()
{
try
{
_rateSheetRepository.ClearCache();
}
catch (Exception exception)
{
var message = "Failure to clear cache for RateSheets";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
}
@@ -0,0 +1,166 @@
using LCU.API.Internal.LoanRateLib.Repositories;
using LCU.Library.Internal.LcuClassPatterns.Crud.Services;
using LCU.Library.Internal.LoanRateModels.Requests;
using LCU.Library.Internal.LoanRateModels.Responses;
using LCU.Library.Internal.TypeExtensions.ObjectExtensions;
using Newtonsoft.Json;
namespace LCU.API.Internal.LoanRate.Services;
public class RateUploadInfoService : CrudService<RateUploadInfo>, IRateUploadInfoService
{
private readonly IRateUploadInfoRepository _rateUploadInfoRepository;
private readonly IRateService _rateService;
public RateUploadInfoService(IRateUploadInfoRepository rateUploadInfoRepository,
IRateService rateService) : base(rateUploadInfoRepository)
{
_rateUploadInfoRepository = rateUploadInfoRepository;
_rateService = rateService;
}
public async Task<RateUploadInfo?> GetLatestAsync()
{
try
{
return await _rateUploadInfoRepository.FindLatestAsync();
}
catch (Exception exception)
{
var message = "Failure retrieving latest RateUploadInfo.";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task<RateUploadInfo?> GetByVersionAsync(int version, DateTime effectiveDate)
{
try
{
return await _rateUploadInfoRepository.FindByVersionAsync(version, effectiveDate);
}
catch (Exception exception)
{
var message = $"Failure retrieving RateUploadInfo with version ({version}) and effective date ({effectiveDate:MM/dd/yyyy}).";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task<RateUploadInfo?> GetPreviousVersion(RateUploadInfo rateUploadInfo)
{
try
{
return await _rateUploadInfoRepository.FindPreviousVersion(rateUploadInfo);
}
catch (Exception exception)
{
var message = "Failure retrieving previous RateUploadInfo. "
+ $"RateUploadInfo: {JsonConvert.SerializeObject(rateUploadInfo)}";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task<RateUploadInfo?> GetLatestVersionOnDate(DateTime date)
{
try
{
return await _rateUploadInfoRepository.FindLatestVersionOnDate(date);
}
catch (Exception exception)
{
var message = $"Failure retrieving previous RateUploadInfo on date EffectiveDate: {date:MM/dd/yyyy}";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task<RateUploadInfoFilterResult> GetFilteredRateUploadInfo(RateUploadInfoFilter rateUploadInfoFilter)
{
try
{
return await _rateUploadInfoRepository.FindFilteredRateUploadInfosAsync(rateUploadInfoFilter);
}
catch (Exception exception)
{
var message = "Failure retrieving filtered RateUploadInfos.";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task<RateUploadInfo> ComplexSave(RateUploadInfoRequest request)
{
try
{
var previousVersion = (await GetLatestVersionOnDate(request.EffectiveDate))?.Version;
var newRates = new List<Rate>();
foreach (var newRate in request.Rates.Select(rate => rate.DeepCopy()))
{
newRate.RateId = 0;
newRate.RateStartDate = request.EffectiveDate;
newRates.Add(newRate);
}
var oldRates = (await _rateService.GetRangeByIdAsync(request.Rates.Select(rate => rate.RateId).ToList())).ToList();
foreach (var rate in oldRates)
{
rate.RateEndDate = request.EffectiveDate;
}
var rateUploadInfo = new RateUploadInfo
{
Version = (previousVersion ?? 0) + 1,
Filename = request.FileName,
EffectiveDate = request.EffectiveDate,
ClosedRates = oldRates,
Rates = newRates,
RateCount = newRates.Count,
TimeCreated = DateTime.Now,
CreatedBy = request.CreatedBy
};
return await SaveAsync(rateUploadInfo);
}
catch (Exception exception)
{
var message = "Failure completing a complex save for RateUploadInfo: " +
$"EvaluationDate: {request.EffectiveDate:MM/dd/yyyy} | " +
$"Rate Count: {request.Rates.Count}";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
public async Task ComplexDelete(int id)
{
try
{
if (id != (await GetLatestAsync())?.RateUploadInfoId)
{
throw new Exception("Only the most recent RateUploadInfo can be deleted.");
}
var closedRates = (await _rateService.GetByClosingRateUploadInfoIdAsync(id))?.ToList();
if (closedRates is not null && closedRates.Count > 0)
{
foreach (var rate in closedRates)
{
rate.RateEndDate = null;
}
await _rateService.UpdateRangeAsync(closedRates);
}
await DeleteAsync(id);
}
catch (Exception exception)
{
var message = $"Failure ComplexDelete for RateUploadInfo with RateUploadInfoId {id}.";
Log.Error(exception, message);
throw new ServiceException(message);
}
}
}
@@ -0,0 +1,28 @@
using LCU.Library.Internal.Status.Services;
using LCU.Library.Internal.StatusModels.Models;
namespace LCU.API.Internal.LoanRate.Services;
public class StatusService : IStatusService
{
private readonly IEnvironmentViewService _environmentViewService;
public StatusService(IEnvironmentViewService environmentViewService)
{
_environmentViewService = environmentViewService;
}
public EnvironmentView GetEnviromentView()
{
try
{
var environmentView = _environmentViewService.BuildEnvironmentView();
Log.Verbose("Status Environment View Heartbeat. EnvironmentView: {@EnvironmentView}", environmentView);
return environmentView;
}
catch (Exception exception)
{
Log.Error(exception, $"Failure Getting Enviroment View Information.");
throw new ServiceException($"Failure Getting Enviroment View Information.");
}
}
}
@@ -0,0 +1,8 @@
using LCU.Library.Internal.LoanRateModels.Requests;
namespace LCU.API.Internal.LoanRate.Services.ValidateLoanRateServices;
public interface IValidateRateEvaluationsService
{
Task<bool> ValidateRatePassesEvaluation(RateRequest request, int rateId, int evaluationDetailId);
Task<bool> ValidateRatePassesEvaluations(RateRequest request, int rateId);
}
@@ -0,0 +1,58 @@
using LCU.API.Internal.LoanRate.Services.LoanRateOperationServices;
using LCU.Library.Internal.LcuEvaluationModels.Enums;
using LCU.Library.Internal.LcuEvaluation.Services;
using LCU.Library.Internal.LcuEvaluation.Services.EvaluationServices;
using LCU.Library.Internal.LcuEvaluationModels.Entities;
using LCU.Library.Internal.LoanRateModels.Requests;
namespace LCU.API.Internal.LoanRate.Services.ValidateLoanRateServices;
public class ValidateRateEvaluationsService : IValidateRateEvaluationsService
{
private readonly IEvaluationDetailService _evaluationDetailService;
private readonly IRateService _rateService;
private readonly IRunRuleService _runRuleService;
private readonly IRateFinderService _rateFinderService;
public ValidateRateEvaluationsService(IEvaluationDetailService evaluationDetailService,
IRateService rateService,
IRunRuleService runRuleService,
IRateFinderService rateFinderService)
{
_evaluationDetailService = evaluationDetailService;
_rateService = rateService;
_runRuleService = runRuleService;
_rateFinderService = rateFinderService;
}
public async Task<bool> ValidateRatePassesEvaluation(RateRequest request, int rateId, int evaluationDetailId)
{
var evaluation = await _evaluationDetailService.GetByIdAsync(evaluationDetailId);
var passedEvaluations = _runRuleService.ValidateRequestRules(request, new List<EvaluationDetail> { evaluation });
var rate = await _rateService.GetByIdAsync(rateId);
var passedEvaluation = passedEvaluations.FirstOrDefault();
if (passedEvaluation == null)
{
return false;
}
var passRate = rate.RateEvaluations.FirstOrDefault(rateEvaluation => rateEvaluation.EvaluationDetailId == passedEvaluation.EvaluationDetailId);
return passRate != null;
}
public async Task<bool> ValidateRatePassesEvaluations(RateRequest request, int rateId)
{
var rate = await _rateService.GetByIdAsync(rateId);
var evaluationIds = rate.RateEvaluations.Select(rateEvaluation => rateEvaluation.EvaluationDetailId).ToList();
var evaluations = await _evaluationDetailService.GetActiveByEvaluationTypeAndIdsAsync(request.ApplicationDate, EvaluationTypes.Rule, evaluationIds);
if (!evaluations.Any())
{
return false;
}
var passedEvaluations = _runRuleService.ValidateRequestRules(request, evaluations.ToList());
var matchingRate = (await _rateFinderService.DetermineRate(request.ApplicationDate, passedEvaluations)).rate;
return matchingRate != null && matchingRate.RateId == rateId;
}
}
@@ -0,0 +1,73 @@
{
"Primary": {
"AppName": "Loan Rate API",
"SeqUrl": "https://qa-seq.lcu-internal.com",
"SeqApiKey": "",
"CorsAllowedOrigins": [
"http://localhost:3000",
"http://lcu-internal.com",
"https://lcu-internal.com",
"https://qa-api.lcu-internal.com"
],
"FeatureFlags": {
"RunLoadTestInitiateConsumer": true,
"RunLoadTestProcessRateConsumer": true,
"RunLoadTestRateCompletionConsumer": true
}
},
"LoanRateSqlConnectionConfiguration": {
"ConnectionString": "data source=localhost;initial catalog=LoanRate;Integrated Security=SSPI;MultipleActiveResultSets=True;App=EntityFramework;Encrypt=False;",
"MaxRetryCount": 3,
"MaxRetryDelay": "00:00:30"
},
"LoanRateLoadTestingSqlConnectionConfiguration": {
"ConnectionString": "data source=localhost;initial catalog=LoanRateLoadTest;Integrated Security=SSPI;MultipleActiveResultSets=True;App=EntityFramework;Encrypt=False;",
"MaxRetryCount": 3,
"MaxRetryDelay": "00:00:30"
},
"EvaluationSqlConnectionConfiguration": {
"ConnectionString": "data source=localhost;initial catalog=LoanRate;Integrated Security=SSPI;MultipleActiveResultSets=True;App=EntityFramework;Encrypt=False;",
"MaxRetryCount": 3,
"MaxRetryDelay": "00:00:30"
},
"ConnectionConfiguration": {
"HostUrl": "localhost",
"UserName": "guest",
"Password": "guest"
},
"LoadTestInitiateReceiveEndpoint": {
"ReceiveEndpoint": "LCU.LoanRate.LoadTest.Initiate",
"ReceiveEndpointType": "exchange",
"PrefetchLimit": 1
},
"LoadTestProcessRateReceiveEndpoint": {
"ReceiveEndpoint": "LCU.LoanRate.LoadTest.ProcessRate",
"ReceiveEndpointType": "exchange",
"PrefetchLimit": 1
},
"LoadTestRateCompletionReceiveEndpoint": {
"ReceiveEndpoint": "LCU.LoanRate.LoadTest.RateCompletion",
"ReceiveEndpointType": "exchange",
"PrefetchLimit": 100
},
"FileOperationsApiConfiguration": {
"Url": "https://localhost:44368",
"ExtractExcelWorkBookDataEndpoint": "/api/Excel/ExtractExcelWorkBookData"
},
"RateCacheConfiguration": {
"CacheName": "RateCache",
"ExpirationMinutes": "480"
},
"RateUploadInfoCacheConfiguration": {
"CacheName": "RateUploadInfoCache",
"ExpirationMinutes": "480"
},
"RateSheetCacheConfiguration": {
"CacheName": "RateSheetCache",
"ExpirationMinutes": "480"
},
"EvaluationCacheConfiguration": {
"CacheName": "EvaluationCache",
"ExpirationMinutes": "480"
}
}
@@ -0,0 +1,3 @@
global using Serilog;
global using LCU.Library.Internal.Exceptions;
global using LCU.Library.Internal.LoanRateModels.Entities;
@@ -0,0 +1,7 @@
using LCU.Library.Internal.LcuCaching.Configurations;
namespace LCU.API.Internal.LoanRateLib.Configurations;
public class RateCacheConfiguration : CacheConfiguration
{
}
@@ -0,0 +1,7 @@
using LCU.Library.Internal.LcuCaching.Configurations;
namespace LCU.API.Internal.LoanRateLib.Configurations;
public class RateSheetCacheConfiguration : CacheConfiguration
{
}
@@ -0,0 +1,7 @@
namespace LCU.API.Internal.LoanRateLib.Configurations;
public class RateUploadInfoCacheConfiguration
{
public string CacheName { get; set; }
public int ExpirationMinutes { get; set; }
}
@@ -0,0 +1,36 @@
using Microsoft.EntityFrameworkCore;
namespace LCU.API.Internal.LoanRateLib.Extensions.Queryables;
public static class IncludeAllQueryable
{
public static IQueryable<Rate> IncludeAll(this IQueryable<Rate> queryable)
{
return queryable.Include(rate => rate.RateEvaluations);
}
public static IQueryable<Rate> IncludeAllRatesEvaluations(this IQueryable<Rate> queryable)
{
return queryable.Include(rate => rate.RateEvaluations)
.ThenInclude(rate => rate.EvaluationDetail);
}
public static IQueryable<RateUploadInfo> IncludeAll(this IQueryable<RateUploadInfo> queryable)
{
return queryable.Include(rateUploadInfo => rateUploadInfo.Rates)
.Include(rateUploadInfo => rateUploadInfo.ClosedRates)
.ThenInclude(rate => rate.RateEvaluations);
}
public static IQueryable<RateUploadInfo> IncludeAllButClosedRates(this IQueryable<RateUploadInfo> queryable)
{
return queryable.Include(rateUploadInfo => rateUploadInfo.Rates)
.ThenInclude(rate => rate.RateEvaluations);
}
public static IQueryable<RateSheet> IncludeAll(this IQueryable<RateSheet> queryable)
{
return queryable.Include(rateSheet => rateSheet.RateSheetCells)
.Include(rateSheet => rateSheet.Rates)
.ThenInclude(rate => rate.RateEvaluations);
}
}
@@ -0,0 +1,8 @@
namespace LCU.API.Internal.LoanRateLib.Extensions.Queryables;
public static class IncludeFiltersQueryable
{
public static IQueryable<RateUploadInfo> IncludeFilters(this IQueryable<RateUploadInfo> queryable, RateUploadInfoFilter rateUploadInfoFilter)
=> queryable.FilterByEffectiveDate(rateUploadInfoFilter)
.FilterByVersion(rateUploadInfoFilter)
.FilterByCreatedBy(rateUploadInfoFilter);
}
@@ -0,0 +1,13 @@
namespace LCU.API.Internal.LoanRateLib.Extensions.Queryables;
public static class RateUploadInfoCreatedByQueryable
{
public static IQueryable<RateUploadInfo> FilterByCreatedBy(this IQueryable<RateUploadInfo> queryable, RateUploadInfoFilter rateUploadInfoFilter)
{
if (rateUploadInfoFilter.CreatedBy == null)
{
return queryable;
}
return queryable.Where(rateUploadInfo => rateUploadInfo.CreatedBy.ToUpper().Contains(rateUploadInfoFilter.CreatedBy.ToUpper()));
}
}
@@ -0,0 +1,13 @@
namespace LCU.API.Internal.LoanRateLib.Extensions.Queryables;
public static class RateUploadInfoEffectiveDateQueryable
{
public static IQueryable<RateUploadInfo> FilterByEffectiveDate(this IQueryable<RateUploadInfo> queryable, RateUploadInfoFilter rateUploadInfoFilter)
{
if (rateUploadInfoFilter.EffectiveDate == null)
{
return queryable;
}
return queryable.Where(rateUploadInfo => rateUploadInfo.EffectiveDate.Date == ((DateTime)rateUploadInfoFilter.EffectiveDate).Date);
}
}
@@ -0,0 +1,13 @@
namespace LCU.API.Internal.LoanRateLib.Extensions.Queryables;
public static class RateUploadInfoVersionQueryable
{
public static IQueryable<RateUploadInfo> FilterByVersion(this IQueryable<RateUploadInfo> queryable, RateUploadInfoFilter rateUploadInfoFilter)
{
if (rateUploadInfoFilter.Version == null)
{
return queryable;
}
return queryable.Where(rateUploadInfo => rateUploadInfo.Version == (int)rateUploadInfoFilter.Version);
}
}
@@ -0,0 +1,28 @@
using System.Linq.Dynamic.Core;
using System.Text;
namespace LCU.API.Internal.LoanRateLib.Extensions.Queryables;
public static class SortableFieldsQueryable
{
public static IQueryable<RateUploadInfo> OrderBySortableFields(this IQueryable<RateUploadInfo> queryable, RateUploadInfoFilter rateUploadInfoFilter)
{
var sortableFields = rateUploadInfoFilter.SortableFields
.Where(sortableField => sortableField.Active && sortableField.Position >= 0)
.OrderBy(sortableField => sortableField.Position).ToList();
if (sortableFields == null || !sortableFields.Any())
{
return queryable;
}
var orderBy = new StringBuilder();
foreach (var field in sortableFields)
{
var addedComma = orderBy.ToString() == "" ? "" : " ,";
var desc = field.IsDescending ? " desc" : "";
orderBy.Append($"{addedComma}{field.Field}{desc}");
}
return queryable.OrderBy(orderBy.ToString());
}
}
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="LCU.Library.Internal.LcuCaching" Version="1.0.0" />
<PackageReference Include="LCU.Library.Internal.LcuClassPatterns.Crud" Version="1.0.2" />
<PackageReference Include="LCU.Library.Internal.TypeExtensions" Version="1.2.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="7.0.8" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.5.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LCU.Library.Internal.LoanRateModels\LCU.Library.Internal.LoanRateModels.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,45 @@
using Microsoft.EntityFrameworkCore;
namespace LCU.API.Internal.LoanRateLib.Persistence;
public class AppDbContext : DbContext
{
public DbSet<Rate> Rates { get; set; }
public DbSet<RateEvaluation> RateEvaluations { get; set; }
public DbSet<RateUploadInfo> RateUploadInfos { get; set; }
public DbSet<RateSheet> RateSheets { get; set; }
public DbSet<RateSheetCell> RateSheetCells { get; set; }
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<Rate>().ToTable("Rate");
builder.Entity<RateEvaluation>().ToTable("RateEvaluation");
builder.Entity<RateUploadInfo>().ToTable("RateUploadInfo")
.HasMany(rateUploadInfo => rateUploadInfo.Rates)
.WithOne()
.HasForeignKey(rate => rate.RateUploadInfoId)
.IsRequired(false)
.OnDelete(DeleteBehavior.Cascade);
builder.Entity<RateUploadInfo>().ToTable("RateUploadInfo")
.HasMany(rateUploadInfo => rateUploadInfo.ClosedRates)
.WithOne()
.HasForeignKey(rate => rate.ClosingRateUploadInfoId)
.IsRequired(false)
.OnDelete(DeleteBehavior.SetNull);
builder.Entity<RateSheet>().ToTable("RateSheet")
.HasMany(rateSheet => rateSheet.Rates)
.WithOne()
.HasForeignKey(rate => rate.RateSheetId)
.IsRequired(false)
.OnDelete(DeleteBehavior.Cascade);
builder.Entity<RateSheet>().ToTable("RateSheet")
.HasMany(rateSheet => rateSheet.RateSheetCells)
.WithOne()
.HasForeignKey(rateSheetCell => rateSheetCell.RateSheetId)
.IsRequired(false)
.OnDelete(DeleteBehavior.Cascade);
builder.Entity<RateSheetCell>().ToTable("RateSheetCell");
}
}
@@ -0,0 +1,12 @@
using LCU.API.Internal.LoanRateLib.Persistence;
namespace LCU.API.Internal.LoanRateLib.Repositories;
public abstract class BaseRepository
{
protected readonly AppDbContext _context;
public BaseRepository(AppDbContext context)
{
_context = context;
}
}
@@ -0,0 +1,18 @@
using LCU.Library.Internal.LoanRateModels.Enums;
namespace LCU.API.Internal.LoanRateLib.Repositories;
public interface IRateEvaluationRepository
{
Task<IEnumerable<RateEvaluation>?> FindAsync();
Task<RateEvaluation?> FindByIdAsync(int id);
Task<IEnumerable<RateEvaluation>?> FindRangeByIdAsync(List<int> ids);
Task<IEnumerable<RateEvaluation>?> FindRangeByEvaluationDetailIdAsync(int evaluationDetailId);
Task<IEnumerable<RateEvaluation>?> FindByRateSheetIdsAsync(List<int> rateSheetIds);
Task<RateEvaluation?> AddAsync(RateEvaluation rateEvaluation);
Task AddRangeAsync(IEnumerable<RateEvaluation> rateEvaluations);
void UpdateRange(IEnumerable<RateEvaluation> rateEvaluations);
void Remove(RateEvaluation rateEvaluation);
void RemoveRange(IEnumerable<RateEvaluation> rateEvaluations);
Task<int> CountByEvaluationDetailIdAsync(int evaluationDetailId);
}
@@ -0,0 +1,23 @@
using LCU.Library.Internal.LcuEvaluationModels.Enums;
namespace LCU.API.Internal.LoanRateLib.Repositories;
public interface IRateRepository
{
Task<IEnumerable<Rate>?> FindAsync();
Task<IEnumerable<Rate>?> FindWithRateEvaluationsAsync();
Task<Rate?> FindByIdAsync(int id);
Task<IEnumerable<Rate>?> FindByClosingRateUploadInfoIdAsync(int id);
Task<IEnumerable<Rate>?> FindByDateAsync(DateTime date);
Task<IEnumerable<Rate>?> FindRateHistoryAsync(Rate rate);
Task<IEnumerable<Rate>?> FindRangeByIdAsync(List<int> ids);
Task<IEnumerable<Rate>?> FindByDateEvaluationIdsAndEvaluationTypeAsync(DateTime date,
List<int> evaluationIds,
EvaluationTypes evaluationType);
Task<Rate?> AddAsync(Rate rate);
Task AddRangeAsync(IEnumerable<Rate> rates);
void UpdateRange(IEnumerable<Rate> rates);
void Remove(Rate rate);
void RemoveRange(IEnumerable<Rate> rates);
Task<IEnumerable<Rate>> FindCacheAsync();
void ClearCache();
}
@@ -0,0 +1,6 @@
using LCU.Library.Internal.LcuClassPatterns.Crud.Repositories;
namespace LCU.API.Internal.LoanRateLib.Repositories;
public interface IRateSheetCellRepository : ICrudRepository<RateSheetCell>
{
}
@@ -0,0 +1,15 @@
using LCU.Library.Internal.LcuClassPatterns.Crud.Repositories;
using LCU.Library.Internal.LoanRateModels.Enums;
namespace LCU.API.Internal.LoanRateLib.Repositories;
public interface IRateSheetRepository : ICrudRepository<RateSheet>
{
Task<IEnumerable<RateSheet>> FindIncludeAllAsync();
Task<IEnumerable<RateSheet>> FindIncludeRateSheetCellsAsync();
Task<IEnumerable<Rate>?> FindRatesByDateAndRateType(DateTime date, RateTypes rateType);
Task<RateSheet?> FindByDateAndRateType(DateTime date, RateTypes rateType);
Task<IEnumerable<Rate>?> FindRatesByRateType(RateTypes rateType);
Task<IEnumerable<int>?> FindRateSheetIdsByRateType(RateTypes rateType);
Task<IEnumerable<RateSheet>> FindCacheAsync();
void ClearCache();
}
@@ -0,0 +1,12 @@
using LCU.Library.Internal.LcuClassPatterns.Crud.Repositories;
using LCU.Library.Internal.LoanRateModels.Responses;
namespace LCU.API.Internal.LoanRateLib.Repositories;
public interface IRateUploadInfoRepository : ICrudRepository<RateUploadInfo>
{
Task<RateUploadInfo?> FindLatestAsync();
Task<RateUploadInfo?> FindByVersionAsync(int version, DateTime effectiveDate);
Task<RateUploadInfo?> FindPreviousVersion(RateUploadInfo rateUploadInfo);
Task<RateUploadInfo?> FindLatestVersionOnDate(DateTime effectiveDate);
Task<RateUploadInfoFilterResult> FindFilteredRateUploadInfosAsync(RateUploadInfoFilter rateUploadInfoFilter);
}
@@ -0,0 +1,7 @@
namespace LCU.API.Internal.LoanRateLib.Repositories;
public interface IUnitOfWork
{
Task CompleteAsync();
void Complete();
}
@@ -0,0 +1,81 @@
using Microsoft.EntityFrameworkCore;
using LCU.API.Internal.LoanRateLib.Persistence;
using LCU.Library.Internal.LoanRateModels.Enums;
namespace LCU.API.Internal.LoanRateLib.Repositories;
public class RateEvaluationRepository : BaseRepository, IRateEvaluationRepository
{
public IRateRepository _rateRepository;
public RateEvaluationRepository(AppDbContext context,
IRateRepository rateRepository) : base(context)
{
_rateRepository = rateRepository;
}
public async Task<IEnumerable<RateEvaluation>?> FindAsync()
{
return await _context.RateEvaluations.ToListAsync();
}
public async Task<RateEvaluation?> FindByIdAsync(int id)
{
return await _context.RateEvaluations.FirstOrDefaultAsync(rateEvaluation => rateEvaluation.RateEvaluationId == id);
}
public async Task<IEnumerable<RateEvaluation>?> FindRangeByIdAsync(List<int> ids)
{
return await _context.RateEvaluations
.Where(rateEvaluation => ids.Contains(rateEvaluation.RateEvaluationId))
.ToListAsync();
}
public async Task<IEnumerable<RateEvaluation>?> FindRangeByEvaluationDetailIdAsync(int evaluationDetailId)
{
return await _context.RateEvaluations
.Where(rateEvaluation => rateEvaluation.EvaluationDetailId == evaluationDetailId)
.ToListAsync();
}
public async Task<IEnumerable<RateEvaluation>?> FindByRateSheetIdsAsync(List<int> rateSheetIds)
{
return (await _rateRepository.FindCacheAsync())
.Where(rate => rateSheetIds.Contains(rate.RateSheetId))
.SelectMany(rate => rate.RateEvaluations);
}
public async Task<RateEvaluation?> AddAsync(RateEvaluation rateEvaluation)
{
return (await _context.RateEvaluations.AddAsync(rateEvaluation)).Entity;
}
public async Task AddRangeAsync(IEnumerable<RateEvaluation> rateEvaluations)
{
await _context.RateEvaluations.AddRangeAsync(rateEvaluations);
}
public void UpdateRange(IEnumerable<RateEvaluation> rateEvaluations)
{
_context.RateEvaluations.UpdateRange(rateEvaluations);
}
public void Remove(RateEvaluation rateEvaluation)
{
_context.RateEvaluations.Remove(rateEvaluation);
}
public void RemoveRange(IEnumerable<RateEvaluation> rateEvaluations)
{
_context.RateEvaluations.RemoveRange(rateEvaluations);
}
public async Task<int> CountByEvaluationDetailIdAsync(int evaluationDetailId)
{
return await _context.RateEvaluations
.Where(rateEvaluation => rateEvaluation.EvaluationDetailId == evaluationDetailId)
.Select(rateEvaluation => rateEvaluation.RateId)
.Distinct()
.CountAsync();
}
}
@@ -0,0 +1,139 @@
using Microsoft.EntityFrameworkCore;
using LCU.API.Internal.LoanRateLib.Configurations;
using LCU.API.Internal.LoanRateLib.Extensions.Queryables;
using LCU.API.Internal.LoanRateLib.Persistence;
using LCU.Library.Internal.LcuCaching.Services;
using LCU.Library.Internal.LcuEvaluationModels.Enums;
namespace LCU.API.Internal.LoanRateLib.Repositories;
public class RateRepository : BaseRepository, IRateRepository
{
private readonly RateCacheConfiguration _rateCacheConfiguration;
private readonly ICacheService _cacheService;
public RateRepository(AppDbContext context,
RateCacheConfiguration rateCacheConfiguration,
ICacheService cacheService) : base(context)
{
_rateCacheConfiguration = rateCacheConfiguration;
_cacheService = cacheService;
}
public async Task<IEnumerable<Rate>?> FindAsync()
{
return await _context.Rates.IncludeAll().ToListAsync();
}
public async Task<IEnumerable<Rate>?> FindWithRateEvaluationsAsync()
{
return await _context.Rates.IncludeAllRatesEvaluations().ToListAsync();
}
public async Task<Rate?> FindByIdAsync(int id)
{
return await _context.Rates.IncludeAll().FirstOrDefaultAsync(rate => rate.RateId == id);
}
public async Task<IEnumerable<Rate>?> FindByClosingRateUploadInfoIdAsync(int id)
{
return await _context.Rates.Where(rate => rate.ClosingRateUploadInfoId == id)
.ToListAsync();
}
public async Task<IEnumerable<Rate>?> FindByDateAsync(DateTime date)
{
return await _context.Rates.Where(rate => date >= rate.RateStartDate &&
(rate.RateEndDate == null || date < rate.RateEndDate))
.IncludeAll()
.ToListAsync();
}
public async Task<IEnumerable<Rate>?> FindRateHistoryAsync(Rate rate)
{
return await _context.Rates.Where(x => x.Row == rate.Row
&& x.Column == rate.Column
&& x.RateSheetId == rate.RateSheetId)
.ToListAsync();
}
public async Task<IEnumerable<Rate>?> FindRangeByIdAsync(List<int> ids)
{
return await _context.Rates
.Where(rate => ids.Contains(rate.RateId))
.IncludeAll()
.ToListAsync();
}
/// <summary>
/// Will get Rates that:
/// - Are between the RateStartDate-RateEndDate(if not null).
/// - Match the evaluation type
/// - Match All the EvaluationIds
/// - Contains ALL the evaluationids and the count of RateEvaluation.EvaluationDetailIds match the count of evaluationIds
/// </summary>
/// <param name="date"></param>
/// <param name="evaluationIds"></param>
/// <param name="evaluationType"></param>
/// <returns></returns>
public async Task<IEnumerable<Rate>?> FindByDateEvaluationIdsAndEvaluationTypeAsync(DateTime date,
List<int> evaluationIds,
EvaluationTypes evaluationType)
{
return await _context.Rates
.Where(
rate => date >= rate.RateStartDate &&
(!rate.RateEndDate.HasValue || date < rate.RateEndDate) &&
(rate.RateEvaluations.Any() &&
rate.RateEvaluations
.Where(rateEvaluation =>
(date >= rateEvaluation.EvaluationDetail.StartDate &&
(!rateEvaluation.EvaluationDetail.EndDate.HasValue || date < rateEvaluation.EvaluationDetail.EndDate)) &&
rateEvaluation.EvaluationDetail.EvaluationType == evaluationType &&
rateEvaluation.EvaluationDetail.Active == true)
.All(rateEvaluation => evaluationIds.Contains(rateEvaluation.EvaluationDetailId)) &&
rate.RateEvaluations
.Where(rateEvaluation =>
(date >= rateEvaluation.EvaluationDetail.StartDate &&
(!rateEvaluation.EvaluationDetail.EndDate.HasValue || date < rateEvaluation.EvaluationDetail.EndDate)) &&
rateEvaluation.EvaluationDetail.EvaluationType == evaluationType &&
rateEvaluation.EvaluationDetail.Active == true &&
evaluationIds.Contains(rateEvaluation.EvaluationDetailId))
.Select(rateEvaluation => rateEvaluation.EvaluationDetailId).Count() == evaluationIds.Count))
.IncludeAllRatesEvaluations()
.ToListAsync();
}
public async Task<Rate?> AddAsync(Rate rate)
{
return (await _context.Rates.AddAsync(rate)).Entity;
}
public async Task AddRangeAsync(IEnumerable<Rate> rates)
{
await _context.Rates.AddRangeAsync(rates);
}
public void UpdateRange(IEnumerable<Rate> rates)
{
_context.Rates.UpdateRange(rates);
}
public void Remove(Rate rate)
{
_context.Rates.Remove(rate);
}
public void RemoveRange(IEnumerable<Rate> rates)
{
_context.Rates.RemoveRange(rates);
}
public async Task<IEnumerable<Rate>> FindCacheAsync()
=> await _cacheService.FindCacheAsync(FindAsync,
_rateCacheConfiguration.CacheName,
_rateCacheConfiguration.ExpirationMinutes);
public void ClearCache()
=> _cacheService.ClearCache(_rateCacheConfiguration.CacheName);
}
@@ -0,0 +1,13 @@
using LCU.API.Internal.LoanRateLib.Persistence;
using LCU.Library.Internal.LcuClassPatterns.Crud.Repositories;
namespace LCU.API.Internal.LoanRateLib.Repositories;
public class RateSheetCellRepository : CrudRepository<RateSheetCell>, IRateSheetCellRepository
{
private readonly AppDbContext _context;
public RateSheetCellRepository(AppDbContext context) : base(context)
{
_context = context;
}
}
@@ -0,0 +1,83 @@
using LCU.API.Internal.LoanRateLib.Configurations;
using LCU.API.Internal.LoanRateLib.Extensions.Queryables;
using LCU.API.Internal.LoanRateLib.Persistence;
using LCU.Library.Internal.LcuCaching.Services;
using LCU.Library.Internal.LcuClassPatterns.Crud.Repositories;
using LCU.Library.Internal.LoanRateModels.Enums;
using Microsoft.EntityFrameworkCore;
namespace LCU.API.Internal.LoanRateLib.Repositories;
public class RateSheetRepository : CrudRepository<RateSheet>, IRateSheetRepository
{
private readonly AppDbContext _context;
private readonly RateSheetCacheConfiguration _rateSheetCacheConfiguration;
private readonly ICacheService _cacheService;
public RateSheetRepository(AppDbContext context,
RateSheetCacheConfiguration rateSheetCacheConfiguration,
ICacheService cacheService) : base(context)
{
_context = context;
_rateSheetCacheConfiguration = rateSheetCacheConfiguration;
_cacheService = cacheService;
}
public async Task<IEnumerable<RateSheet>> FindIncludeAllAsync()
{
return await _context.RateSheets.IncludeAll().ToListAsync();
}
public async Task<IEnumerable<RateSheet>> FindIncludeRateSheetCellsAsync()
{
return await _context.RateSheets.Include(rateSheet => rateSheet.RateSheetCells).ToListAsync();
}
public async Task<IEnumerable<Rate>?> FindRatesByDateAndRateType(DateTime date, RateTypes rateType)
{
return (await FindCacheAsync()).FirstOrDefault(rateSheet => rateSheet.RateType == rateType)?
.Rates.Where(rate =>
date >= rate.RateStartDate
&& (rate.RateEndDate == null || date < rate.RateEndDate));
}
public async Task<RateSheet?> FindByDateAndRateType(DateTime date, RateTypes rateType)
{
return await _context.RateSheets.Include(rateSheet => rateSheet.Rates)
.Include(rateSheet => rateSheet.RateSheetCells)
.Where(rateSheet => rateSheet.RateType == rateType)
.Select(rateSheet =>
new RateSheet
{
RateSheetId = rateSheet.RateSheetId,
RateType = rateSheet.RateType,
RateSheetCells = rateSheet.RateSheetCells,
Rates = _context.Rates.Where(rate => rate.RateSheetId == rateSheet.RateSheetId
&& date >= rate.RateStartDate
&& (rate.RateEndDate == null || date < rate.RateEndDate)).ToList(),
CreatedBy = rateSheet.CreatedBy,
TimeCreated = rateSheet.TimeCreated
})
.FirstOrDefaultAsync();
}
public async Task<IEnumerable<Rate>?> FindRatesByRateType(RateTypes rateType)
{
return (await FindCacheAsync()).FirstOrDefault(rateSheet => rateSheet.RateType == rateType)?.Rates;
}
public async Task<IEnumerable<int>?> FindRateSheetIdsByRateType(RateTypes rateType)
{
return await _context.RateSheets.Where(rateSheet => rateSheet.RateType == rateType)
.Select(rateSheet => rateSheet.RateSheetId)
.ToListAsync();
}
public async Task<IEnumerable<RateSheet>> FindCacheAsync()
{
return await _cacheService.FindCacheAsync(FindIncludeAllAsync,
_rateSheetCacheConfiguration.CacheName,
_rateSheetCacheConfiguration.ExpirationMinutes);
}
public void ClearCache() => _cacheService.ClearCache(_rateSheetCacheConfiguration.CacheName);
}
@@ -0,0 +1,91 @@
using LCU.API.Internal.LoanRateLib.Extensions.Queryables;
using LCU.API.Internal.LoanRateLib.Persistence;
using LCU.Library.Internal.LcuClassPatterns.Crud.Repositories;
using LCU.Library.Internal.LoanRateModels.Responses;
using Microsoft.EntityFrameworkCore;
namespace LCU.API.Internal.LoanRateLib.Repositories;
public class RateUploadInfoRepository : CrudRepository<RateUploadInfo>, IRateUploadInfoRepository
{
private readonly AppDbContext _context;
public RateUploadInfoRepository(AppDbContext context) : base(context)
{
_context = context;
}
public async Task<RateUploadInfo?> FindLatestAsync()
{
return await _context.RateUploadInfos.OrderByDescending(r => r.EffectiveDate)
.ThenByDescending(r => r.Version)
.FirstOrDefaultAsync();
}
public async Task<RateUploadInfo?> FindByVersionAsync(int version, DateTime effectiveDate)
{
return await _context.RateUploadInfos.Where(rateUploadInfo => rateUploadInfo.EffectiveDate.Date == effectiveDate.Date
&& rateUploadInfo.Version == version)
.IncludeAllButClosedRates()
.FirstOrDefaultAsync();
}
public async Task<RateUploadInfo?> FindPreviousVersion(RateUploadInfo rateUploadInfo)
{
return await _context.RateUploadInfos.Where(r => r.EffectiveDate.Date <= rateUploadInfo.EffectiveDate.Date
&& (r.EffectiveDate.Date != rateUploadInfo.EffectiveDate.Date || r.Version < rateUploadInfo.Version )
&& r.RateUploadInfoId != rateUploadInfo.RateUploadInfoId)
.OrderByDescending(r => r.EffectiveDate)
.ThenByDescending(r => r.Version)
.IncludeAllButClosedRates()
.FirstOrDefaultAsync();
}
public async Task<RateUploadInfo?> FindLatestVersionOnDate(DateTime effectiveDate)
{
return await _context.RateUploadInfos.Where(r => r.EffectiveDate.Date == effectiveDate.Date)
.OrderByDescending(r => r.Version)
.IncludeAllButClosedRates()
.FirstOrDefaultAsync();
}
public override async Task<IEnumerable<RateUploadInfo>> FindAsync()
{
return await _context.RateUploadInfos.IncludeAllButClosedRates().ToListAsync();
}
public async Task<RateUploadInfoFilterResult> FindFilteredRateUploadInfosAsync(RateUploadInfoFilter rateUploadInfoFilter)
{
var results = new RateUploadInfoFilterResult();
var skip = (rateUploadInfoFilter.Page - 1) * rateUploadInfoFilter.Limit;
results.Total = await _context.RateUploadInfos
.IncludeFilters(rateUploadInfoFilter)
.CountAsync();
results.Items = await _context.RateUploadInfos
.IncludeFilters(rateUploadInfoFilter)
.OrderBySortableFields(rateUploadInfoFilter)
.Skip(skip)
.Take(rateUploadInfoFilter.Limit)
.ToArrayAsync();
results.TotalCount = await _context.RateUploadInfos.CountAsync();
results.LatestRateUploadInfo = await FindLatestAsync();
return results;
}
public override async Task<RateUploadInfo> FindByIdAsync(int id)
{
return await _context.RateUploadInfos.Where(rateUploadInfo => rateUploadInfo.RateUploadInfoId == id)
.IncludeAllButClosedRates()
.FirstOrDefaultAsync();
}
public override async Task<IEnumerable<RateUploadInfo>> FindRangeByIdAsync(List<int> ids)
{
return await _context.RateUploadInfos.Where(rateUploadInfo => ids.Contains(rateUploadInfo.RateUploadInfoId))
.IncludeAllButClosedRates()
.ToListAsync();
}
}

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