Adding
This commit is contained in:
@@ -0,0 +1,17 @@
|
|||||||
|
**/*.bat
|
||||||
|
**/*.log
|
||||||
|
**/*.md
|
||||||
|
**/*.yml
|
||||||
|
**/.dockerignore
|
||||||
|
**/.editorconfig
|
||||||
|
**/.git
|
||||||
|
**/.gitattributes
|
||||||
|
**/.gitignore
|
||||||
|
**/.vs
|
||||||
|
**/.vscode
|
||||||
|
**/bin
|
||||||
|
**/dist
|
||||||
|
**/dockerfile
|
||||||
|
**/node_modules
|
||||||
|
**/obj
|
||||||
|
**/package-lock.json
|
||||||
@@ -0,0 +1,334 @@
|
|||||||
|
## 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
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
|
*.userprefs
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
[Dd]ebug/
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
x64/
|
||||||
|
x86/
|
||||||
|
bld/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
[Ll]og/
|
||||||
|
|
||||||
|
# SpecFlow pickled files
|
||||||
|
Specs/
|
||||||
|
|
||||||
|
# Visual Studio 2015/2017 cache/options directory
|
||||||
|
.vs/
|
||||||
|
# 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
|
||||||
|
|
||||||
|
# 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/
|
||||||
|
**/Properties/launchSettings.json
|
||||||
|
|
||||||
|
# StyleCop
|
||||||
|
StyleCopReport.xml
|
||||||
|
|
||||||
|
# Files built by Visual Studio
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*_i.h
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.iobj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.ipdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*.log
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.svclog
|
||||||
|
*.scc
|
||||||
|
*.feature.cs
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
# JustCode is a .NET coding add-in
|
||||||
|
.JustCode
|
||||||
|
|
||||||
|
# TeamCity is a build add-in
|
||||||
|
_TeamCity*
|
||||||
|
|
||||||
|
# DotCover is a Code Coverage Tool
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
# AxoCover is a Code Coverage Tool
|
||||||
|
.axoCover/*
|
||||||
|
!.axoCover/settings.json
|
||||||
|
|
||||||
|
# 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
|
||||||
|
# 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
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
# 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/
|
||||||
|
|
||||||
|
# JetBrains Rider
|
||||||
|
.idea/
|
||||||
|
*.sln.iml
|
||||||
|
|
||||||
|
# CodeRush
|
||||||
|
.cr/
|
||||||
|
|
||||||
|
# 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/
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
# .NET Core SDK
|
||||||
|
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS aspnetcore-build
|
||||||
|
|
||||||
|
# Copy Projects (context is Api/)
|
||||||
|
COPY ReserveManagementSystemApi/ReserveManagementSystemApi.csproj ./source/ReserveManagementSystemApi/
|
||||||
|
COPY ReserveManagementSystemLib/ReserveManagementSystemLib.csproj ./source/ReserveManagementSystemLib/
|
||||||
|
|
||||||
|
# Install Credential Provider and set env variables to enable Nuget restore with auth
|
||||||
|
ARG PAT=bh2lq3jibktw67b2wdbqyfln7cd3je6lk52kijntpj43v6kimpgq
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates curl && \
|
||||||
|
update-ca-certificates && \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Download the NuGet Credential Provider directly (Docker's ADD uses trusted TLS)
|
||||||
|
ADD https://github.com/microsoft/artifacts-credprovider/releases/latest/download/Microsoft.Net6.NuGet.CredentialProvider.tar.gz /tmp/
|
||||||
|
|
||||||
|
# Extract and install Credential Provider
|
||||||
|
RUN mkdir -p /root/.nuget/plugins/netcore && \
|
||||||
|
tar --strip-components=3 -xzf /tmp/Microsoft.Net6.NuGet.CredentialProvider.tar.gz -C /root/.nuget/plugins/netcore && \
|
||||||
|
rm /tmp/Microsoft.Net6.NuGet.CredentialProvider.tar.gz
|
||||||
|
|
||||||
|
ENV NUGET_PLUGIN_PATHS=/root/.nuget/plugins/netcore/CredentialProvider.Microsoft.dll
|
||||||
|
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/ReserveManagementSystemApi/ReserveManagementSystemApi.csproj
|
||||||
|
|
||||||
|
# Copy All Files
|
||||||
|
COPY . ./source/
|
||||||
|
|
||||||
|
FROM aspnetcore-build AS test
|
||||||
|
LABEL test=true
|
||||||
|
COPY ReserveManagementSystemApi.Test/ReserveManagementSystemApi.Test.csproj ./source/ReserveManagementSystemApi.Test/
|
||||||
|
RUN dotnet restore ./source/ReserveManagementSystemApi.Test/ReserveManagementSystemApi.Test.csproj
|
||||||
|
RUN dotnet test -c Release --results-directory /testresults --logger "trx;LogFileName=test_results.trx" ./source/ReserveManagementSystemApi.Test/ReserveManagementSystemApi.Test.csproj
|
||||||
|
|
||||||
|
# .NET Core Publish
|
||||||
|
FROM aspnetcore-build AS publish
|
||||||
|
RUN dotnet publish ./source/ReserveManagementSystemApi/ReserveManagementSystemApi.csproj -c Release -o /dist
|
||||||
|
|
||||||
|
# ASP.NET Core
|
||||||
|
FROM mcr.microsoft.com/dotnet/aspnet:6.0-alpine3.14
|
||||||
|
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", "ReserveManagementSystemApi.dll"]
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
CREATE TABLE [dbo].[Dealer]
|
||||||
|
(
|
||||||
|
[DealerCode] VARCHAR(4) NULL,
|
||||||
|
[Name] VARCHAR(40) NULL,
|
||||||
|
[DealerAccountNumber] VARCHAR(20) NULL,
|
||||||
|
[DealerOrganizationNumber] VARCHAR(20) NOT NULL,
|
||||||
|
[DealerGroupCode] VARCHAR(10) NULL,
|
||||||
|
CONSTRAINT [PK_Dealer] PRIMARY KEY (DealerOrganizationNumber)
|
||||||
|
)
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
/*
|
||||||
|
Do not change the database path or name variables.
|
||||||
|
Any sqlcmd variables will be properly substituted during
|
||||||
|
build and deployment.
|
||||||
|
*/
|
||||||
|
CREATE TABLE [dbo].[Import](
|
||||||
|
[ImportId] int NOT NULL IDENTITY,
|
||||||
|
[StartDate] DATETIME2 NOT NULL,
|
||||||
|
[EndDate] DATETIME2 NULL,
|
||||||
|
[RecordCount] [int] NOT NULL DEFAULT 0,
|
||||||
|
[RecordsSaved] [int] NOT NULL DEFAULT 0,
|
||||||
|
[Success] [bit] NOT NULL,
|
||||||
|
[FileName] [varchar](50) NULL,
|
||||||
|
[ImportType] [varchar](10) NULL
|
||||||
|
CONSTRAINT [PK_Import] PRIMARY KEY (ImportId)
|
||||||
|
)
|
||||||
|
|
||||||
+41
@@ -0,0 +1,41 @@
|
|||||||
|
CREATE TABLE [dbo].[Loan](
|
||||||
|
[LoanId] int NOT NULL IDENTITY,
|
||||||
|
[ImportId] [int] NOT NULL,
|
||||||
|
[MemberNumber] [varchar](13) NULL,
|
||||||
|
[LoanNumber] [varchar](20) NOT NULL,
|
||||||
|
[MemberLastName] [varchar](60) NULL,
|
||||||
|
[MemberFirstName] [varchar](20) NULL,
|
||||||
|
[MemberInitial] [char](1) NULL,
|
||||||
|
[DealerOrganizationNumber] [varchar](20) NOT NULL,
|
||||||
|
[LoanDate] [smalldatetime] NOT NULL,
|
||||||
|
[FirstPmtdate] [smalldatetime] NOT NULL,
|
||||||
|
[FinalPmtDate] [smalldatetime] NOT NULL,
|
||||||
|
[PostedDate] [smalldatetime] NOT NULL,
|
||||||
|
[LoanAmount] [money] NOT NULL,
|
||||||
|
[BuyRate] [decimal](5, 3) NOT NULL,
|
||||||
|
[ContractRate] [decimal](5, 3) NOT NULL,
|
||||||
|
[MonthlyPmt] [decimal](20, 4) NOT NULL,
|
||||||
|
[LoanTypeId] [char](2) NULL,
|
||||||
|
[Term] [int] NOT NULL DEFAULT 0,
|
||||||
|
[ReserveAmount] [money] NOT NULL DEFAULT 0,
|
||||||
|
[FlatFeePaid] [bit] NOT NULL,
|
||||||
|
[Chargeback] [money] NULL,
|
||||||
|
[PaidLoanDate] [smalldatetime] NULL,
|
||||||
|
[ReserveMessage] [varchar](100) NOT NULL,
|
||||||
|
[ChargebackMessage] [varchar](100) NULL,
|
||||||
|
[ActionRequired] [bit] NOT NULL DEFAULT 0,
|
||||||
|
[StatementDate] [smalldatetime] NULL,
|
||||||
|
[Adjustment] [money] NULL,
|
||||||
|
[LoanStatus] [varchar](25) NULL,
|
||||||
|
[ExportedReserveDate] [datetime2] NULL,
|
||||||
|
[ExportedChargebackDate] [datetime2] NULL,
|
||||||
|
[ApplicationId] VARCHAR(20) NULL,
|
||||||
|
[Warranty] BIT NOT NULL DEFAULT 0,
|
||||||
|
[GAP] BIT NOT NULL DEFAULT 0,
|
||||||
|
[CreditLife] BIT NOT NULL DEFAULT 0,
|
||||||
|
[CreditDisability] BIT NOT NULL DEFAULT 0,
|
||||||
|
[MBP] BIT NOT NULL DEFAULT 0,
|
||||||
|
[RemainingMonthsAtClose] TINYINT NULL,
|
||||||
|
[AccountType] VARCHAR(4) NULL,
|
||||||
|
CONSTRAINT [PK_Loan] PRIMARY KEY (LoanId)
|
||||||
|
)
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
CREATE TABLE [dbo].[LoanAudit](
|
||||||
|
[AuditId] int NOT NULL IDENTITY,
|
||||||
|
[LoanId] int NULL,
|
||||||
|
[MemberNumber] VARCHAR(13) NULL,
|
||||||
|
[LoanNumber] VARCHAR(20) NULL,
|
||||||
|
[ModifiedBy] [varchar](50) NOT NULL,
|
||||||
|
[ModifiedDate] [smalldatetime] NOT NULL,
|
||||||
|
[OldValue] [varchar](MAX) NULL,
|
||||||
|
[NewValue] [varchar](MAX) NULL,
|
||||||
|
[ActivityType][varchar](20) NULL,
|
||||||
|
[AuditDescription] [varchar] (255) NULL,
|
||||||
|
CONSTRAINT [PK_LoanAudit] PRIMARY KEY (AuditId),
|
||||||
|
)
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
CREATE TABLE [dbo].[LoanType](
|
||||||
|
[LoanTypeId] [char](2) NOT NULL,
|
||||||
|
[LoanComment] [varchar](70) NOT NULL,
|
||||||
|
[ChargebackMethod] [char](1) NOT NULL,
|
||||||
|
[NoChargebackDays] [smallint] NOT NULL,
|
||||||
|
[NoChargebackPayments] [smallint] NOT NULL,
|
||||||
|
[ReserveDiscount] [decimal](4,2) NOT NULL,
|
||||||
|
[FlatFeePercent] [decimal](4,2) NOT NULL,
|
||||||
|
[NoReserveThreshold] [decimal](4,2) NOT NULL,
|
||||||
|
CONSTRAINT [PK_LoanType] PRIMARY KEY ([LoanTypeId])
|
||||||
|
)
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
/*
|
||||||
|
Do not change the database path or name variables.
|
||||||
|
Any sqlcmd variables will be properly substituted during
|
||||||
|
build and deployment.
|
||||||
|
*/
|
||||||
|
CREATE TABLE [dbo].[MinorAccountType](
|
||||||
|
[MinorAccountTypeId] int NOT NULL IDENTITY,
|
||||||
|
[AccountType] [varchar](4) NULL,
|
||||||
|
[GeneralLedgerAccountNumber] [varchar](20) NULL
|
||||||
|
CONSTRAINT [PK_MinorAccountType] PRIMARY KEY (MinorAccountTypeId)
|
||||||
|
)
|
||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Operations Version="1.0" xmlns="http://schemas.microsoft.com/sqlserver/dac/Serialization/2012/02">
|
||||||
|
<Operation Name="Rename Refactor" Key="69fc61bd-1b0d-4310-ab5f-4e3fccb9c3df" ChangeDateTime="05/13/2021 15:21:43">
|
||||||
|
<Property Name="ElementName" Value="[dbo].[Dealer].[Id]" />
|
||||||
|
<Property Name="ElementType" Value="SqlSimpleColumn" />
|
||||||
|
<Property Name="ParentElementName" Value="[dbo].[Dealer]" />
|
||||||
|
<Property Name="ParentElementType" Value="SqlTable" />
|
||||||
|
<Property Name="NewName" Value="DealerCode" />
|
||||||
|
</Operation>
|
||||||
|
<Operation Name="Rename Refactor" Key="0a110887-6676-4aca-9942-f330f30f704f" ChangeDateTime="05/19/2021 21:46:24">
|
||||||
|
<Property Name="ElementName" Value="[dbo].[Loan].[LoanType]" />
|
||||||
|
<Property Name="ElementType" Value="SqlSimpleColumn" />
|
||||||
|
<Property Name="ParentElementName" Value="[dbo].[Loan]" />
|
||||||
|
<Property Name="ParentElementType" Value="SqlTable" />
|
||||||
|
<Property Name="NewName" Value="LoanTypeId" />
|
||||||
|
</Operation>
|
||||||
|
<Operation Name="Rename Refactor" Key="23eba713-18fa-44bb-a71e-04e955a9b20a" ChangeDateTime="08/13/2021 21:40:09">
|
||||||
|
<Property Name="ElementName" Value="[dbo].[Dealer].[DealerGroup]" />
|
||||||
|
<Property Name="ElementType" Value="SqlSimpleColumn" />
|
||||||
|
<Property Name="ParentElementName" Value="[dbo].[Dealer]" />
|
||||||
|
<Property Name="ParentElementType" Value="SqlTable" />
|
||||||
|
<Property Name="NewName" Value="DealerGroupCode" />
|
||||||
|
</Operation>
|
||||||
|
<Operation Name="Rename Refactor" Key="e3d400fd-ceec-4ff6-9557-c2403be5fd00" ChangeDateTime="08/13/2021 21:52:38">
|
||||||
|
<Property Name="ElementName" Value="[dbo].[Loan].[DealerCode]" />
|
||||||
|
<Property Name="ElementType" Value="SqlSimpleColumn" />
|
||||||
|
<Property Name="ParentElementName" Value="[dbo].[Loan]" />
|
||||||
|
<Property Name="ParentElementType" Value="SqlTable" />
|
||||||
|
<Property Name="NewName" Value="DealerOrg" />
|
||||||
|
</Operation>
|
||||||
|
<Operation Name="Rename Refactor" Key="79da7c58-8312-4cea-b111-4ff27f87ad19" ChangeDateTime="08/13/2021 21:53:00">
|
||||||
|
<Property Name="ElementName" Value="[dbo].[Loan].[DealerOrg]" />
|
||||||
|
<Property Name="ElementType" Value="SqlSimpleColumn" />
|
||||||
|
<Property Name="ParentElementName" Value="[dbo].[Loan]" />
|
||||||
|
<Property Name="ParentElementType" Value="SqlTable" />
|
||||||
|
<Property Name="NewName" Value="DealerOrganizationNumber" />
|
||||||
|
</Operation>
|
||||||
|
</Operations>
|
||||||
+81
@@ -0,0 +1,81 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<Name>ReserveManagementSystemApi.Sql</Name>
|
||||||
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
|
<ProjectVersion>4.1</ProjectVersion>
|
||||||
|
<ProjectGuid>{5a41c8dc-6f4d-4fd2-b03d-d0b2d8b363df}</ProjectGuid>
|
||||||
|
<DSP>Microsoft.Data.Tools.Schema.Sql.Sql130DatabaseSchemaProvider</DSP>
|
||||||
|
<OutputType>Database</OutputType>
|
||||||
|
<RootPath>
|
||||||
|
</RootPath>
|
||||||
|
<RootNamespace>ReserveManagementSystemApi.Sql</RootNamespace>
|
||||||
|
<AssemblyName>ReserveManagementSystemApi.Sql</AssemblyName>
|
||||||
|
<ModelCollation>1033, CI</ModelCollation>
|
||||||
|
<DefaultFileStructure>BySchemaAndSchemaType</DefaultFileStructure>
|
||||||
|
<DeployToDatabase>True</DeployToDatabase>
|
||||||
|
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||||
|
<TargetLanguage>CS</TargetLanguage>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<SqlServerVerification>False</SqlServerVerification>
|
||||||
|
<IncludeCompositeObjects>True</IncludeCompositeObjects>
|
||||||
|
<TargetDatabaseSet>True</TargetDatabaseSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<BuildScriptName>$(MSBuildProjectName).sql</BuildScriptName>
|
||||||
|
<TreatWarningsAsErrors>False</TreatWarningsAsErrors>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<DefineDebug>false</DefineDebug>
|
||||||
|
<DefineTrace>true</DefineTrace>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<BuildScriptName>$(MSBuildProjectName).sql</BuildScriptName>
|
||||||
|
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<DefineDebug>true</DefineDebug>
|
||||||
|
<DefineTrace>true</DefineTrace>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">11.0</VisualStudioVersion>
|
||||||
|
<!-- Default to the v11.0 targets path if the targets file for the current VS version is not found -->
|
||||||
|
<SSDTExists Condition="Exists('$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\SSDT\Microsoft.Data.Tools.Schema.SqlTasks.targets')">True</SSDTExists>
|
||||||
|
<VisualStudioVersion Condition="'$(SSDTExists)' == ''">11.0</VisualStudioVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Condition="'$(SQLDBExtensionsRefPath)' != ''" Project="$(SQLDBExtensionsRefPath)\Microsoft.Data.Tools.Schema.SqlTasks.targets" />
|
||||||
|
<Import Condition="'$(SQLDBExtensionsRefPath)' == ''" Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\SSDT\Microsoft.Data.Tools.Schema.SqlTasks.targets" />
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="Properties" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Build Include="Loan.sql" />
|
||||||
|
<Build Include="LoanAudit.sql" />
|
||||||
|
<Build Include="LoanType.sql" />
|
||||||
|
<Build Include="Import.sql" />
|
||||||
|
<Build Include="Dealer.sql" />
|
||||||
|
<Build Include="Vehicle.sql" />
|
||||||
|
<Build Include="MinorAccountType.sql" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="ReserveManagementSystem.publish.xml" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PostDeploy Include="Script.PostDeploymentPopulateLoanTypeTable.sql" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PreDeploy Include="Script.PreDeploymentTruncateLoanTypes.sql" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<RefactorLog Include="ReserveManagementSystemApi.Sql.refactorlog" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
Post-Deployment Script Template
|
||||||
|
--------------------------------------------------------------------------------------
|
||||||
|
This file contains SQL statements that will be appended to the build script.
|
||||||
|
Use SQLCMD syntax to include a file in the post-deployment script.
|
||||||
|
Example: :r .\myfile.sql
|
||||||
|
Use SQLCMD syntax to reference a variable in the post-deployment script.
|
||||||
|
Example: :setvar TableName MyTable
|
||||||
|
SELECT * FROM [$(TableName)]
|
||||||
|
--------------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
USE [ReserveManagementSystem]
|
||||||
|
GO
|
||||||
|
|
||||||
|
INSERT INTO [dbo].[LoanType] (LoanTypeId, LoanComment, ChargebackMethod, NoChargebackDays, NoChargebackPayments, ReserveDiscount, FlatFeePercent, NoReserveThreshold) VALUES ('BB', 'Standard Loan', 'S', 0, 0, 0.00, 1.00, 0.25)
|
||||||
|
INSERT INTO [dbo].[LoanType] (LoanTypeId, LoanComment, ChargebackMethod, NoChargebackDays, NoChargebackPayments, ReserveDiscount, FlatFeePercent, NoReserveThreshold) VALUES ('NC', '75% Reserve Paid - No charge back- after 90 Days', 'N', 90, 3, 25.00, 1.00, 0.25)
|
||||||
|
INSERT INTO [dbo].[LoanType] (LoanTypeId, LoanComment, ChargebackMethod, NoChargebackDays, NoChargebackPayments, ReserveDiscount, FlatFeePercent, NoReserveThreshold) VALUES ('NR', 'No reserve to be paid', 'N', 0, 0, 0.00, 0.00, 0.25)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
USE [ReserveManagementSystem]
|
||||||
|
GO
|
||||||
|
IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'LoanType')
|
||||||
|
BEGIN
|
||||||
|
TRUNCATE TABLE [dbo].[LoanType];
|
||||||
|
END
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
CREATE TABLE [dbo].[Vehicle]
|
||||||
|
(
|
||||||
|
[VehicleId] INT NOT NULL IDENTITY,
|
||||||
|
[LoanId] INT NULL,
|
||||||
|
[VINNumber] VARCHAR(30) NULL,
|
||||||
|
[Make] VARCHAR(30) NULL,
|
||||||
|
[Model] VARCHAR(30) NULL,
|
||||||
|
[Year] VARCHAR(4) NULL,
|
||||||
|
[Mileage] FLOAT NULL,
|
||||||
|
[Color] VARCHAR(30) NULL,
|
||||||
|
CONSTRAINT [PK_Vehicle] PRIMARY KEY (VehicleId)
|
||||||
|
)
|
||||||
+28
@@ -0,0 +1,28 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="5.0.12" />
|
||||||
|
<PackageReference Include="Moq" Version="4.16.1" />
|
||||||
|
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||||
|
<PackageReference Include="NUnit3TestAdapter" Version="3.16.1" />
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
|
||||||
|
<PackageReference Include="xunit" Version="2.4.1" />
|
||||||
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\ReserveManagementSystemApi\ReserveManagementSystemApi.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
+780
@@ -0,0 +1,780 @@
|
|||||||
|
using Moq;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Xunit;
|
||||||
|
using LCU.Library.Internal.CoreApiWrapperModel.CoreModels.CoreRequests;
|
||||||
|
using LCU.Library.Internal.CoreApiWrapperModel.CoreModels.Transaction;
|
||||||
|
using ReserveManagementSystemApi.Helpers;
|
||||||
|
using ReserveManagementSystemApi.Mappers;
|
||||||
|
using ReserveManagementSystemApi.ServiceClients;
|
||||||
|
using ReserveManagementSystemApi.Services;
|
||||||
|
using ReserveManagementSystemLib.Configuration;
|
||||||
|
using ReserveManagementSystemLib.Models;
|
||||||
|
using ReserveManagementSystemLib.Repositories;
|
||||||
|
using ReserveManagementSystemLib.Persistence;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi.Test.Service
|
||||||
|
{
|
||||||
|
public class ExportServiceTest
|
||||||
|
{
|
||||||
|
private ExportService _exportService;
|
||||||
|
private Mock<ICoreApiServiceClient> _mockCoreApiServiceClient;
|
||||||
|
private Mock<IMinorAccountTypeRepository> _mockMinorAccountRepository;
|
||||||
|
private Mock<RmsApiConfiguration> _mockConfiguration;
|
||||||
|
private AppDbContext _appDbContext;
|
||||||
|
private ILoanRepository _loanRepository;
|
||||||
|
|
||||||
|
public ExportServiceTest()
|
||||||
|
{
|
||||||
|
_mockCoreApiServiceClient = new Mock<ICoreApiServiceClient>();
|
||||||
|
_mockMinorAccountRepository = new Mock<IMinorAccountTypeRepository>();
|
||||||
|
_mockConfiguration = new Mock<RmsApiConfiguration>();
|
||||||
|
|
||||||
|
var options = new DbContextOptionsBuilder<AppDbContext>()
|
||||||
|
.UseInMemoryDatabase(Guid.NewGuid().ToString())
|
||||||
|
.Options;
|
||||||
|
_appDbContext = new AppDbContext(options);
|
||||||
|
|
||||||
|
_loanRepository = new LoanRepository(_appDbContext);
|
||||||
|
_mockConfiguration.Object.DefaultBatchSize = 100;
|
||||||
|
_mockConfiguration.Object.DefaultImportStartDate = "2021-07-01 00:00:00";
|
||||||
|
_mockConfiguration.Object.DefaultConvertedLoanPostDate = "2021-10-31";
|
||||||
|
|
||||||
|
_exportService = new ExportService(_loanRepository, _mockCoreApiServiceClient.Object, _mockMinorAccountRepository.Object, _mockConfiguration.Object);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task SendExportChargebacksAsyncTest_OK()
|
||||||
|
{
|
||||||
|
var loan = new Loan();
|
||||||
|
|
||||||
|
loan.ExportedChargebackDate = null;
|
||||||
|
loan.PaidLoanDate = Convert.ToDateTime("2021-11-01");
|
||||||
|
loan.LoanNumber = "1111100000";
|
||||||
|
loan.LoanId = 1;
|
||||||
|
loan.DealerOrganizationNumber = "15500";
|
||||||
|
loan.AccountType = "DL01";
|
||||||
|
|
||||||
|
loan.Dealer = new Dealer()
|
||||||
|
{
|
||||||
|
DealerAccountNumber = "7788888",
|
||||||
|
DealerOrganizationNumber = "15500"
|
||||||
|
};
|
||||||
|
|
||||||
|
loan.Adjustment = 0;
|
||||||
|
loan.ChargeBack = (decimal)22.00;
|
||||||
|
|
||||||
|
var account = new MinorAccountType()
|
||||||
|
{
|
||||||
|
MinorAccountTypeId = 1,
|
||||||
|
GeneralLedgerAccountNumber = "11111111",
|
||||||
|
AccountType = "DL01"
|
||||||
|
};
|
||||||
|
|
||||||
|
_loanRepository.Add(loan);
|
||||||
|
_mockMinorAccountRepository.Setup(repo => repo.GetMinorAccountType("DL01")).Returns(account);
|
||||||
|
|
||||||
|
var result = ExportMapper.MapLoanToIndirectLoanForChargeback(loan, account);
|
||||||
|
|
||||||
|
var groupedList = new List<GroupedMonetaryTransactionRequest> { result };
|
||||||
|
|
||||||
|
var response = new MonetaryTransactionResponse()
|
||||||
|
{
|
||||||
|
WasSuccessful = true
|
||||||
|
};
|
||||||
|
|
||||||
|
var listResponse = new List<MonetaryTransactionResponse> { response };
|
||||||
|
var resultBatch = BatchHelper.CreateBatch(groupedList, _mockConfiguration.Object.DefaultBatchSize);
|
||||||
|
|
||||||
|
List<GroupedMonetaryTransactionRequest> batchList = new List<GroupedMonetaryTransactionRequest>(resultBatch.FirstOrDefault());
|
||||||
|
|
||||||
|
_mockCoreApiServiceClient.Setup(x => x.PostMonetaryTransactions(batchList)).Returns(Task.FromResult(listResponse)).Verifiable();
|
||||||
|
|
||||||
|
var numberOfLoansUpdatedSuccessfully = await _exportService.SendBatchListMonetaryTransactionRequests(groupedList);
|
||||||
|
var success = numberOfLoansUpdatedSuccessfully[0].WasSuccessful.ToString();
|
||||||
|
|
||||||
|
Assert.True(true, success);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region "Unit tests for Chargeback rounding"
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task MappedExportRoundedUpChargebackAsyncTest_OK()
|
||||||
|
{
|
||||||
|
var loan = new Loan();
|
||||||
|
loan.ExportedReserveDate = null;
|
||||||
|
loan.ExportedChargebackDate = null;
|
||||||
|
loan.LoanNumber = "1111100000";
|
||||||
|
loan.LoanId = 1;
|
||||||
|
loan.DealerOrganizationNumber = "15500";
|
||||||
|
loan.AccountType = "DL01";
|
||||||
|
|
||||||
|
loan.Dealer = new Dealer()
|
||||||
|
{
|
||||||
|
DealerAccountNumber = "7788888",
|
||||||
|
DealerOrganizationNumber = "15500"
|
||||||
|
};
|
||||||
|
|
||||||
|
var account = new MinorAccountType()
|
||||||
|
{
|
||||||
|
MinorAccountTypeId = 1,
|
||||||
|
GeneralLedgerAccountNumber = "11111111",
|
||||||
|
AccountType = "DL01"
|
||||||
|
};
|
||||||
|
|
||||||
|
loan.Adjustment = 0;
|
||||||
|
loan.ChargeBack = (decimal)502.525;
|
||||||
|
|
||||||
|
var result = ExportMapper.MapLoanToIndirectLoanForChargeback(loan, account);
|
||||||
|
|
||||||
|
var groupedList = new List<GroupedMonetaryTransactionRequest> { result };
|
||||||
|
|
||||||
|
var resultBatch = BatchHelper.CreateBatch(groupedList, _mockConfiguration.Object.DefaultBatchSize);
|
||||||
|
|
||||||
|
List<GroupedMonetaryTransactionRequest> batchList = new List<GroupedMonetaryTransactionRequest>(resultBatch.FirstOrDefault());
|
||||||
|
|
||||||
|
Assert.Equal(-502.53, batchList[0].MonetaryTransactionRequests[1].TransactionAmount);
|
||||||
|
Assert.Equal("ChrgBk-1111100000", batchList[0].MonetaryTransactionRequests[1].Description);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task MappedExportRoundedDownChargebackAsyncTest_OK()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
var loan = new Loan();
|
||||||
|
loan.ExportedReserveDate = null;
|
||||||
|
loan.ExportedChargebackDate = null;
|
||||||
|
loan.LoanNumber = "2411000009999";
|
||||||
|
loan.LoanId = 1;
|
||||||
|
loan.DealerOrganizationNumber = "15500";
|
||||||
|
loan.AccountType = "DL01";
|
||||||
|
|
||||||
|
loan.Dealer = new Dealer()
|
||||||
|
{
|
||||||
|
DealerAccountNumber = "7788888",
|
||||||
|
DealerOrganizationNumber = "15500"
|
||||||
|
};
|
||||||
|
|
||||||
|
var account = new MinorAccountType()
|
||||||
|
{
|
||||||
|
MinorAccountTypeId = 1,
|
||||||
|
GeneralLedgerAccountNumber = "11111111",
|
||||||
|
AccountType = "DL01"
|
||||||
|
};
|
||||||
|
|
||||||
|
loan.Adjustment = 0;
|
||||||
|
loan.ChargeBack = (decimal)38.171850;
|
||||||
|
|
||||||
|
var result = ExportMapper.MapLoanToIndirectLoanForChargeback(loan, account);
|
||||||
|
|
||||||
|
var groupedList = new List<GroupedMonetaryTransactionRequest> { result };
|
||||||
|
|
||||||
|
var resultBatch = BatchHelper.CreateBatch(groupedList, _mockConfiguration.Object.DefaultBatchSize);
|
||||||
|
|
||||||
|
List<GroupedMonetaryTransactionRequest> batchList = new List<GroupedMonetaryTransactionRequest>(resultBatch.FirstOrDefault());
|
||||||
|
|
||||||
|
Assert.Equal(-38.17, batchList[0].MonetaryTransactionRequests[1].TransactionAmount);
|
||||||
|
Assert.Equal("ChrgBk-2411000009999", batchList[0].MonetaryTransactionRequests[1].Description);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region "Unit tests for Reserve rounding"
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void MappedExportRoundedUpReserveAsyncTest1_OK()
|
||||||
|
{
|
||||||
|
var loan = new Loan();
|
||||||
|
loan.ExportedReserveDate = null;
|
||||||
|
loan.ExportedChargebackDate = null;
|
||||||
|
loan.LoanNumber = "1111100000";
|
||||||
|
loan.LoanId = 1;
|
||||||
|
loan.DealerOrganizationNumber = "15500";
|
||||||
|
loan.AccountType = "DL01";
|
||||||
|
|
||||||
|
loan.Dealer = new Dealer()
|
||||||
|
{
|
||||||
|
DealerAccountNumber = "7788888",
|
||||||
|
DealerOrganizationNumber = "15500"
|
||||||
|
};
|
||||||
|
|
||||||
|
loan.Adjustment = 0;
|
||||||
|
loan.ReserveAmount = (decimal)502.525;
|
||||||
|
|
||||||
|
var result = ExportMapper.MapLoanToIndirectLoanForReserve(loan);
|
||||||
|
|
||||||
|
var groupedList = new List<GroupedMonetaryTransactionRequest> { result };
|
||||||
|
|
||||||
|
var resultBatch = BatchHelper.CreateBatch(groupedList, _mockConfiguration.Object.DefaultBatchSize);
|
||||||
|
|
||||||
|
List<GroupedMonetaryTransactionRequest> batchList = new List<GroupedMonetaryTransactionRequest>(resultBatch.FirstOrDefault());
|
||||||
|
|
||||||
|
//in order to test reserve rounding set the reserves and adjustments accordingly.
|
||||||
|
Assert.Equal(-502.53, batchList[0].MonetaryTransactionRequests[0].TransactionAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void MappedExportRoundedUpReserveAsyncTest2_OK()
|
||||||
|
{
|
||||||
|
var loan = new Loan();
|
||||||
|
loan.ExportedReserveDate = null;
|
||||||
|
loan.ExportedChargebackDate = null;
|
||||||
|
loan.LoanNumber = "1111100000";
|
||||||
|
loan.LoanId = 1;
|
||||||
|
loan.DealerOrganizationNumber = "15500";
|
||||||
|
loan.AccountType = "DL01";
|
||||||
|
|
||||||
|
loan.Dealer = new Dealer()
|
||||||
|
{
|
||||||
|
DealerAccountNumber = "7788888",
|
||||||
|
DealerOrganizationNumber = "15500"
|
||||||
|
};
|
||||||
|
|
||||||
|
loan.Adjustment = 0;
|
||||||
|
loan.ReserveAmount = (decimal)1237.715;
|
||||||
|
|
||||||
|
var result = ExportMapper.MapLoanToIndirectLoanForReserve(loan);
|
||||||
|
|
||||||
|
var groupedList = new List<GroupedMonetaryTransactionRequest> { result };
|
||||||
|
|
||||||
|
var resultBatch = BatchHelper.CreateBatch(groupedList, _mockConfiguration.Object.DefaultBatchSize);
|
||||||
|
|
||||||
|
List<GroupedMonetaryTransactionRequest> batchList = new List<GroupedMonetaryTransactionRequest>(resultBatch.FirstOrDefault());
|
||||||
|
|
||||||
|
//in order to test reserve rounding set the reserves and adjustments accordingly.
|
||||||
|
Assert.Equal(-1237.72, batchList[0].MonetaryTransactionRequests[0].TransactionAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task MappedExportRoundedUpReserveAsyncTest3_OK()
|
||||||
|
{
|
||||||
|
var loan = new Loan();
|
||||||
|
loan.ExportedReserveDate = null;
|
||||||
|
loan.ExportedChargebackDate = null;
|
||||||
|
loan.LoanNumber = "1111100000";
|
||||||
|
loan.LoanId = 1;
|
||||||
|
loan.DealerOrganizationNumber = "15500";
|
||||||
|
loan.AccountType = "DL01";
|
||||||
|
|
||||||
|
loan.Dealer = new Dealer()
|
||||||
|
{
|
||||||
|
DealerAccountNumber = "7788888",
|
||||||
|
DealerOrganizationNumber = "15500"
|
||||||
|
};
|
||||||
|
|
||||||
|
loan.Adjustment = 0;
|
||||||
|
loan.ReserveAmount = (decimal)1439.675;
|
||||||
|
|
||||||
|
var result = ExportMapper.MapLoanToIndirectLoanForReserve(loan);
|
||||||
|
|
||||||
|
var groupedList = new List<GroupedMonetaryTransactionRequest> { result };
|
||||||
|
|
||||||
|
var resultBatch = BatchHelper.CreateBatch(groupedList, _mockConfiguration.Object.DefaultBatchSize);
|
||||||
|
|
||||||
|
List<GroupedMonetaryTransactionRequest> batchList = new List<GroupedMonetaryTransactionRequest>(resultBatch.FirstOrDefault());
|
||||||
|
|
||||||
|
//in order to test reserve rounding set the reserves and adjustments accordingly.
|
||||||
|
Assert.Equal(-1439.68, batchList[0].MonetaryTransactionRequests[0].TransactionAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task MappedExportRoundedDownReserveAsyncTest1_OK()
|
||||||
|
{
|
||||||
|
var loan = new Loan();
|
||||||
|
loan.ExportedReserveDate = null;
|
||||||
|
loan.ExportedChargebackDate = null;
|
||||||
|
loan.LoanNumber = "1111100000";
|
||||||
|
loan.LoanId = 1;
|
||||||
|
loan.DealerOrganizationNumber = "15500";
|
||||||
|
loan.AccountType = "DL01";
|
||||||
|
|
||||||
|
loan.Dealer = new Dealer()
|
||||||
|
{
|
||||||
|
DealerAccountNumber = "7788888",
|
||||||
|
DealerOrganizationNumber = "15500"
|
||||||
|
};
|
||||||
|
|
||||||
|
loan.Adjustment = 0;
|
||||||
|
loan.ReserveAmount = (decimal)1982.1045;
|
||||||
|
|
||||||
|
var result = ExportMapper.MapLoanToIndirectLoanForReserve(loan);
|
||||||
|
|
||||||
|
var groupedList = new List<GroupedMonetaryTransactionRequest> { result };
|
||||||
|
|
||||||
|
var resultBatch = BatchHelper.CreateBatch(groupedList, _mockConfiguration.Object.DefaultBatchSize);
|
||||||
|
|
||||||
|
List<GroupedMonetaryTransactionRequest> batchList = new List<GroupedMonetaryTransactionRequest>(resultBatch.FirstOrDefault());
|
||||||
|
|
||||||
|
//in order to test reserve rounding set the reserves and adjustments accordingly.
|
||||||
|
Assert.Equal(-1982.10, batchList[0].MonetaryTransactionRequests[0].TransactionAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task MappedExportRoundedDownReserveAsyncTest2_OK()
|
||||||
|
|
||||||
|
{
|
||||||
|
var loan = new Loan();
|
||||||
|
loan.ExportedReserveDate = null;
|
||||||
|
loan.ExportedChargebackDate = null;
|
||||||
|
loan.LoanNumber = "1111100000";
|
||||||
|
loan.LoanId = 1;
|
||||||
|
loan.DealerOrganizationNumber = "15500";
|
||||||
|
loan.AccountType = "DL01";
|
||||||
|
|
||||||
|
loan.Dealer = new Dealer()
|
||||||
|
{
|
||||||
|
DealerAccountNumber = "7788888",
|
||||||
|
DealerOrganizationNumber = "15500"
|
||||||
|
};
|
||||||
|
|
||||||
|
loan.Adjustment = 0;
|
||||||
|
loan.ReserveAmount = (decimal)1803.52449;
|
||||||
|
|
||||||
|
var result = ExportMapper.MapLoanToIndirectLoanForReserve(loan);
|
||||||
|
|
||||||
|
var groupedList = new List<GroupedMonetaryTransactionRequest> { result };
|
||||||
|
|
||||||
|
var resultBatch = BatchHelper.CreateBatch(groupedList, _mockConfiguration.Object.DefaultBatchSize);
|
||||||
|
|
||||||
|
List<GroupedMonetaryTransactionRequest> batchList = new List<GroupedMonetaryTransactionRequest>(resultBatch.FirstOrDefault());
|
||||||
|
|
||||||
|
//in order to test reserve rounding set the reserves and adjustments accordingly.
|
||||||
|
Assert.Equal(-1803.52, batchList[0].MonetaryTransactionRequests[0].TransactionAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task MappedExportRoundedDownReserveAsyncTest3_OK()
|
||||||
|
|
||||||
|
{
|
||||||
|
var loan = new Loan();
|
||||||
|
loan.ExportedReserveDate = null;
|
||||||
|
loan.ExportedChargebackDate = null;
|
||||||
|
loan.LoanNumber = "1111100000";
|
||||||
|
loan.LoanId = 1;
|
||||||
|
loan.DealerOrganizationNumber = "15500";
|
||||||
|
loan.AccountType = "DL01";
|
||||||
|
|
||||||
|
loan.Dealer = new Dealer()
|
||||||
|
{
|
||||||
|
DealerAccountNumber = "7788888",
|
||||||
|
DealerOrganizationNumber = "15500"
|
||||||
|
};
|
||||||
|
|
||||||
|
loan.Adjustment = 0;
|
||||||
|
loan.ReserveAmount = (decimal)38.171850;
|
||||||
|
|
||||||
|
var result = ExportMapper.MapLoanToIndirectLoanForReserve(loan);
|
||||||
|
|
||||||
|
var groupedList = new List<GroupedMonetaryTransactionRequest> { result };
|
||||||
|
|
||||||
|
var resultBatch = BatchHelper.CreateBatch(groupedList, _mockConfiguration.Object.DefaultBatchSize);
|
||||||
|
|
||||||
|
List<GroupedMonetaryTransactionRequest> batchList = new List<GroupedMonetaryTransactionRequest>(resultBatch.FirstOrDefault());
|
||||||
|
|
||||||
|
//in order to test reserve rounding set the reserves and adjustments accordingly.
|
||||||
|
Assert.Equal(-38.17, batchList[0].MonetaryTransactionRequests[0].TransactionAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task MappedExportRoundedDownTenThousandthReserveAsyncTest1_OK()
|
||||||
|
{
|
||||||
|
var loan = new Loan();
|
||||||
|
loan.ExportedReserveDate = null;
|
||||||
|
loan.ExportedChargebackDate = null;
|
||||||
|
loan.LoanNumber = "1111100000";
|
||||||
|
loan.LoanId = 1;
|
||||||
|
loan.DealerOrganizationNumber = "15500";
|
||||||
|
loan.AccountType = "DL01";
|
||||||
|
|
||||||
|
loan.Dealer = new Dealer()
|
||||||
|
{
|
||||||
|
DealerAccountNumber = "7788888",
|
||||||
|
DealerOrganizationNumber = "15500"
|
||||||
|
};
|
||||||
|
|
||||||
|
loan.Adjustment = 0;
|
||||||
|
loan.ReserveAmount = (decimal)4240.9217;
|
||||||
|
|
||||||
|
var result = ExportMapper.MapLoanToIndirectLoanForReserve(loan);
|
||||||
|
|
||||||
|
var groupedList = new List<GroupedMonetaryTransactionRequest> { result };
|
||||||
|
|
||||||
|
var resultBatch = BatchHelper.CreateBatch(groupedList, _mockConfiguration.Object.DefaultBatchSize);
|
||||||
|
|
||||||
|
List<GroupedMonetaryTransactionRequest> batchList = new List<GroupedMonetaryTransactionRequest>(resultBatch.FirstOrDefault());
|
||||||
|
|
||||||
|
//in order to test reserve rounding set the reserves and adjustments accordingly.
|
||||||
|
Assert.Equal(-4240.92, batchList[0].MonetaryTransactionRequests[0].TransactionAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task MappedExportRoundedDownTenThousandthReserveAsyncTest2_OK()
|
||||||
|
{
|
||||||
|
var loan = new Loan();
|
||||||
|
loan.ExportedReserveDate = null;
|
||||||
|
loan.ExportedChargebackDate = null;
|
||||||
|
loan.LoanNumber = "1111100000";
|
||||||
|
loan.LoanId = 1;
|
||||||
|
loan.DealerOrganizationNumber = "15500";
|
||||||
|
loan.AccountType = "DL01";
|
||||||
|
|
||||||
|
loan.Dealer = new Dealer()
|
||||||
|
{
|
||||||
|
DealerAccountNumber = "7788888",
|
||||||
|
DealerOrganizationNumber = "15500"
|
||||||
|
};
|
||||||
|
|
||||||
|
loan.Adjustment = 0;
|
||||||
|
loan.ReserveAmount = (decimal)397.2345;
|
||||||
|
|
||||||
|
var result = ExportMapper.MapLoanToIndirectLoanForReserve(loan);
|
||||||
|
|
||||||
|
var groupedList = new List<GroupedMonetaryTransactionRequest> { result };
|
||||||
|
|
||||||
|
var resultBatch = BatchHelper.CreateBatch(groupedList, _mockConfiguration.Object.DefaultBatchSize);
|
||||||
|
|
||||||
|
List<GroupedMonetaryTransactionRequest> batchList = new List<GroupedMonetaryTransactionRequest>(resultBatch.FirstOrDefault());
|
||||||
|
|
||||||
|
//in order to test reserve rounding set the reserves and adjustments accordingly.
|
||||||
|
Assert.Equal(-397.23, batchList[0].MonetaryTransactionRequests[0].TransactionAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task MappedExportRoundedDownTenThousandthReserveAsyncTest3_OK()
|
||||||
|
{
|
||||||
|
var loan = new Loan();
|
||||||
|
loan.ExportedReserveDate = null;
|
||||||
|
loan.ExportedChargebackDate = null;
|
||||||
|
loan.LoanNumber = "1111100000";
|
||||||
|
loan.LoanId = 1;
|
||||||
|
loan.DealerOrganizationNumber = "15500";
|
||||||
|
loan.AccountType = "DL01";
|
||||||
|
|
||||||
|
loan.Dealer = new Dealer()
|
||||||
|
{
|
||||||
|
DealerAccountNumber = "7788888",
|
||||||
|
DealerOrganizationNumber = "15500"
|
||||||
|
};
|
||||||
|
|
||||||
|
loan.Adjustment = 0;
|
||||||
|
loan.ReserveAmount = (decimal)434.9949;
|
||||||
|
|
||||||
|
var result = ExportMapper.MapLoanToIndirectLoanForReserve(loan);
|
||||||
|
|
||||||
|
var groupedList = new List<GroupedMonetaryTransactionRequest> { result };
|
||||||
|
|
||||||
|
var resultBatch = BatchHelper.CreateBatch(groupedList, _mockConfiguration.Object.DefaultBatchSize);
|
||||||
|
|
||||||
|
List<GroupedMonetaryTransactionRequest> batchList = new List<GroupedMonetaryTransactionRequest>(resultBatch.FirstOrDefault());
|
||||||
|
|
||||||
|
//in order to test reserve rounding set the reserves and adjustments accordingly.
|
||||||
|
Assert.Equal(-434.99, batchList[0].MonetaryTransactionRequests[0].TransactionAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task MappedExportRoundedDownTenThousandthReserveAsyncTest4_OK()
|
||||||
|
{
|
||||||
|
var loan = new Loan();
|
||||||
|
loan.ExportedReserveDate = null;
|
||||||
|
loan.ExportedChargebackDate = null;
|
||||||
|
loan.LoanNumber = "1111100000";
|
||||||
|
loan.LoanId = 1;
|
||||||
|
loan.DealerOrganizationNumber = "15500";
|
||||||
|
loan.AccountType = "DL01";
|
||||||
|
|
||||||
|
loan.Dealer = new Dealer()
|
||||||
|
{
|
||||||
|
DealerAccountNumber = "7788888",
|
||||||
|
DealerOrganizationNumber = "15500"
|
||||||
|
};
|
||||||
|
|
||||||
|
loan.Adjustment = 0;
|
||||||
|
loan.ReserveAmount = (decimal)1513.1451;
|
||||||
|
|
||||||
|
var result = ExportMapper.MapLoanToIndirectLoanForReserve(loan);
|
||||||
|
|
||||||
|
var groupedList = new List<GroupedMonetaryTransactionRequest> { result };
|
||||||
|
|
||||||
|
var resultBatch = BatchHelper.CreateBatch(groupedList, _mockConfiguration.Object.DefaultBatchSize);
|
||||||
|
|
||||||
|
List<GroupedMonetaryTransactionRequest> batchList = new List<GroupedMonetaryTransactionRequest>(resultBatch.FirstOrDefault());
|
||||||
|
|
||||||
|
//in order to test reserve rounding set the reserves and adjustments accordingly.
|
||||||
|
Assert.Equal(-1513.15, batchList[0].MonetaryTransactionRequests[0].TransactionAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task MappedExportRoundedDownTenThousandthReserveAsyncTest5_OK()
|
||||||
|
{
|
||||||
|
var loan = new Loan();
|
||||||
|
loan.ExportedReserveDate = null;
|
||||||
|
loan.ExportedChargebackDate = null;
|
||||||
|
loan.LoanNumber = "1111100000";
|
||||||
|
loan.LoanId = 1;
|
||||||
|
loan.DealerOrganizationNumber = "15500";
|
||||||
|
loan.AccountType = "DL01";
|
||||||
|
|
||||||
|
loan.Dealer = new Dealer()
|
||||||
|
{
|
||||||
|
DealerAccountNumber = "7788888",
|
||||||
|
DealerOrganizationNumber = "15500"
|
||||||
|
};
|
||||||
|
|
||||||
|
loan.Adjustment = 0;
|
||||||
|
loan.ReserveAmount = (decimal)4240.9247;
|
||||||
|
|
||||||
|
var result = ExportMapper.MapLoanToIndirectLoanForReserve(loan);
|
||||||
|
|
||||||
|
var groupedList = new List<GroupedMonetaryTransactionRequest> { result };
|
||||||
|
|
||||||
|
var resultBatch = BatchHelper.CreateBatch(groupedList, _mockConfiguration.Object.DefaultBatchSize);
|
||||||
|
|
||||||
|
List<GroupedMonetaryTransactionRequest> batchList = new List<GroupedMonetaryTransactionRequest>(resultBatch.FirstOrDefault());
|
||||||
|
|
||||||
|
//in order to test reserve rounding set the reserves and adjustments accordingly.
|
||||||
|
Assert.Equal(-4240.92, batchList[0].MonetaryTransactionRequests[0].TransactionAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task MappedExportRoundedUpTenThousandthReserveAsyncTest1_OK()
|
||||||
|
{
|
||||||
|
var loan = new Loan();
|
||||||
|
loan.ExportedReserveDate = null;
|
||||||
|
loan.ExportedChargebackDate = null;
|
||||||
|
loan.LoanNumber = "1111100000";
|
||||||
|
loan.LoanId = 1;
|
||||||
|
loan.DealerOrganizationNumber = "15500";
|
||||||
|
loan.AccountType = "DL01";
|
||||||
|
|
||||||
|
loan.Dealer = new Dealer()
|
||||||
|
{
|
||||||
|
DealerAccountNumber = "7788888",
|
||||||
|
DealerOrganizationNumber = "15500"
|
||||||
|
};
|
||||||
|
|
||||||
|
loan.Adjustment = 0;
|
||||||
|
loan.ReserveAmount = (decimal)1513.154999; //value that would be written to DB is 1513.155
|
||||||
|
|
||||||
|
var result = ExportMapper.MapLoanToIndirectLoanForReserve(loan);
|
||||||
|
|
||||||
|
var groupedList = new List<GroupedMonetaryTransactionRequest> { result };
|
||||||
|
|
||||||
|
var resultBatch = BatchHelper.CreateBatch(groupedList, _mockConfiguration.Object.DefaultBatchSize);
|
||||||
|
|
||||||
|
List<GroupedMonetaryTransactionRequest> batchList = new List<GroupedMonetaryTransactionRequest>(resultBatch.FirstOrDefault());
|
||||||
|
|
||||||
|
//in order to test reserve rounding set the reserves and adjustments accordingly.
|
||||||
|
Assert.Equal(-1513.16, batchList[0].MonetaryTransactionRequests[0].TransactionAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region "Unit tests for reserve rounding with adjustments"
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task MappedExportRoundedDownReserveAdjustmentAsyncTest_OK()
|
||||||
|
{
|
||||||
|
var loan = new Loan();
|
||||||
|
loan.ExportedReserveDate = null;
|
||||||
|
loan.ExportedChargebackDate = null;
|
||||||
|
loan.LoanNumber = "1111100000";
|
||||||
|
loan.LoanId = 1;
|
||||||
|
loan.DealerOrganizationNumber = "15500";
|
||||||
|
loan.AccountType = "DL01";
|
||||||
|
|
||||||
|
loan.Dealer = new Dealer()
|
||||||
|
{
|
||||||
|
DealerAccountNumber = "7788888",
|
||||||
|
DealerOrganizationNumber = "15500"
|
||||||
|
};
|
||||||
|
|
||||||
|
var adjustmentCalculation = (decimal)(1513.154999 - 1803.4656); //1513.16 - 1803.47
|
||||||
|
|
||||||
|
loan.Adjustment = (decimal)adjustmentCalculation;
|
||||||
|
loan.ReserveAmount = (decimal)1513.155; //as saved in DB
|
||||||
|
|
||||||
|
var result = ExportMapper.MapLoanToIndirectLoanForReserve(loan);
|
||||||
|
|
||||||
|
var groupedList = new List<GroupedMonetaryTransactionRequest> { result };
|
||||||
|
|
||||||
|
var resultBatch = BatchHelper.CreateBatch(groupedList, _mockConfiguration.Object.DefaultBatchSize);
|
||||||
|
|
||||||
|
List<GroupedMonetaryTransactionRequest> batchList = new List<GroupedMonetaryTransactionRequest>(resultBatch.FirstOrDefault());
|
||||||
|
|
||||||
|
//in order to test adjustment to the reserve rounding set the reserves and adjustments accordingly.
|
||||||
|
Assert.Equal(290.31, batchList[0].MonetaryTransactionRequests[0].TransactionAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task MappedExportRoundedDownTenThousandthReserveAdjustmentAsyncTest_OK()
|
||||||
|
{
|
||||||
|
var loan = new Loan();
|
||||||
|
loan.ExportedReserveDate = null;
|
||||||
|
loan.ExportedChargebackDate = null;
|
||||||
|
loan.LoanNumber = "1111100000";
|
||||||
|
loan.LoanId = 1;
|
||||||
|
loan.DealerOrganizationNumber = "15500";
|
||||||
|
loan.AccountType = "DL01";
|
||||||
|
|
||||||
|
loan.Dealer = new Dealer()
|
||||||
|
{
|
||||||
|
DealerAccountNumber = "7788888",
|
||||||
|
DealerOrganizationNumber = "15500"
|
||||||
|
};
|
||||||
|
|
||||||
|
var adjustmentCalculation = (decimal)(1513.1489 - 1803.4734); //-290.3245
|
||||||
|
|
||||||
|
loan.Adjustment = (decimal)adjustmentCalculation;
|
||||||
|
loan.ReserveAmount = (decimal)1513.1489; //as saved in DB
|
||||||
|
|
||||||
|
var result = ExportMapper.MapLoanToIndirectLoanForReserve(loan);
|
||||||
|
|
||||||
|
var groupedList = new List<GroupedMonetaryTransactionRequest> { result };
|
||||||
|
|
||||||
|
var resultBatch = BatchHelper.CreateBatch(groupedList, _mockConfiguration.Object.DefaultBatchSize);
|
||||||
|
|
||||||
|
List<GroupedMonetaryTransactionRequest> batchList = new List<GroupedMonetaryTransactionRequest>(resultBatch.FirstOrDefault());
|
||||||
|
|
||||||
|
//in order to test adjustment to the reserve rounding set the reserves and adjustments accordingly.
|
||||||
|
Assert.Equal(290.32, batchList[0].MonetaryTransactionRequests[0].TransactionAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task MappedExportRoundedUpHundredThousandthReserveAdjustmentAsyncTest_OK()
|
||||||
|
{
|
||||||
|
var loan = new Loan();
|
||||||
|
loan.ExportedReserveDate = null;
|
||||||
|
loan.ExportedChargebackDate = null;
|
||||||
|
loan.LoanNumber = "1111100000";
|
||||||
|
loan.LoanId = 1;
|
||||||
|
loan.DealerOrganizationNumber = "15500";
|
||||||
|
loan.AccountType = "DL01";
|
||||||
|
|
||||||
|
loan.Dealer = new Dealer()
|
||||||
|
{
|
||||||
|
DealerAccountNumber = "7788888",
|
||||||
|
DealerOrganizationNumber = "15500"
|
||||||
|
};
|
||||||
|
|
||||||
|
var adjustmentCalculation = (decimal)(1513.145 - 1803.52449); //-290.37949 //Reserve written to DB 1803.5245
|
||||||
|
|
||||||
|
loan.Adjustment = (decimal)adjustmentCalculation;
|
||||||
|
loan.ReserveAmount = (decimal)1513.145; //as saved in DB
|
||||||
|
|
||||||
|
var result = ExportMapper.MapLoanToIndirectLoanForReserve(loan);
|
||||||
|
|
||||||
|
var groupedList = new List<GroupedMonetaryTransactionRequest> { result };
|
||||||
|
|
||||||
|
var resultBatch = BatchHelper.CreateBatch(groupedList, _mockConfiguration.Object.DefaultBatchSize);
|
||||||
|
|
||||||
|
List<GroupedMonetaryTransactionRequest> batchList = new List<GroupedMonetaryTransactionRequest>(resultBatch.FirstOrDefault());
|
||||||
|
|
||||||
|
//in order to test adjustment to the reserve rounding set the reserves and adjustments accordingly.
|
||||||
|
Assert.Equal(290.38, batchList[0].MonetaryTransactionRequests[0].TransactionAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task MappedExportRoundedUpMillionthReserveNegativeOneAdjustmentAsyncTest_OK()
|
||||||
|
{
|
||||||
|
var loan = new Loan();
|
||||||
|
loan.ExportedReserveDate = null;
|
||||||
|
loan.ExportedChargebackDate = null;
|
||||||
|
loan.LoanNumber = "1111100000";
|
||||||
|
loan.LoanId = 1;
|
||||||
|
loan.DealerOrganizationNumber = "15500";
|
||||||
|
loan.AccountType = "DL01";
|
||||||
|
|
||||||
|
loan.Dealer = new Dealer()
|
||||||
|
{
|
||||||
|
DealerAccountNumber = "7788888",
|
||||||
|
DealerOrganizationNumber = "15500"
|
||||||
|
};
|
||||||
|
|
||||||
|
var adjustmentCalculation = (decimal)(39.171450 - 38.171550); //0.999899999999997
|
||||||
|
|
||||||
|
loan.Adjustment = (decimal)adjustmentCalculation;
|
||||||
|
loan.ReserveAmount = (decimal)38.1715; //as saved in DB
|
||||||
|
|
||||||
|
var result = ExportMapper.MapLoanToIndirectLoanForReserve(loan);
|
||||||
|
|
||||||
|
var groupedList = new List<GroupedMonetaryTransactionRequest> { result };
|
||||||
|
|
||||||
|
var resultBatch = BatchHelper.CreateBatch(groupedList, _mockConfiguration.Object.DefaultBatchSize);
|
||||||
|
|
||||||
|
List<GroupedMonetaryTransactionRequest> batchList = new List<GroupedMonetaryTransactionRequest>(resultBatch.FirstOrDefault());
|
||||||
|
|
||||||
|
//in order to test adjustment to the reserve rounding set the reserves and adjustments accordingly.
|
||||||
|
Assert.Equal(-1, batchList[0].MonetaryTransactionRequests[0].TransactionAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task MappedExportRoundedUpMillionthReservePositiveOneAdjustmentAsyncTest_OK()
|
||||||
|
{
|
||||||
|
var loan = new Loan();
|
||||||
|
loan.ExportedReserveDate = null;
|
||||||
|
loan.ExportedChargebackDate = null;
|
||||||
|
loan.LoanNumber = "1111100000";
|
||||||
|
loan.LoanId = 1;
|
||||||
|
loan.DealerOrganizationNumber = "15500";
|
||||||
|
loan.AccountType = "DL01";
|
||||||
|
|
||||||
|
loan.Dealer = new Dealer()
|
||||||
|
{
|
||||||
|
DealerAccountNumber = "7788888",
|
||||||
|
DealerOrganizationNumber = "15500"
|
||||||
|
};
|
||||||
|
|
||||||
|
var adjustmentCalculation = (decimal)(38.171550 - 39.171450); //-0.999899999999997
|
||||||
|
|
||||||
|
loan.Adjustment = (decimal)adjustmentCalculation;
|
||||||
|
loan.ReserveAmount = (decimal)38.1715; //as saved in DB
|
||||||
|
|
||||||
|
var result = ExportMapper.MapLoanToIndirectLoanForReserve(loan);
|
||||||
|
|
||||||
|
var groupedList = new List<GroupedMonetaryTransactionRequest> { result };
|
||||||
|
|
||||||
|
var resultBatch = BatchHelper.CreateBatch(groupedList, _mockConfiguration.Object.DefaultBatchSize);
|
||||||
|
|
||||||
|
List<GroupedMonetaryTransactionRequest> batchList = new List<GroupedMonetaryTransactionRequest>(resultBatch.FirstOrDefault());
|
||||||
|
|
||||||
|
//in order to test adjustment to the reserve rounding set the reserves and adjustments accordingly.
|
||||||
|
Assert.Equal(1, batchList[0].MonetaryTransactionRequests[0].TransactionAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task MappedExportRoundedUpMillionthReserveNoAdjustmentAsyncTest_OK()
|
||||||
|
{
|
||||||
|
var loan = new Loan();
|
||||||
|
loan.ExportedReserveDate = null;
|
||||||
|
loan.ExportedChargebackDate = null;
|
||||||
|
loan.LoanNumber = "1111100000";
|
||||||
|
loan.LoanId = 1;
|
||||||
|
loan.DealerOrganizationNumber = "15500";
|
||||||
|
loan.AccountType = "DL01";
|
||||||
|
|
||||||
|
loan.Dealer = new Dealer()
|
||||||
|
{
|
||||||
|
DealerAccountNumber = "7788888",
|
||||||
|
DealerOrganizationNumber = "15500"
|
||||||
|
};
|
||||||
|
|
||||||
|
var adjustmentCalculation = (decimal)(38.171450 - 38.171850); //-0.000399999999999068
|
||||||
|
|
||||||
|
loan.Adjustment = (decimal)adjustmentCalculation;
|
||||||
|
loan.ReserveAmount = (decimal)38.1719; //as saved in DB
|
||||||
|
|
||||||
|
var result = ExportMapper.MapLoanToIndirectLoanForReserve(loan);
|
||||||
|
|
||||||
|
var groupedList = new List<GroupedMonetaryTransactionRequest> { result };
|
||||||
|
|
||||||
|
var resultBatch = BatchHelper.CreateBatch(groupedList, _mockConfiguration.Object.DefaultBatchSize);
|
||||||
|
|
||||||
|
List<GroupedMonetaryTransactionRequest> batchList = new List<GroupedMonetaryTransactionRequest>(resultBatch.FirstOrDefault());
|
||||||
|
|
||||||
|
//in order to test adjustment to the reserve rounding set the reserves and adjustments accordingly.
|
||||||
|
Assert.Equal(0, batchList[0].MonetaryTransactionRequests[0].TransactionAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
+631
@@ -0,0 +1,631 @@
|
|||||||
|
Feature: Chargeback Calculation
|
||||||
|
Calculate chargeback for a paid loan
|
||||||
|
|
||||||
|
Scenario: NC - Calculate Chargeback for Paid Date is within 15 days of Loan date, 30 days to first payment
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 2/10/2021 | 3/12/2021 | 2/12/2028 | NC | 1206.8106 | 2/19/2021 | 84 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 1206.8106 | Paid On or Before Chargeback Date | 84 |
|
||||||
|
|
||||||
|
#May 11, 2021 vs. May 12, 2021 First Payment Date wins by one day
|
||||||
|
Scenario: NC - Calculate Chargeback for Paid Date is within 15 days of Loan date, 30 days to first payment, Compare Loan Date vs. First Pmt Date, First Pmt Date Wins by 1 day
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 2/10/2021 | 3/12/2021 | 2/12/2028 | NC | 1206.8106 | 2/19/2021 | 84 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 1206.8106 | Paid On or Before Chargeback Date | 84 |
|
||||||
|
|
||||||
|
Scenario: NC - Calculate Chargeback for Paid Date is after 15 days of Loan date, Compare Loan Date vs. First Pmt Date, Loan Date Wins by 1 day
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 2/1/2021 | 2/15/2021 | 2/15/2028 | NC | 1206.8106 | 2/19/2021 | 85 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 1178.7452372093023255813953488 | Paid On or Before Chargeback Date | 84 |
|
||||||
|
|
||||||
|
Scenario: NC - Calculate Chargeback for Paid Date is after 15 days of Loan date, in a different year
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 12/1/2020 | 12/15/2020 | 12/15/2027 | NC | 1206.8106 | 1/19/2021 | 85 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 1151.0100551573187414500683995 | Paid On or Before Chargeback Date | 83 |
|
||||||
|
|
||||||
|
Scenario: NC - Calculate Chargeback for Paid Date is within 15 days of Loan date, 30 days to first payment, Compare Loan Date vs. First Pmt Date, Loan Date Wins by 1 day
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 2/10/2021 | 3/10/2021 | 2/10/2028 | NC | 1206.8106 | 2/19/2021 | 84 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 1206.8106 | Paid On or Before Chargeback Date | 84 |
|
||||||
|
|
||||||
|
Scenario: NC - Calculate Chargeback for Paid Date is after 15 days of Loan date, Compare Loan Date vs. First Pmt Date, Loan Date Wins by 1 day, Leslie's scenario
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 1/15/2019 | 2/14/2019 | 4/14/2025 | NC | 2141.8721 | 4/15/2019 | 75 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 1975.0315364210526315789473684 | Paid On or Before Chargeback Date | 72 |
|
||||||
|
|
||||||
|
Scenario: Calculate Chargeback for Paid Date is within 15 days of Loan date, 30 days to first payment - Missing Loan Type Id
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 2/10/2021 | 3/12/2021 | 2/12/2028 | | 1206.8106 | 2/19/2021 | 84 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 1206.8106 | Paid On or Before Chargeback Date | 84 |
|
||||||
|
|
||||||
|
Scenario: NC - Calculate Chargeback for Paid Date is within 15 days of Loan date, 45 days to first payment
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 10/30/2017 | 12/14/2017 | 11/14/2023 | NC | 927.0989 | 11/6/2017 | 72 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 927.0989 | Paid On or Before Chargeback Date | 72 |
|
||||||
|
|
||||||
|
Scenario: NC - Calculate Chargeback for Paid Date is within 15 days of Loan date, 90 days to first payment
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 10/7/2020 | 1/5/2021 | 12/5/2025 | NC | 229.0637 | 10/21/2020 | 48 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 238.60802083333333333333333333 | Paid On or Before Chargeback Date | 49 |
|
||||||
|
|
||||||
|
Scenario: NC - Calculate Chargeback for Paid Date is exactly 15 days from Loan date, 45 days to first payment
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 12/7/2020 | 1/21/2021 | 12/21/2025 | NC | 878.8602 | 12/22/2020 | 60 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 878.8602 | Paid On or Before Chargeback Date | 60 |
|
||||||
|
|
||||||
|
Scenario: NC - Calculate Chargeback for Paid Date more than 15 days past Loan date but before or on the first payment date, 32 days until first payment date
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 1/28/2021 | 3/1/2021 | 5/1/2027 | NC | 855.6368 | 2/25/2021 | 75 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 833.1200421052631578947368421 | Paid On or Before Chargeback Date | 74 |
|
||||||
|
|
||||||
|
Scenario: NC - Calculate Chargeback for Paid Date more than 15 days past Loan date but before or on the first payment date, 45 days until first payment date
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 10/15/2019 | 11/29/2019 | 10/29/2025 | NC | 1320.8907 | 10/31/2019 | 72 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 1320.8907 | Paid On or Before Chargeback Date | 72 |
|
||||||
|
|
||||||
|
Scenario: NC - Calculate Chargeback for Paid Date more than 15 days past Loan date but before or on the first payment date, 90 days until first payment date
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 12/22/2020 | 3/22/2021 | 2/22/2027 | NC | 1689.8999 | 1/14/2021 | 72 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 1736.8415638888888888888888889 | Paid On or Before Chargeback Date | 73 |
|
||||||
|
|
||||||
|
Scenario: NC - Calculate Chargeback for Paid Date more than 15 days past Loan date but before or on the first payment date, 91 days until first payment date
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 10/26/2018 | 1/25/2019 | 12/25/2024 | NC | 203.7054 | 11/15/2018 | 72 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 209.36388333333333333333333333 | Paid On or Before Chargeback Date | 73 |
|
||||||
|
|
||||||
|
Scenario: NC - Calculate Chargeback for Paid Date more than 15 days past Loan date after the first payment date, over Feb month example to trigger "not a date" condition.
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 3/11/2021 | 4/25/2021 | 3/25/2027 | NC | 309.4481 | 4/30/2021 | 72 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 300.9700698630136986301369863 | Paid On or Before Chargeback Date | 71 |
|
||||||
|
|
||||||
|
Scenario: NC - Calculate Chargeback for Paid Date past the chargeback date - this is day after
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 10/26/2018 | 1/25/2019 | 12/25/2024 | NC | 203.7054 | 3/26/2019 | 72 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 0 | Paid After Chargeback Date | 69 |
|
||||||
|
|
||||||
|
Scenario: NC - Calculate Chargeback for Paid Date past the final payment date
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 10/26/2018 | 1/25/2019 | 12/25/2024 | NC | 203.7054 | 3/26/2025 | 72 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 0 | Paid After Chargeback Date | 0 |
|
||||||
|
|
||||||
|
Scenario: NR - Calculate Chargeback for NR loan - paid past chargeback date (month before first payment date)
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 10/15/2019 | 11/29/2019 | 10/29/2025 | NR | 0 | 10/31/2019 | 72 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NR | No reserve to be paid | N | 0 | 0 | 0 | 0.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 0 | No Reserve - No Chargeback | 72 |
|
||||||
|
|
||||||
|
Scenario: NR - Calculate Chargeback for NR loan - paid before chargeback date, 0 chargeback because reserve is 0
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 10/15/2019 | 11/29/2019 | 10/29/2025 | NR | 0 | 10/20/2019 | 72 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NR | No reserve to be paid | N | 0 | 0 | 0 | 0.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 0 | No Reserve - No Chargeback | 72 |
|
||||||
|
|
||||||
|
Scenario: NR - Calculate Chargeback for NR loan - paid after final payment date
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 10/15/2019 | 11/29/2019 | 10/29/2025 | NR | 0 | 12/1/2025 | 72 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NR | No reserve to be paid | N | 0 | 0 | 0 | 0.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 0 | No Reserve - No Chargeback | 0 |
|
||||||
|
|
||||||
|
Scenario: BB - Calculate Chargeback for BB loan - 0 chargeback because reserve is 0
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 10/15/2019 | 11/29/2019 | 10/29/2025 | BB | 0 | 10/20/2019 | 72 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| BB | Standard Loan | S | 0 | 0 | 0 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 0 | No Reserve - No Chargeback | 72 |
|
||||||
|
|
||||||
|
Scenario: BB - Calculate Chargeback for BB loan - 0 chargeback because it is paid after final payment date.
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 8/24/2017 | 9/23/2017 | 8/23/2020 | BB | 127.24 | 5/18/2021 | 36 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| BB | Standard Loan | S | 0 | 0 | 0 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 0 | Paid After Chargeback Date | 0 |
|
||||||
|
|
||||||
|
Scenario: BB - Calculate Chargeback for BB loan - 0 chargeback because it is paid on the final payment date.
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 8/24/2017 | 9/23/2017 | 5/18/2021 | BB | 127.24 | 5/18/2021 | 36 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| BB | Standard Loan | S | 0 | 0 | 0 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 0 | Paid After Chargeback Date | 0 |
|
||||||
|
|
||||||
|
Scenario: BB - Calculate Chargeback for BB loan - using BB Chargeback method, past chargeback date, NoChargebackPayments
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 9/11/2018 | 10/24/2018 | 12/24/2024 | BB | 287.3639 | 4/30/2021 | 75 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| BB | Standard Loan | S | 0 | 0 | 0 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 99.82114421052631578947368421 | Paid On or Before Chargeback Date | 44 |
|
||||||
|
|
||||||
|
Scenario: BB - Calculate Chargeback for BB loan - using BB Chargeback method, paid before first payment date, NoChargebackPayments
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 10/15/2019 | 11/29/2019 | 10/29/2025 | BB | 500 | 10/20/2019 | 72 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| BB | Standard Loan | S | 0 | 0 | 0 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 500 | Paid On or Before Chargeback Date | 72 |
|
||||||
|
|
||||||
|
Scenario: BB - Calculate Chargeback for BB loan - using BB Chargeback method, paid more than a year after first payment.
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 1/18/2018 | 3/4/2018 | 2/4/2023 | BB | 790.4206 | 4/30/2021 | 60 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| BB | Standard Loan | S | 0 | 0 | 0 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 99.77440360655737704918032787 | Paid On or Before Chargeback Date | 21 |
|
||||||
|
|
||||||
|
Scenario: BB - Calculate Chargeback for BB loan - using BB Chargeback method, almost to final payment date.
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 5/2/2015 | 6/10/2015 | 5/10/2021 | BB | 26938.75 | 4/30/2021 | 72 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| BB | Standard Loan | S | 0 | 0 | 0 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 0 | Paid After Chargeback Date | 0 |
|
||||||
|
|
||||||
|
Scenario: BB - Calculate Chargeback for BB loan - using BB Chargeback method, before final payment date.
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 3/30/2017 | 5/14/2017 | 4/14/2022 | BB | 115.00 | 4/30/2021 | 60 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| BB | Standard Loan | S | 0 | 0 | 0 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 4.1475409836065573770491803279 | Paid On or Before Chargeback Date | 11 |
|
||||||
|
|
||||||
|
Scenario: BB - Calculate Chargeback for BB loan - using BB Chargeback method, paid within a year of loan date.
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 12/22/2020 | 2/5/2021 | 4/5/2027 | BB | 265.9569 | 4/26/2021 | 75 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| BB | Standard Loan | S | 0 | 0 | 0 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 238.52134610526315789473684211 | Paid On or Before Chargeback Date | 71 |
|
||||||
|
|
||||||
|
Scenario: BB - Calculate Chargeback for BB loan - paid after final pmt date
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 12/22/2020 | 2/5/2021 | 4/5/2027 | BB | 265.9569 | 4/26/2027 | 75 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| BB | Standard Loan | S | 0 | 0 | 0 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 0 | Paid After Chargeback Date | 0 |
|
||||||
|
|
||||||
|
Scenario: BB - Calculate Chargeback for Buydown reserve - checking Buydown message buydown reserve below threshold
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term | ReserveMessage |
|
||||||
|
| 8/4/2017 | 9/3/2017 | 8/3/2022 | NC | 0 | 10/20/2019 | 60 | BuyDown - Reserve - Below Threshold |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve Paid - No charge back- after 90 Days | N | 90 | 3 | 25 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 0 | Buy Down Reserve - No Chargeback | 33 |
|
||||||
|
|
||||||
|
Scenario: NC - Calculate Chargeback for Buydown reserve - checking Buydown message buydown reserve and negative value
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term | ReserveMessage |
|
||||||
|
| 9/30/2019 | 11/14/2019 | 10/14/2025 | NC | -3471.1087 | 3/20/2021 | 72 | BuyDown - Reserve |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve Paid - No charge back- after 90 Days | N | 90 | 3 | 25 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 0 | Buy Down Reserve - No Chargeback | 55 |
|
||||||
|
|
||||||
|
Scenario: NC - Calculate Boat Chargeback for Buydown reserve - checking Buydown message buydown reserve and negative value
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term | ReserveMessage | AccountType |
|
||||||
|
| 9/30/2019 | 11/14/2019 | 10/14/2025 | NC | -3471.1087 | 3/20/2021 | 60 | BuyDown - Reserve | DL10 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve Paid - No charge back- after 90 Days | N | 90 | 3 | 25 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 0 | Buy Down Reserve - No Chargeback | 43 |
|
||||||
|
|
||||||
|
Scenario: NC - Calculate Boat Chargeback for paid before chargeback date - Term 63 or less
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term | AccountType |
|
||||||
|
| 7/4/2019 | 8/3/2019 | 10/3/2024 | NC | 460.04 | 11/21/2019 | 63 | DL12 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 390.44069444444444444444444444 | Paid On or Before Chargeback Date | 58 |
|
||||||
|
|
||||||
|
Scenario: NC - Calculate Boat Chargeback for paid before chargeback date - Term greater than 63
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term | AccountType |
|
||||||
|
| 7/3/2019 | 8/2/2019 | 7/2/2029 | NC | 1163.05 | 5/6/2020 | 120 | DL11 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 978.0193181818181818181818182 | Paid On or Before Chargeback Date | 110 |
|
||||||
|
|
||||||
|
Scenario: NC - Calculate Boat Chargeback for after chargeback date - Term 63 or less
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term | AccountType |
|
||||||
|
| 07/04/2019 | 8/3/2019 | 10/3/2024 | NC | 460.04 | 12/21/2020 | 63 | DL11 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 0 | Paid After Chargeback Date | 45 |
|
||||||
|
|
||||||
|
Scenario: NC - Calculate Boat Chargeback for after chargeback date - Term greater than 63
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term | AccountType |
|
||||||
|
| 7/3/2019 | 8/2/2019 | 7/2/2029 | NC | 1163.05 | 5/6/2021 | 120 | DL09 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 0 | Paid After Chargeback Date | 98 |
|
||||||
|
|
||||||
|
Scenario Outline: NC - Calculate Chargeback for paid date between first payment date and chargeback date examples 1 and 2
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 12/26/2020 | 2/9/2021 | 4/9/2027 | NC | 1815.0503 | <PaidLoanDate> | 75 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| <Chargeback> | <ChargebackMessage> | <RemainingMonthsAtClose> |
|
||||||
|
Examples:
|
||||||
|
| PaidLoanDate | Chargeback | ChargebackMessage | RemainingMonthsAtClose |
|
||||||
|
| 2/26/2021 | 1720.1581965964912280701754386 | Paid On or Before Chargeback Date | 73 |
|
||||||
|
| 2/25/2021 | 1720.1581965964912280701754386 | Paid On or Before Chargeback Date | 73 |
|
||||||
|
|
||||||
|
Scenario: NC - Calculate Chargeback for paid date between first payment date and chargeback date - example 3
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 12/29/2020 | 2/12/2021 | 1/12/2027 | NC | 1835.6378 | 2/26/2021 | 72 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 1785.3463534246575342465753425 | Paid On or Before Chargeback Date | 71 |
|
||||||
|
|
||||||
|
Scenario: NC - Calculate Chargeback for paid date between first payment date and chargeback date - example 4
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 11/23/2020 | 1/7/2021 |12/7/2025 | NC | 1085.4654 | 2/25/2021 | 60 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 980.477762950819672131147541 | Paid On or Before Chargeback Date | 57 |
|
||||||
|
|
||||||
|
Scenario: NC - Calculate Chargeback for paid date between first payment date and chargeback date - example 5
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 12/14/2020 | 1/28/2021 | 12/28/2024 | NC | 58.5443 | 2/19/2021 | 48 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 53.814956037414965986394557823 | Paid On or Before Chargeback Date | 46 |
|
||||||
|
|
||||||
|
Scenario: NC - Calculate Chargeback for paid date between first payment date and chargeback date - example 6
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 12/22/2020 | 2/5/2021 | 1/5/2027 | NC | 853.1331 | 2/19/2021 | 72 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 829.7595904109589041095890411 | Paid On or Before Chargeback Date | 71 |
|
||||||
|
|
||||||
|
Scenario: NC - Calculate Chargeback for paid date between first payment date and chargeback date - example 7
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 12/4/2020 | 1/18/2021 | 12/18/2025 | NC | 584.2477 | 2/18/2021 | 60 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 546.25563644808743169398907104 | Paid On or Before Chargeback Date | 58 |
|
||||||
|
|
||||||
|
Scenario: NC - Calculate Chargeback for paid date between first payment date and chargeback date - example 8 - paid day after first payment date
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 1/2/2021 | 2/16/2021 | 11/16/2024 | NC | 116.0986 | 2/17/2021 | 46 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 111.15823404255319148936170213 | Paid On or Before Chargeback Date | 45 |
|
||||||
|
|
||||||
|
Scenario: NC - Calculate Chargeback for paid date between first payment date and chargeback date - example 9 - first payment in a month with 30 days
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 10/14/2020 | 11/28/2020 | 10/28/2023 | NC | 110.7846 | 1/25/2021 | 36 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 93.31855945945945945945945946 | Paid On or Before Chargeback Date | 33 |
|
||||||
|
|
||||||
|
Scenario: NC - Calculate Chargeback without using Arbitrary Date (paid loan date 29th, not leap year) for Paid Date after First Payment Date
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 1/16/2020 | 4/15/2020 | 3/15/2025 | NC | 169.0256 | 4/29/2020 | 60 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 163.48377704918032786885245902 | Paid On or Before Chargeback Date | 59 |
|
||||||
|
|
||||||
|
Scenario: NC - Calculate Chargeback without using Arbitrary Date (paid loan date 30th, not leap year) for Paid Date after First Payment Date
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 3/17/2017 | 4/16/2017 | 3/16/2019 | NC | 86.4577 | 5/30/2017 | 24 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 72.912660333333333333333333333 | Paid On or Before Chargeback Date | 22 |
|
||||||
|
|
||||||
|
Scenario: NC - Calculate Chargeback without using Arbitrary Date (paid loan date 31st, not leap year) for Paid Date after First Payment Date
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 3/17/2017 | 4/16/2017 | 3/16/2019 | NC | 86.4577 | 5/31/2017 | 24 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 72.912660333333333333333333333 | Paid On or Before Chargeback Date | 22 |
|
||||||
|
|
||||||
|
Scenario: NC - Calculate Chargeback using Arbitrary Date (paid loan date 29th, leap year) for Paid Date after First Payment Date
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 1/16/2019 | 4/15/2019 | 3/15/2024 | NC | 169.0256 | 4/29/2019 | 60 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 163.48377704918032786885245902 | Paid On or Before Chargeback Date | 59 |
|
||||||
|
|
||||||
|
Scenario: NC - Calculate Chargeback using Arbitrary Date (paid loan date 30th, leap year) for Paid Date after First Payment Date
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 3/17/2018 | 4/16/2018 | 3/16/2020 | NC | 86.4577 | 5/30/2018 | 24 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 72.912660333333333333333333333 | Paid On or Before Chargeback Date | 22 |
|
||||||
|
|
||||||
|
Scenario: NC - Calculate Chargeback without using Arbitrary Date (paid loan date 31st, leap year) for Paid Date after First Payment Date
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 3/17/2018 | 4/16/2018 | 3/16/2020 | NC | 86.4577 | 5/31/2018 | 24 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 72.912660333333333333333333333 | Paid On or Before Chargeback Date | 22 |
|
||||||
|
|
||||||
|
Scenario: NC - Calculate Chargeback using Arbitrary Date with Final pmt after Arbitrary Date (paid loan date 31st, not leap year) for Paid Date after First Payment Date
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Type Id | ReserveAmount | PaidLoanDate | Term |
|
||||||
|
| 11/30/2018 | 1/1/2019 | 3/1/2025 | NC | 2456.5546 | 1/31/2019 | 75 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the chargeback is calculated
|
||||||
|
Then the chargeback returned is
|
||||||
|
| ChargebackAmount | ChargebackTypeMessage | RemainingMonthsAtClose |
|
||||||
|
| 2328.1242016140350877192982456 | Paid On or Before Chargeback Date | 73 |
|
||||||
+155
@@ -0,0 +1,155 @@
|
|||||||
|
Feature: Dealer Service
|
||||||
|
Get a list of dealers when searching code or name. Update dealers
|
||||||
|
|
||||||
|
Scenario: Search for Dealer - Code - find multiple dealers
|
||||||
|
Given the dealer table looks like
|
||||||
|
| Dealer Code | Name | DealerOrganizationNumber | DealerAccountNumber |
|
||||||
|
| S1 | SUBURBAN MOTORS HARLEY DAVIDSON | 1234 | 4535434333 |
|
||||||
|
| S11 | ANTHONY AUTO GROUP | 5678 | 7535434333 |
|
||||||
|
| H21 | HEISER CHEVROLET CADILLAC OF WEST BEND | 1111 | 9535434333 |
|
||||||
|
When I search for dealers with search string 'S1'
|
||||||
|
Then dealers returned should be
|
||||||
|
| Dealer Code | Name | DealerOrganizationNumber | DealerAccountNumber |
|
||||||
|
| S1 | SUBURBAN MOTORS HARLEY DAVIDSON | 1234 | 4535434333 |
|
||||||
|
| S11 | ANTHONY AUTO GROUP | 5678 | 7535434333 |
|
||||||
|
|
||||||
|
Scenario: Search for Dealer - Code - no dealers returned
|
||||||
|
Given the dealer table looks like
|
||||||
|
| Dealer Code | Name | DealerOrganizationNumber | DealerAccountNumber |
|
||||||
|
| S1 | SUBURBAN MOTORS HARLEY DAVIDSON | 1234 | 4535434333 |
|
||||||
|
| S11 | ANTHONY AUTO GROUP | 5678 | 7535434333 |
|
||||||
|
| H21 | HEISER CHEVROLET CADILLAC OF WEST BEND | 1111 | 9535434333 |
|
||||||
|
When I search for dealers with search string 'A1'
|
||||||
|
Then dealers returned should be
|
||||||
|
| Dealer Code | Name | DealerOrganizationNumber | DealerAccountNumber |
|
||||||
|
|
||||||
|
Scenario: Search for Dealer - Name - find multiple dealers
|
||||||
|
Given the dealer table looks like
|
||||||
|
| Dealer Code | Name | DealerOrganizationNumber | DealerAccountNumber |
|
||||||
|
| S1 | SUBURBAN MOTORS HARLEY DAVIDSON | 1234 | 4535434333 |
|
||||||
|
| S11 | ANTHONY AUTO GROUP OF WEST BEND | 5678 | 7535434333 |
|
||||||
|
| H21 | HEISER CHEVROLET CADILLAC OF WEST BEND | 1111 | 9535434333 |
|
||||||
|
When I search for dealers with search string 'WEST'
|
||||||
|
Then dealers returned should be
|
||||||
|
| Dealer Code | Name | DealerOrganizationNumber | DealerAccountNumber |
|
||||||
|
| S11 | ANTHONY AUTO GROUP OF WEST BEND | 5678 | 7535434333 |
|
||||||
|
| H21 | HEISER CHEVROLET CADILLAC OF WEST BEND | 1111 | 9535434333 |
|
||||||
|
|
||||||
|
Scenario: Search for Dealer - Name - no dealers returned
|
||||||
|
Given the dealer table looks like
|
||||||
|
| Dealer Code | Name | DealerOrganizationNumber | DealerAccountNumber |
|
||||||
|
| S1 | SUBURBAN MOTORS HARLEY DAVIDSON | 1234 | 4535434333 |
|
||||||
|
| S11 | ANTHONY AUTO GROUP | 5678 | 7535434333 |
|
||||||
|
| H21 | HEISER CHEVROLET CADILLAC OF WEST BEND | 1111 | 9535434333 |
|
||||||
|
When I search for dealers with search string 'A1'
|
||||||
|
Then dealers returned should be
|
||||||
|
| Dealer Code | Name | DealerOrganizationNumber | DealerAccountNumber |
|
||||||
|
|
||||||
|
Scenario: Search for Dealer - Code and name - find multiple dealers
|
||||||
|
Given the dealer table looks like
|
||||||
|
| Dealer Code | Name | DealerOrganizationNumber | DealerAccountNumber |
|
||||||
|
| S1 | SUBURBAN MOTORS HARLEY DAVIDSON | 1234 | 4535434333 |
|
||||||
|
| A1 | ANTHONY AUTO GROUP OF WEST BEND S1 | 9234 | 3535434333 |
|
||||||
|
| H21 | HEISER CHEVROLET CADILLAC OF WEST BEND | 1111 | 9535434333 |
|
||||||
|
When I search for dealers with search string 'S1'
|
||||||
|
Then dealers returned should be
|
||||||
|
| Dealer Code | Name | DealerOrganizationNumber | DealerAccountNumber |
|
||||||
|
| S1 | SUBURBAN MOTORS HARLEY DAVIDSON | 1234 | 4535434333 |
|
||||||
|
| A1 | ANTHONY AUTO GROUP OF WEST BEND S1 | 9234 | 3535434333 |
|
||||||
|
|
||||||
|
Scenario: Update dealers from loans - add dealer that doesn't exist
|
||||||
|
Given a list of loans with dealers that look like
|
||||||
|
| LoanId | Dealer Organization Number | Dealer Code | Name | Dealer Account Number |
|
||||||
|
| 1 | 1234 | S1 | SUBURBAN MOTORS HARLEY DAVIDSON | 4535434333 |
|
||||||
|
And the dealer table looks like
|
||||||
|
|Dealer Organization Number | Dealer Code | Name | Dealer Account Number |
|
||||||
|
When I update the dealers from the loans
|
||||||
|
Then the dealer table now looks like
|
||||||
|
| Dealer Organization Number | Dealer Code | Name | Dealer Account Number |
|
||||||
|
| 1234 | S1 | SUBURBAN MOTORS HARLEY DAVIDSON | 4535434333 |
|
||||||
|
|
||||||
|
Scenario: Update dealers from loans - add dealer with blank org number
|
||||||
|
Given a list of loans with dealers that look like
|
||||||
|
| LoanId | Dealer Organization Number | Dealer Code | Name | Dealer Account Number |
|
||||||
|
| 1 | | | | |
|
||||||
|
And the dealer table looks like
|
||||||
|
| Dealer Organization Number | Dealer Code | Name | Dealer Account Number |
|
||||||
|
| 1234 | S1 | SUBURBAN MOTORS HARLEY DAVIDSON | 4535434333 |
|
||||||
|
When I update the dealers from the loans
|
||||||
|
Then the dealer table now looks like
|
||||||
|
| Dealer Organization Number | Dealer Code | Name | Dealer Account Number |
|
||||||
|
| 1234 | S1 | SUBURBAN MOTORS HARLEY DAVIDSON | 4535434333 |
|
||||||
|
| | | | |
|
||||||
|
|
||||||
|
Scenario: Update dealers from loans - update name and account number
|
||||||
|
Given a list of loans with dealers that look like
|
||||||
|
| LoanId | Dealer Organization Number | Dealer Code | Name | Dealer Account Number |
|
||||||
|
| 1 | 1234 | S1 | SUBURBAN MOTORS HD | 4535434334 |
|
||||||
|
And the dealer table looks like
|
||||||
|
| Dealer Organization Number | Dealer Code | Name | Dealer Account Number |
|
||||||
|
| 1234 | S1 | SUBURBAN MOTORS HARLEY DAVIDSON | 4535434334 |
|
||||||
|
When I update the dealers from the loans
|
||||||
|
Then the dealer table now looks like
|
||||||
|
| Dealer Organization Number | Dealer Code | Name | Dealer Account Number |
|
||||||
|
| 1234 | S1 | SUBURBAN MOTORS HD | 4535434334 |
|
||||||
|
|
||||||
|
Scenario: Update dealers from loans - DO update dealer code
|
||||||
|
Given a list of loans with dealers that look like
|
||||||
|
| LoanId | Dealer Organization Number | Dealer Code | Name | Dealer Account Number |
|
||||||
|
| 1 | 1234 | S11 | SUBURBAN MOTORS HARLEY DAVIDSON | 4535434334 |
|
||||||
|
And the dealer table looks like
|
||||||
|
| Dealer Organization Number | Dealer Code | Name | Dealer Account Number |
|
||||||
|
| 1234 | S1 | SUBURBAN MOTORS HARLEY DAVIDSON | 4535434334 |
|
||||||
|
When I update the dealers from the loans
|
||||||
|
Then the dealer table now looks like
|
||||||
|
| Dealer Organization Number | Dealer Code | Name | Dealer Account Number |
|
||||||
|
| 1234 | S11 | SUBURBAN MOTORS HARLEY DAVIDSON | 4535434334 |
|
||||||
|
|
||||||
|
Scenario: Update dealers from loans - only take updates from the first loan with that dealer
|
||||||
|
Given a list of loans with dealers that look like
|
||||||
|
| LoanId | Dealer Organization Number | Dealer Code | Name | Dealer Account Number |
|
||||||
|
| 1 | 1234 | S1 | SUBURBAN MOTORS HD | 4535434334 |
|
||||||
|
| 1 | 1234 | S1 | BEST SUBURBAN MOTORS HD | 4535434335 |
|
||||||
|
And the dealer table looks like
|
||||||
|
| Dealer Organization Number | Dealer Code | Name | Dealer Account Number |
|
||||||
|
| 1234 | S1 | SUBURBAN MOTORS HARLEY DAVIDSON | 4535434334 |
|
||||||
|
When I update the dealers from the loans
|
||||||
|
Then the dealer table now looks like
|
||||||
|
| Dealer Organization Number | Dealer Code | Name | Dealer Account Number |
|
||||||
|
| 1234 | S1 | SUBURBAN MOTORS HD | 4535434334 |
|
||||||
|
|
||||||
|
Scenario: Update dealers from loans - a null dealer code doesn't get pulled in
|
||||||
|
Given a list of loans with dealers that look like
|
||||||
|
| LoanId | Dealer Organization Number | Dealer Code | Name | Dealer Account Number |
|
||||||
|
| 1 | 1234 | <null> | SUBURBAN MOTORS HARLEY DAVIDSON | 4535434334 |
|
||||||
|
And the dealer table looks like
|
||||||
|
| Dealer Organization Number | Dealer Code | Name | Dealer Account Number |
|
||||||
|
| 1234 | S1 | SUBURBAN MOTORS HARLEY DAVIDSON | 4535434334 |
|
||||||
|
When I update the dealers from the loans
|
||||||
|
Then the dealer table now looks like
|
||||||
|
| Dealer Organization Number | Dealer Code | Name | Dealer Account Number |
|
||||||
|
| 1234 | S1 | SUBURBAN MOTORS HARLEY DAVIDSON | 4535434334 |
|
||||||
|
|
||||||
|
Scenario: Update dealers from loans - a null dealer name doesn't get pulled in
|
||||||
|
Given a list of loans with dealers that look like
|
||||||
|
| LoanId | Dealer Organization Number | Dealer Code | Name | Dealer Account Number |
|
||||||
|
| 1 | 1234 | S1 | <null> | 4535434334 |
|
||||||
|
And the dealer table looks like
|
||||||
|
| Dealer Organization Number | Dealer Code | Name | Dealer Account Number |
|
||||||
|
| 1234 | S1 | SUBURBAN MOTORS HARLEY DAVIDSON | 4535434334 |
|
||||||
|
When I update the dealers from the loans
|
||||||
|
Then the dealer table now looks like
|
||||||
|
| Dealer Organization Number | Dealer Code | Name | Dealer Account Number |
|
||||||
|
| 1234 | S1 | SUBURBAN MOTORS HARLEY DAVIDSON | 4535434334 |
|
||||||
|
|
||||||
|
Scenario: Update dealers from loans - a null dealer account number doesn't get pulled in
|
||||||
|
Given a list of loans with dealers that look like
|
||||||
|
| LoanId | Dealer Organization Number | Dealer Code | Name | Dealer Account Number |
|
||||||
|
| 1 | 1234 | S1 | SUBURBAN MOTORS HARLEY DAVIDSON | <null> |
|
||||||
|
And the dealer table looks like
|
||||||
|
| Dealer Organization Number | Dealer Code | Name | Dealer Account Number |
|
||||||
|
| 1234 | S1 | SUBURBAN MOTORS HARLEY DAVIDSON | 4535434334 |
|
||||||
|
When I update the dealers from the loans
|
||||||
|
Then the dealer table now looks like
|
||||||
|
| Dealer Organization Number | Dealer Code | Name | Dealer Account Number |
|
||||||
|
| 1234 | S1 | SUBURBAN MOTORS HARLEY DAVIDSON | 4535434334 |
|
||||||
+95
@@ -0,0 +1,95 @@
|
|||||||
|
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using ReserveManagementSystemApi.Services;
|
||||||
|
using ReserveManagementSystemLib.Models;
|
||||||
|
using ReserveManagementSystemLib.Persistence;
|
||||||
|
using ReserveManagementSystemLib.Repositories;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using TechTalk.SpecFlow;
|
||||||
|
using TechTalk.SpecFlow.Assist;
|
||||||
|
using TechTalk.SpecFlow.Assist.ValueRetrievers;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi.Tests.Features
|
||||||
|
{
|
||||||
|
[Binding]
|
||||||
|
public sealed class DealerServiceSteps
|
||||||
|
{
|
||||||
|
// For additional details on SpecFlow step definitions see https://go.specflow.org/doc-stepdef
|
||||||
|
|
||||||
|
private readonly ScenarioContext _scenarioContext;
|
||||||
|
private DealerService _dealerService;
|
||||||
|
private AppDbContext _appDbContext;
|
||||||
|
private IEnumerable<Dealer> _dealersResult;
|
||||||
|
private List<Loan> _loans;
|
||||||
|
|
||||||
|
public DealerServiceSteps(ScenarioContext scenarioContext)
|
||||||
|
{
|
||||||
|
_scenarioContext = scenarioContext;
|
||||||
|
Service.Instance.ValueRetrievers.Register(new NullValueRetriever("<null>"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[BeforeScenario]
|
||||||
|
public void CreateDatabase()
|
||||||
|
{
|
||||||
|
var options = new DbContextOptionsBuilder<AppDbContext>()
|
||||||
|
.UseInMemoryDatabase(Guid.NewGuid().ToString())
|
||||||
|
.Options;
|
||||||
|
_appDbContext = new AppDbContext(options);
|
||||||
|
_dealerService = new DealerService(new DealerRepository(_appDbContext));
|
||||||
|
}
|
||||||
|
|
||||||
|
[AfterScenario]
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_appDbContext.Database.EnsureDeleted();
|
||||||
|
_appDbContext.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Given(@"the dealer table looks like")]
|
||||||
|
public void GivenTheDealerTableLooksLike(Table table)
|
||||||
|
{
|
||||||
|
var dealers = table.CreateSet<Dealer>().ToList();
|
||||||
|
_appDbContext.Dealers.AddRange(dealers);
|
||||||
|
_appDbContext.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Given(@"a list of loans with dealers that look like")]
|
||||||
|
public void GivenAListOfLoansWithDealersThatLookLike(Table table)
|
||||||
|
{
|
||||||
|
_loans = table.CreateSet<Loan>().ToList();
|
||||||
|
var dealers = table.CreateSet<Dealer>().ToList();
|
||||||
|
for (var i=0; i < _loans.Count; i++)
|
||||||
|
{
|
||||||
|
_loans.Skip(i).First().Dealer = dealers.Skip(i).First();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[When(@"I search for dealers with search string '(.*)'")]
|
||||||
|
public async void WhenISearchForDealersWithSearchString(string dealerSearchText)
|
||||||
|
{
|
||||||
|
_dealersResult = await _dealerService.Search(dealerSearchText);
|
||||||
|
}
|
||||||
|
|
||||||
|
[When(@"I update the dealers from the loans")]
|
||||||
|
public async void WhenIUpdateTheDealersFromTheLoans()
|
||||||
|
{
|
||||||
|
await _dealerService.UpdateDealersAsync(_loans);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"dealers returned should be")]
|
||||||
|
public void ThenDealersReturnedShouldBe(Table table)
|
||||||
|
{
|
||||||
|
table.CompareToSet(_dealersResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the dealer table now looks like")]
|
||||||
|
public void ThenTheDealerTableNowLooksLike(Table table)
|
||||||
|
{
|
||||||
|
var dealers = _appDbContext.Dealers.ToList();
|
||||||
|
table.CompareToSet(dealers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+131
@@ -0,0 +1,131 @@
|
|||||||
|
Feature: Export Service
|
||||||
|
Export loans to DNA that have updated reserves or chargebacks
|
||||||
|
|
||||||
|
Scenario: Export loan reserves and mark as exported
|
||||||
|
Given the current loans that look like this
|
||||||
|
| LoanId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | DealerOrganizationNumber | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type Id | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | ExportedReserveDate | ExportedChargebackDate |
|
||||||
|
| 1 | 452 | 731 | SMITH | JOE | | 1234 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | 50.00 | 4/29/2021 | Standard | 5/1/2021 2:00 PM | 5/2/2021 2 pm |
|
||||||
|
| 2 | 451 | 6 | JONES | LAURA | M | 5678 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | | |
|
||||||
|
| 3 | 451 | 73 | JONES | LAURA | M | 1111 | 2/24/2023 | 2/27/2023 | 4/10/2023 | 3/10/2028 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | | |
|
||||||
|
And the dealers that look like
|
||||||
|
| Dealer Code | Name | DealerOrganizationNumber | DealerAccountNumber |
|
||||||
|
| S7 | SUBURBAN MOTORS HARLEY DAVIDSON | 1111 | 929292929292929 |
|
||||||
|
| H21 | HEISER CHEVROLET CADILLAC OF WEST BEND | 5678 | 121212212121212 |
|
||||||
|
| A1 | ACURA OF BROOKFIELD | 1234 | 48484848484844 |
|
||||||
|
And the Core Api is successful in saving reserves
|
||||||
|
When I export the loan reserves on the date '6/1/2021 3:00 PM'
|
||||||
|
Then the Core API is called with 2 loan reserves
|
||||||
|
And the loan list will be updated to look like
|
||||||
|
| LoanId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | DealerOrganizationNumber | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type Id | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | ExportedReserveDate | ExportedChargebackDate |
|
||||||
|
| 1 | 452 | 731 | SMITH | JOE | | 1234 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | 50.00 | 4/29/2021 | Standard | 5/1/2021 2:00 PM | 5/2/2021 2 pm |
|
||||||
|
| 2 | 451 | 6 | JONES | LAURA | M | 5678 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 6/1/2021 3:00 PM | |
|
||||||
|
| 3 | 451 | 73 | JONES | LAURA | M | 1111 | 2/24/2023 | 2/27/2023 | 4/10/2023 | 3/10/2028 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 6/1/2021 3:00 PM | |
|
||||||
|
And the result of saving the reserves will be 2
|
||||||
|
|
||||||
|
Scenario: Export loan reserves - core api service returns false
|
||||||
|
Given the current loans that look like this
|
||||||
|
| LoanId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | DealerOrganizationNumber | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type Id | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | ExportedReserveDate | ExportedChargebackDate |
|
||||||
|
| 1 | 452 | 731 | SMITH | JOE | | 1234 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | 50.00 | 4/29/2021 | Standard | 5/1/2021 2:00 PM | 5/2/2021 2 pm |
|
||||||
|
| 2 | 451 | 6 | JONES | LAURA | M | 5678 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | | |
|
||||||
|
| 3 | 451 | 73 | JONES | LAURA | M | 1111 | 2/24/2023 | 2/27/2023 | 4/10/2023 | 3/10/2028 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | | |
|
||||||
|
And the dealers that look like
|
||||||
|
| Dealer Code | Name | DealerOrganizationNumber | DealerAccountNumber |
|
||||||
|
| S7 | SUBURBAN MOTORS HARLEY DAVIDSON | 1111 | 929292929292929 |
|
||||||
|
| H21 | HEISER CHEVROLET CADILLAC OF WEST BEND | 5678 | 121212212121212 |
|
||||||
|
| A1 | ACURA OF BROOKFIELD | 1234 | 48484848484844 |
|
||||||
|
And the Core Api returns false when saving reserves
|
||||||
|
When I export the loan reserves on the date '6/1/2021 3:00 PM'
|
||||||
|
Then the Core API is called with 2 loan reserves
|
||||||
|
And the loan list will be updated to look like
|
||||||
|
| LoanId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | DealerOrganizationNumber | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type Id | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | ExportedReserveDate | ExportedChargebackDate |
|
||||||
|
| 1 | 452 | 731 | SMITH | JOE | | 1234 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | 50.00 | 4/29/2021 | Standard | 5/1/2021 2:00 PM | 5/2/2021 2 pm |
|
||||||
|
| 2 | 451 | 6 | JONES | LAURA | M | 5678 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | | |
|
||||||
|
| 3 | 451 | 73 | JONES | LAURA | M | 1111 | 2/24/2023 | 2/27/2023 | 4/10/2023 | 3/10/2028 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | | |
|
||||||
|
And the result of saving the reserves will be 0
|
||||||
|
|
||||||
|
Scenario: Export loan reserves - error in service client
|
||||||
|
Given the current loans that look like this
|
||||||
|
| LoanId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | DealerOrganizationNumber | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type Id | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | ExportedReserveDate | ExportedChargebackDate |
|
||||||
|
| 1 | 452 | 731 | SMITH | JOE | | 1234 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 5/1/2021 2:00 PM | 5/2/2021 2 pm |
|
||||||
|
| 2 | 451 | 6 | JONES | LAURA | M | 5678 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | | |
|
||||||
|
| 3 | 451 | 73 | JONES | LAURA | M | 1111 | 2/24/2023 | 2/27/2023 | 4/10/2023 | 3/10/2028 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | | |
|
||||||
|
And the dealers that look like
|
||||||
|
| Dealer Code | Name | DealerOrganizationNumber | DealerAccountNumber |
|
||||||
|
| S7 | SUBURBAN MOTORS HARLEY DAVIDSON | 1111 | 929292929292929 |
|
||||||
|
| H21 | HEISER CHEVROLET CADILLAC OF WEST BEND | 5678 | 121212212121212 |
|
||||||
|
| A1 | ACURA OF BROOKFIELD | 1234 | 48484848484844 |
|
||||||
|
And the Core Api throws an error in saving reserves
|
||||||
|
When I export the loan reserves on the date '6/1/2021 3:00 PM'
|
||||||
|
Then the Core API is called with 2 loan reserves
|
||||||
|
And the loan list will be updated to look like
|
||||||
|
| LoanId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | DealerOrganizationNumber | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type Id | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | ExportedReserveDate | ExportedChargebackDate |
|
||||||
|
| 1 | 452 | 731 | SMITH | JOE | | 1234 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 5/1/2021 2:00 PM | 5/2/2021 2 pm |
|
||||||
|
| 2 | 451 | 6 | JONES | LAURA | M | 5678 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | | |
|
||||||
|
| 3 | 451 | 73 | JONES | LAURA | M | 1111 | 2/24/2023 | 2/27/2023 | 4/10/2023 | 3/10/2028 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | | |
|
||||||
|
And the export service throws an Exception
|
||||||
|
|
||||||
|
Scenario: Export loan chargebacks and mark as exported
|
||||||
|
Given the current loans that look like this
|
||||||
|
| LoanId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | DealerOrganizationNumber | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type Id | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | ExportedReserveDate | ExportedChargebackDate | AccountType |
|
||||||
|
| 1 | 452 | 731 | SMITH | JOE | | 1234 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | 50.00 | 4/29/2021 | Standard | 4/20/2021 1 pm | | DL01 |
|
||||||
|
| 2 | 451 | 6 | JONES | LAURA | M | 5678 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 4/20/2021 1 pm | | DL01 |
|
||||||
|
| 3 | 451 | 73 | JONES | LAURA | M | 1111 | 2/24/2023 | 2/27/2023 | 4/10/2023 | 3/10/2028 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | | | DL01 |
|
||||||
|
And the dealers that look like
|
||||||
|
| Dealer Code | Name | DealerOrganizationNumber | DealerAccountNumber |
|
||||||
|
| S7 | SUBURBAN MOTORS HARLEY DAVIDSON | 1111 | 929292929292929 |
|
||||||
|
| H21 | HEISER CHEVROLET CADILLAC OF WEST BEND | 5678 | 121212212121212 |
|
||||||
|
| A1 | ACURA OF BROOKFIELD | 1234 | 48484848484844 |
|
||||||
|
And the current minor account that look like this
|
||||||
|
| MinorAccountTypeId | GeneralLedgerAccountNumber | AccountType |
|
||||||
|
| 1 | 731 | DL01 |
|
||||||
|
And the Core Api is successful in saving chargebacks
|
||||||
|
When I export the loan chargebacks on the date '5/2/2021 2:00 PM'
|
||||||
|
Then the Core API is called with 1 loan chargebacks
|
||||||
|
And the loan list will be updated to look like
|
||||||
|
| LoanId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | DealerOrganizationNumber | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type Id | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | ExportedReserveDate | ExportedChargebackDate | AccountType |
|
||||||
|
| 1 | 452 | 731 | SMITH | JOE | | 1234 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | 50.00 | 4/29/2021 | Standard | 4/20/2021 1 pm | 5/2/2021 2:00 PM | DL01 |
|
||||||
|
| 2 | 451 | 6 | JONES | LAURA | M | 5678 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 4/20/2021 1 pm | | DL01 |
|
||||||
|
| 3 | 451 | 73 | JONES | LAURA | M | 1111 | 2/24/2023 | 2/27/2023 | 4/10/2023 | 3/10/2028 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | | | DL01 |
|
||||||
|
And the result of saving the chargebacks will be 1
|
||||||
|
|
||||||
|
Scenario: Export loan chargebacks - core api returns false
|
||||||
|
Given the current loans that look like this
|
||||||
|
| LoanId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | DealerOrganizationNumber | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type Id | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | ExportedReserveDate | ExportedChargebackDate |
|
||||||
|
| 1 | 452 | 731 | SMITH | JOE | | 1234 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | 50.00 | 4/29/2021 | Standard | 4/20/2021 1 pm | |
|
||||||
|
| 2 | 451 | 6 | JONES | LAURA | M | 5678 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 4/20/2021 1 pm | |
|
||||||
|
| 3 | 451 | 73 | JONES | LAURA | M | 1111 | 2/24/2023 | 2/27/2023 | 4/10/2023 | 3/10/2028 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | | |
|
||||||
|
And the dealers that look like
|
||||||
|
| Dealer Code | Name | DealerOrganizationNumber | DealerAccountNumber |
|
||||||
|
| S7 | SUBURBAN MOTORS HARLEY DAVIDSON | 1111 | 929292929292929 |
|
||||||
|
| H21 | HEISER CHEVROLET CADILLAC OF WEST BEND | 5678 | 121212212121212 |
|
||||||
|
| A1 | ACURA OF BROOKFIELD | 1234 | 48484848484844 |
|
||||||
|
And the Core Api returns false when saving chargebacks
|
||||||
|
When I export the loan chargebacks on the date '5/2/2021 2:00 PM'
|
||||||
|
Then the Core API is called with 1 loan chargebacks
|
||||||
|
And the loan list will be updated to look like
|
||||||
|
| LoanId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | DealerOrganizationNumber | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type Id | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | ExportedReserveDate | ExportedChargebackDate |
|
||||||
|
| 1 | 452 | 731 | SMITH | JOE | | 1234 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | 50.00 | 4/29/2021 | Standard | 4/20/2021 1 pm | |
|
||||||
|
| 2 | 451 | 6 | JONES | LAURA | M | 5678 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 4/20/2021 1 pm | |
|
||||||
|
| 3 | 451 | 73 | JONES | LAURA | M | 1111 | 2/24/2023 | 2/27/2023 | 4/10/2023 | 3/10/2028 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | | |
|
||||||
|
And the result of saving the chargebacks will be 0
|
||||||
|
|
||||||
|
Scenario: Export loan chargebacks - error in service client
|
||||||
|
Given the current loans that look like this
|
||||||
|
| LoanId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | DealerOrganizationNumber | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type Id | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | ExportedReserveDate | ExportedChargebackDate |
|
||||||
|
| 1 | 452 | 731 | SMITH | JOE | | 1234 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | 50.00 | 4/29/2021 | Standard | 4/20/2021 1 pm | |
|
||||||
|
| 2 | 451 | 6 | JONES | LAURA | M | 5678 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 4/20/2021 1 pm | |
|
||||||
|
| 3 | 451 | 73 | JONES | LAURA | M | 1111 | 2/24/2023 | 2/27/2023 | 4/10/2023 | 3/10/2028 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | | |
|
||||||
|
And the dealers that look like
|
||||||
|
| Dealer Code | Name | DealerOrganizationNumber | DealerAccountNumber |
|
||||||
|
| S7 | SUBURBAN MOTORS HARLEY DAVIDSON | 1111 | 929292929292929 |
|
||||||
|
| H21 | HEISER CHEVROLET CADILLAC OF WEST BEND | 5678 | 121212212121212 |
|
||||||
|
| A1 | ACURA OF BROOKFIELD | 1234 | 48484848484844 |
|
||||||
|
And the Core Api throws an error in saving chargebacks
|
||||||
|
When I export the loan chargebacks on the date '5/2/2021 2:00 PM'
|
||||||
|
Then the Core API is called with 1 loan chargebacks
|
||||||
|
And the loan list will be updated to look like
|
||||||
|
| LoanId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | DealerOrganizationNumber | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type Id | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | ExportedReserveDate | ExportedChargebackDate |
|
||||||
|
| 1 | 452 | 731 | SMITH | JOE | | 1234 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | 50.00 | 4/29/2021 | Standard | 4/20/2021 1 pm | |
|
||||||
|
| 2 | 451 | 6 | JONES | LAURA | M | 5678 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 4/20/2021 1 pm | |
|
||||||
|
| 3 | 451 | 73 | JONES | LAURA | M | 1111 | 2/24/2023 | 2/27/2023 | 4/10/2023 | 3/10/2028 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | | |
|
||||||
|
And the export service throws an Exception
|
||||||
+209
@@ -0,0 +1,209 @@
|
|||||||
|
using LCU.Library.Internal.CoreApiWrapperModel.CoreModels.Transaction;
|
||||||
|
using LCU.Library.Internal.CoreApiWrapperModel.CoreModels.CoreRequests;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Moq;
|
||||||
|
using ReserveManagementSystemApi.ServiceClients;
|
||||||
|
using ReserveManagementSystemApi.Services;
|
||||||
|
using ReserveManagementSystemLib.Models;
|
||||||
|
using ReserveManagementSystemLib.Persistence;
|
||||||
|
using ReserveManagementSystemLib.Repositories;
|
||||||
|
using TechTalk.SpecFlow;
|
||||||
|
using TechTalk.SpecFlow.Assist;
|
||||||
|
using Xunit;
|
||||||
|
using ReserveManagementSystemLib.Configuration;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi.Tests.Features
|
||||||
|
{
|
||||||
|
[Binding]
|
||||||
|
public sealed class ExportServiceSteps
|
||||||
|
{
|
||||||
|
// For additional details on SpecFlow step definitions see https://go.specflow.org/doc-stepdef
|
||||||
|
|
||||||
|
private readonly ScenarioContext _scenarioContext;
|
||||||
|
|
||||||
|
private ExportService _exportService;
|
||||||
|
private AppDbContext _appDbContext;
|
||||||
|
private Mock<ICoreApiServiceClient> _mockCoreApiServiceClient = new Mock<ICoreApiServiceClient>();
|
||||||
|
private int _exportResult;
|
||||||
|
private Mock<RmsApiConfiguration> _mockConfiguration = new Mock<RmsApiConfiguration>();
|
||||||
|
private Exception _exportException;
|
||||||
|
|
||||||
|
public ExportServiceSteps(ScenarioContext scenarioContext)
|
||||||
|
{
|
||||||
|
_scenarioContext = scenarioContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BeforeScenario]
|
||||||
|
public void CreateDatabase()
|
||||||
|
{
|
||||||
|
var options = new DbContextOptionsBuilder<AppDbContext>()
|
||||||
|
.UseInMemoryDatabase(Guid.NewGuid().ToString())
|
||||||
|
.Options;
|
||||||
|
_appDbContext = new AppDbContext(options);
|
||||||
|
_mockConfiguration.Object.DefaultBatchSize = 100;
|
||||||
|
_exportService = new ExportService(new LoanRepository(_appDbContext), _mockCoreApiServiceClient.Object, new MinorAccountTypeRepository(_appDbContext), _mockConfiguration.Object);
|
||||||
|
}
|
||||||
|
|
||||||
|
[AfterScenario]
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_appDbContext.Database.EnsureDeleted();
|
||||||
|
_appDbContext.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Given(@"the current loans that look like this")]
|
||||||
|
public void GivenTheCurrentLoansThatLookLikeThis(Table table)
|
||||||
|
{
|
||||||
|
var loans = table.CreateSet<Loan>();
|
||||||
|
_appDbContext.Loans.AddRange(loans);
|
||||||
|
_appDbContext.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Given(@"the current minor account that look like this")]
|
||||||
|
public void GivenTheCurrentMinorAccountsThatLookLikeThis(Table table)
|
||||||
|
{
|
||||||
|
var accounts = table.CreateSet<MinorAccountType>();
|
||||||
|
_appDbContext.MinorAccountTypes.AddRange(accounts);
|
||||||
|
_appDbContext.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Given(@"the Core Api is successful in saving reserves")]
|
||||||
|
public void GivenTheCoreApiIsSuccessfulInSavingReserves()
|
||||||
|
{
|
||||||
|
var transactionResponse = new MonetaryTransactionResponse();
|
||||||
|
transactionResponse.AccountNumber = 6;
|
||||||
|
transactionResponse.WasSuccessful = true;
|
||||||
|
|
||||||
|
var transactionResponse2 = new MonetaryTransactionResponse();
|
||||||
|
transactionResponse2.AccountNumber = 73;
|
||||||
|
transactionResponse2.WasSuccessful = true;
|
||||||
|
|
||||||
|
var transactionResponseList = new List<MonetaryTransactionResponse> { transactionResponse, transactionResponse2 };
|
||||||
|
|
||||||
|
_mockCoreApiServiceClient.Setup(x => x.PostMonetaryTransactions(It.IsAny<List<GroupedMonetaryTransactionRequest>>())).ReturnsAsync(transactionResponseList);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Given(@"the Core Api returns false when saving reserves")]
|
||||||
|
public void GivenTheCoreApiReturnsFalseWhenSavingReserves()
|
||||||
|
{
|
||||||
|
var transactionResponse = new MonetaryTransactionResponse();
|
||||||
|
transactionResponse.AccountNumber = 6;
|
||||||
|
transactionResponse.WasSuccessful = false;
|
||||||
|
|
||||||
|
var transactionResponse2 = new MonetaryTransactionResponse();
|
||||||
|
transactionResponse.AccountNumber = 73;
|
||||||
|
transactionResponse.WasSuccessful = false;
|
||||||
|
|
||||||
|
var transactionResponseList = new List<MonetaryTransactionResponse> { transactionResponse, transactionResponse2 };
|
||||||
|
|
||||||
|
_mockCoreApiServiceClient.Setup(x => x.PostMonetaryTransactions(It.IsAny<List<GroupedMonetaryTransactionRequest>>())).ReturnsAsync(transactionResponseList);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Given(@"the Core Api returns false when saving chargebacks")]
|
||||||
|
public void GivenTheCoreApiReturnsFalseWhenSavingChargebacks()
|
||||||
|
{
|
||||||
|
var transactionResponse = new MonetaryTransactionResponse();
|
||||||
|
transactionResponse.AccountNumber = 731;
|
||||||
|
transactionResponse.WasSuccessful = false;
|
||||||
|
|
||||||
|
var transactionResponseList = new List<MonetaryTransactionResponse> { transactionResponse };
|
||||||
|
|
||||||
|
_mockCoreApiServiceClient.Setup(x => x.PostMonetaryTransactions(It.IsAny<List<GroupedMonetaryTransactionRequest>>())).ReturnsAsync(transactionResponseList);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Given(@"the Core Api throws an error in saving reserves")]
|
||||||
|
public void GivenTheCoreApiThrowsAnErrorInSavingReserves()
|
||||||
|
{
|
||||||
|
_mockCoreApiServiceClient.Setup(x => x.PostMonetaryTransactions(It.IsAny<List<GroupedMonetaryTransactionRequest>>())).Throws(new Exception());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Given(@"the Core Api is successful in saving chargebacks")]
|
||||||
|
public void GivenTheCoreApiIsSuccessfulInSavingChargebacks()
|
||||||
|
{
|
||||||
|
var transactionResponse = new MonetaryTransactionResponse();
|
||||||
|
transactionResponse.AccountNumber = 731;
|
||||||
|
transactionResponse.WasSuccessful = true;
|
||||||
|
|
||||||
|
var transactionResponseList = new List<MonetaryTransactionResponse> { transactionResponse };
|
||||||
|
|
||||||
|
_mockCoreApiServiceClient.Setup(x => x.PostMonetaryTransactions(It.IsAny<List<GroupedMonetaryTransactionRequest>>())).ReturnsAsync(transactionResponseList);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Given(@"the Core Api throws an error in saving chargebacks")]
|
||||||
|
public void GivenTheCoreApiThrowsAnErrorInSavingChargebacks()
|
||||||
|
{
|
||||||
|
_mockCoreApiServiceClient.Setup(x => x.PostMonetaryTransactions(It.IsAny<List<GroupedMonetaryTransactionRequest>>())).Throws(new Exception());
|
||||||
|
}
|
||||||
|
|
||||||
|
[When(@"I export the loan reserves on the date '(.*)'")]
|
||||||
|
public async void WhenIExportTheLoanReservesOnTheDate(DateTime currentDate)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_exportResult = await _exportService.ExportReservesAsync(currentDate);
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
_exportException = ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[When(@"I export the loan chargebacks on the date '(.*)'")]
|
||||||
|
public async void WhenIExportTheLoanChargebacksOnTheDate(DateTime currentDate)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_exportResult = await _exportService.ExportChargebacksAsync(currentDate);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_exportException = ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the Core API is called with (.*) loan reserves")]
|
||||||
|
public void ThenTheCoreAPIIsCalledWithLoanReserves(int numberOfReserves)
|
||||||
|
{
|
||||||
|
_mockCoreApiServiceClient.Verify(x => x.PostMonetaryTransactions(It.Is<List<GroupedMonetaryTransactionRequest>>(x => x.Count == numberOfReserves)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the Core API is called with (.*) loan chargebacks")]
|
||||||
|
public void ThenTheCoreAPIIsCalledWithLoanChargebacks(int numberOfChargebacks)
|
||||||
|
{
|
||||||
|
_mockCoreApiServiceClient.Verify(x => x.PostMonetaryTransactions(It.Is<List<GroupedMonetaryTransactionRequest>>(x => x.Count == numberOfChargebacks)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the loan list will be updated to look like")]
|
||||||
|
public void ThenTheLoanListWillBeUpdatedToLookLike(Table table)
|
||||||
|
{
|
||||||
|
var loansResult = _appDbContext.Loans;
|
||||||
|
table.CompareToSet(loansResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the result of saving the reserves will be (.*)")]
|
||||||
|
public void ThenTheResultOfSavingTheReservesWillBe(int exportNumber)
|
||||||
|
{
|
||||||
|
Assert.Equal(exportNumber, _exportResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the result of saving the chargebacks will be (.*)")]
|
||||||
|
public void ThenTheResultOfSavingTheChargebacksWillBe(int exportNumber)
|
||||||
|
{
|
||||||
|
Assert.Equal(exportNumber, _exportResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the export service throws an Exception")]
|
||||||
|
public void ThenTheExportServiceThrowsAnException()
|
||||||
|
{
|
||||||
|
Assert.IsType<Exception>(_exportException);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Given(@"the dealers that look like")]
|
||||||
|
public void GivenTheDealersThatLookLike(Table table)
|
||||||
|
{
|
||||||
|
var dealers = table.CreateSet<Dealer>().ToList();
|
||||||
|
_appDbContext.Dealers.AddRange(dealers);
|
||||||
|
_appDbContext.SaveChanges();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+392
@@ -0,0 +1,392 @@
|
|||||||
|
Feature: Import Read Service - Closed Loans from DNA
|
||||||
|
Gets closed loans from DNA by calling a CoreApiWrapper endpoint, reads loans into memory, calculates chargebacks, saves loans, saves import information
|
||||||
|
|
||||||
|
Background:
|
||||||
|
Given a loan type table consisting of
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
| BB | Standard | S | 0 | 0 | 0 | 1.00 | 0.25 |
|
||||||
|
| NR | No reserve to be paid | N | 0 | 0 | 0 | 0.00 | 0.25 |
|
||||||
|
|
||||||
|
Scenario: AddImport for Closed Loans from DNA - all loans are saved
|
||||||
|
Given that I get these closed loans back from DNA
|
||||||
|
| LoanNumber | PaidLoanDate |
|
||||||
|
| 147 | 02/25/2021 |
|
||||||
|
| 143 | 02/12/2021 |
|
||||||
|
| 144 | 02/12/2021 |
|
||||||
|
And a loan table consisting of
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Dealer Code | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | LoanStatus | RemainingMonthsAtClose |
|
||||||
|
| 1 | 1 | 5841 | 147 | SMITH | JOE | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | New | |
|
||||||
|
| 2 | 2 | 10094 | 143 | JONES | LAURA | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | NC | 60 | 1450.2923 | 500 | false | | | Message | Updated | |
|
||||||
|
| 3 | 2 | 100947 | 144 | JOHNSON | LAURA | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | NC | 60 | 1450.2923 | 500 | false | | | Message | New | |
|
||||||
|
When I process the closed loan import from DNA at "3/5/2021 5:00:00 AM"
|
||||||
|
Then the import looks like
|
||||||
|
| StartDate | RecordCount | RecordsSaved | Success | Filename | Import Type |
|
||||||
|
| 3/5/2021 5:00:00 AM | 3 | 3 | true | | Closed |
|
||||||
|
And the import has an end date that is greater or equal to the start date
|
||||||
|
And the loans now look like
|
||||||
|
| LoanId | Member Number | Loan Number | Chargeback | Paid Loan Date | LoanStatus | RemainingMonthsAtClose |
|
||||||
|
| 1 | 5841 | 147 | 210.0375 | 2/25/2021 | Closed | 63 |
|
||||||
|
| 2 | 10094 | 143 | 1498.6354 | 2/12/2021 | Closed | 61 |
|
||||||
|
| 3 | 100947 | 144 | 1498.6354 | 2/12/2021 | Closed | 61 |
|
||||||
|
And AddHistoriesAsync is called with 2 history/ies having OldValue "New" and NewValue "Closed"
|
||||||
|
And AddHistoriesAsync is called with 1 history/ies having OldValue "Updated" and NewValue "Closed"
|
||||||
|
And AddHistoriesAsync is called with 3 history/ies having ActivityType "LoanStatusChange" and AuditDescription "Importing closed loan changed loan status"
|
||||||
|
And ExportChargebacksAsync is called
|
||||||
|
|
||||||
|
Scenario: AddImport for Closed Loans from DNA - saves two loans that are in the loan table
|
||||||
|
Given that I get these closed loans back from DNA
|
||||||
|
| LoanNumber | PaidLoanDate |
|
||||||
|
| 141 | 04/25/2021 |
|
||||||
|
| 143 | 02/12/2021 |
|
||||||
|
| 144 | 02/12/2021 |
|
||||||
|
And a loan table consisting of
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Dealer Code | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | LoanStatus |
|
||||||
|
| 1 | 1 | 12 | 3 | SMITH | JOE | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | New |
|
||||||
|
| 2 | 2 | 10094 | 143 | JONES | LAURA | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | New |
|
||||||
|
| 3 | 2 | 10621 | 144 | JOHNSON | LAURA | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | New |
|
||||||
|
When I process the closed loan import with missing loan "141" with date from DNA at "3/5/2021 5:00:00 AM" and select from "2/25/2021 5:00:00 AM"
|
||||||
|
Then the import looks like
|
||||||
|
| StartDate | RecordCount | RecordsSaved | Success | Filename | Import Type | ImportId |
|
||||||
|
| 3/5/2021 5:00:00 AM | 2 | 2 | true | | Closed | 1 |
|
||||||
|
And the import has an end date that is greater or equal to the start date
|
||||||
|
And the loans now look like
|
||||||
|
| LoanId | Member Number | Loan Number | Chargeback | Paid Loan Date | LoanStatus | RemainingMonthsAtClose |
|
||||||
|
| 1 | 12 | 3 | | | New | |
|
||||||
|
| 2 | 10094 | 143 | 1498.6354 | 2/12/2021 | Closed | 61 |
|
||||||
|
| 3 | 10621 | 144 | 1498.6354 | 2/12/2021 | Closed | 61 |
|
||||||
|
And AddHistoriesAsync is called with 2 history/ies having OldValue "New" and NewValue "Closed"
|
||||||
|
And AddHistoriesAsync is called with 2 history/ies having ActivityType "LoanStatusChange" and AuditDescription "Importing closed loan changed loan status"
|
||||||
|
And ExportChargebacksAsync is called
|
||||||
|
Given an import from DNA that contains
|
||||||
|
| Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Dealer Code | LoanType | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | LoanAmount | Buy Rate | Contract Rate | Gap | Warranty | Mbp | CreditLife | CreditDisability | DealerOrganizationNumber | DealerAccountNumber | ApplicationId | VIN | Make | Model | Year | Mileage | Color | PaidLoanDate | Term |
|
||||||
|
| 3250 | 141 | MUELLER | STEVEN | C | S7 | NC | 2/10/2021 | 02/03/2021 | 03/05/2021 | 05/05/2026 | 27889.51 | 2.03 | 5.39 | True | False | False | False | True | 3434 | 324324324324324 | 2123444 | | | | | | | 4/25/2021 | 63 |
|
||||||
|
When I process the missing active loans with detail from DNA at "3/5/2021 5:00:00 AM" and export
|
||||||
|
Then the import looks like
|
||||||
|
| StartDate | RecordCount | RecordsSaved | Success | Filename | Import Type | ImportId |
|
||||||
|
| 3/5/2021 5:00:00 AM | 1 | 1 | true | | Closed | 2 |
|
||||||
|
And the import has an end date that is greater or equal to the start date
|
||||||
|
And the loans with details now look like
|
||||||
|
| LoanId | Member Number | Loan Number | Chargeback | Paid Loan Date | LoanStatus | RemainingMonthsAtClose |
|
||||||
|
| 1 | 3250 | 141 | 720.6656 | 04/25/2021 | Closed | 60 |
|
||||||
|
|
||||||
|
Scenario: AddImport for Closed Boat Loans from DNA - saves two boat loans that are in the loan table
|
||||||
|
Given that I get these closed loans back from DNA
|
||||||
|
| LoanNumber | PaidLoanDate |
|
||||||
|
| 147 | 02/25/2021 |
|
||||||
|
| 143 | 04/12/2021 |
|
||||||
|
| 144 | 04/12/2021 |
|
||||||
|
And a loan table consisting of
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Dealer Code | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | LoanStatus | AccountType |
|
||||||
|
| 1 | 1 | 12 | 3 | SMITH | JOE | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | New | DL09 |
|
||||||
|
| 2 | 2 | 10094 | 143 | JONES | LAURA | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | New | DL10 |
|
||||||
|
| 3 | 2 | 10621 | 144 | JOHNSON | LAURA | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | New | DL11 |
|
||||||
|
When I process the closed loan import with missing loan "147" with date from DNA at "3/5/2021 5:00:00 AM" and select from "2/25/2021 5:00:00 AM"
|
||||||
|
Then the import looks like
|
||||||
|
| StartDate | RecordCount | RecordsSaved | Success | Filename | Import Type | ImportId |
|
||||||
|
| 3/5/2021 5:00:00 AM | 2 | 2 | true | | Closed | 1 |
|
||||||
|
And the import has an end date that is greater or equal to the start date
|
||||||
|
And the loans now look like
|
||||||
|
| LoanId | Member Number | Loan Number | Chargeback | Paid Loan Date | LoanStatus | RemainingMonthsAtClose |
|
||||||
|
| 1 | 12 | 3 | | | New | |
|
||||||
|
| 2 | 10094 | 143 | 1402.7417 | 4/12/2021 | Closed | 59 |
|
||||||
|
| 3 | 10621 | 144 | 1402.7417 | 4/12/2021 | Closed | 59 |
|
||||||
|
And AddHistoriesAsync is called with 2 history/ies having OldValue "New" and NewValue "Closed"
|
||||||
|
And AddHistoriesAsync is called with 2 history/ies having ActivityType "LoanStatusChange" and AuditDescription "Importing closed loan changed loan status"
|
||||||
|
And ExportChargebacksAsync is called
|
||||||
|
Given an import from DNA that contains
|
||||||
|
| Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Dealer Code | LoanType | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | LoanAmount | Buy Rate | Contract Rate | Gap | Warranty | Mbp | CreditLife | CreditDisability | DealerOrganizationNumber | DealerAccountNumber | ApplicationId | VIN | Make | Model | Year | Mileage | Color | PaidLoanDate | OriginalTermInDays | AccountType |
|
||||||
|
| 3250 | 147 | MUELLER | STEVEN | C | S7 | NC | 2/10/2021 | 02/03/2021 | 03/05/2021 | 05/05/2026 | 27889.51 | 2.03 | 3.39 | True | False | False | False | True | 3434 | 324324324324324 | 2123444 | | | | | | | 2/25/2021 | 1918 | DL09 |
|
||||||
|
When I process the missing active loans with detail from DNA at "3/5/2021 5:00:00 AM" and export
|
||||||
|
Then the import looks like
|
||||||
|
| StartDate | RecordCount | RecordsSaved | Success | Filename | Import Type | ImportId |
|
||||||
|
| 3/5/2021 5:00:00 AM | 1 | 1 | true | | Closed | 2 |
|
||||||
|
And the import has an end date that is greater or equal to the start date
|
||||||
|
And the loans with details now look like
|
||||||
|
| LoanId | Member Number | Loan Number | Chargeback | Paid Loan Date | LoanStatus | RemainingMonthsAtClose |
|
||||||
|
| 1 | 3250 | 147 | 769.1038 | 02/25/2021 | Closed | 62 |
|
||||||
|
|
||||||
|
Scenario: AddImport for Closed Loans from DNA - Set Action Required = false
|
||||||
|
Given that I get these closed loans back from DNA
|
||||||
|
| LoanNumber | PaidLoanDate |
|
||||||
|
| 148 | 05/25/2021 |
|
||||||
|
| 143 | 02/12/2021 |
|
||||||
|
| 144 | 02/12/2021 |
|
||||||
|
And a loan table consisting of
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Dealer Code | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | LoanStatus | ActionRequired |
|
||||||
|
| 1 | 1 | 12 | 3 | SMITH | JOE | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | New | false |
|
||||||
|
| 2 | 2 | 10094 | 143 | JONES | LAURA | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | New | true |
|
||||||
|
| 3 | 2 | 10621 | 144 | JOHNSON | LAURA | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | New | true |
|
||||||
|
When I process the closed loan import with missing loan "148" with date from DNA at "3/5/2021 5:00:00 AM" and select from "2/25/2021 5:00:00 AM"
|
||||||
|
Then the import looks like
|
||||||
|
| StartDate | RecordCount | RecordsSaved | Success | Filename | Import Type | ImportId |
|
||||||
|
| 3/5/2021 5:00:00 AM | 2 | 2 | true | | Closed | 1 |
|
||||||
|
And the import has an end date that is greater or equal to the start date
|
||||||
|
And the loans now look like
|
||||||
|
| LoanId | Member Number | Loan Number | Chargeback | Paid Loan Date | LoanStatus | RemainingMonthsAtClose | ActionRequired |
|
||||||
|
| 1 | 12 | 3 | | | New | | false |
|
||||||
|
| 2 | 10094 | 143 | 1498.6354 | 2/12/2021 | Closed | 61 | false |
|
||||||
|
| 3 | 10621 | 144 | 1498.6354 | 2/12/2021 | Closed | 61 | false |
|
||||||
|
And AddHistoriesAsync is called with 2 history/ies having OldValue "New" and NewValue "Closed"
|
||||||
|
And AddHistoriesAsync is called with 2 history/ies having ActivityType "LoanStatusChange" and AuditDescription "Importing closed loan changed loan status"
|
||||||
|
And ExportChargebacksAsync is called
|
||||||
|
Given an import from DNA that contains
|
||||||
|
| Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Dealer Code | LoanType | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | LoanAmount | Buy Rate | Contract Rate | Gap | Warranty | Mbp | CreditLife | CreditDisability | DealerOrganizationNumber | DealerAccountNumber | ApplicationId | VIN | Make | Model | Year | Mileage | Color | PaidLoanDate | Term |
|
||||||
|
| 3250 | 148 | MUELLER | STEVEN | C | S7 | NC | 2/10/2021 | 02/03/2021 | 03/05/2021 | 05/05/2026 | 27889.51 | 2.03 | 3.39 | True | False | False | False | True | 3434 | 324324324324324 | 2123444 | | | | | | | 5/25/2021 | 63 |
|
||||||
|
When I process the missing active loans with detail from DNA at "3/5/2021 5:00:00 AM" and export
|
||||||
|
Then the import looks like
|
||||||
|
| StartDate | RecordCount | RecordsSaved | Success | Filename | Import Type | ImportId |
|
||||||
|
| 3/5/2021 5:00:00 AM | 1 | 1 | true | | Closed | 2 |
|
||||||
|
And the import has an end date that is greater or equal to the start date
|
||||||
|
And the loans with details now look like
|
||||||
|
| LoanId | Member Number | Loan Number | Chargeback | Paid Loan Date | LoanStatus | RemainingMonthsAtClose |
|
||||||
|
| 1 | 3250 | 147 | 0 | 05/25/2021 | Closed | 59 |
|
||||||
|
|
||||||
|
Scenario: AddImport for Closed Loans from DNA - no loans are returned
|
||||||
|
Given that I get these closed loans back from DNA
|
||||||
|
| LoanNumber | PaidLoanDate |
|
||||||
|
And a loan table consisting of
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Dealer Code | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | LoanStatus | RemainingMonthsAtClose |
|
||||||
|
| 1 | 1 | 5841 | 147 | SMITH | JOE | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | New | |
|
||||||
|
| 2 | 2 | 10094 | 143 | JONES | LAURA | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | NC | 60 | 1450.2923 | 500 | false | | | Message | Updated | |
|
||||||
|
| 3 | 2 | 100947 | 144 | JOHNSON | LAURA | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | NC | 60 | 1450.2923 | 500 | false | | | Message | New | |
|
||||||
|
When I process the closed loan import from DNA at "3/5/2021 5:00:00 AM"
|
||||||
|
Then the import looks like
|
||||||
|
| StartDate | RecordCount | RecordsSaved | Success | Filename | Import Type |
|
||||||
|
| 3/5/2021 5:00:00 AM | 0 | 0 | true | | Closed |
|
||||||
|
And the import has an end date that is greater or equal to the start date
|
||||||
|
And ExportChargebacksAsync is called
|
||||||
|
|
||||||
|
Scenario: Import Closed Loans from DNA with loan details, first adding them, starting at a certain closed date
|
||||||
|
Given an import from DNA that contains
|
||||||
|
| Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Dealer Code | LoanType | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | LoanAmount | Buy Rate | Contract Rate | Gap | Warranty | Mbp | CreditLife | CreditDisability | DealerOrganizationNumber | DealerAccountNumber | ApplicationId | VIN | Make | Model | Year | Mileage | Color | PaidLoanDate | OriginalTermInDays |
|
||||||
|
| 3250 | 3250144 | MUELLER | STEVEN | C | S7 | NC | 2/10/2021 | 02/03/2021 | 03/05/2021 | 05/05/2026 | 27889.51 | 2.03 | 3.39 | True | False | False | False | True | 3434 | 324324324324324 | 2123444 | | | | | | | 6/30/2021 | 1918 |
|
||||||
|
| 12021 | 12021143 | HAYDEN | ALEXANDER | W | H21 | BB | 10/31/2019 | 11/6/2019 | 12/15/2019 | 2/15/2026 | 20171.51 | 3.29 | 4.90 | False | True | False | True | False | 3488 | 9888447543454544 | 232323455 | M233333389Y853128921 | Honda | Civic | 2020 | 1900 | Black | 7/1/2021 | 2294 |
|
||||||
|
| 2233 | 2233143 | JONES | FRED | | S7 | NC | 2/1/2021 | 2/5/2021 | 4/1/2021 | 3/1/2024 | 20000 | 3.5 | 5 | false | true | true | false | false | 3434 | 324324324324324 | 21235 | M34kls | Toyota | Camry | 2019 | 5 | Red | 7/3/2021 | 1121 |
|
||||||
|
And a loan table consisting of
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Dealer Code | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate |Loan Type | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | LoanStatus | RemainingMonthsAtClose |
|
||||||
|
When I process the closed loan import with detail from DNA at "8/1/2021 5:00:00 AM"
|
||||||
|
Then the import looks like
|
||||||
|
| StartDate | RecordCount | RecordsSaved | Success | Filename | Import Type |
|
||||||
|
| 8/1/2021 5:00:00 AM | 3 | 3 | true | | Closed |
|
||||||
|
And the import has an end date that is greater or equal to the start date
|
||||||
|
And the loans now look like
|
||||||
|
| LoanId | Member Number | Loan Number | Term | FlatFeePaid | ReserveAmount | Chargeback | Paid Loan Date | LoanStatus | RemainingMonthsAtClose | Adjustment |
|
||||||
|
| 1 | 3250 | 3250144 | 63 | false | 793.9136070432343049958707190 | 0 | 6/30/2021 | Closed | 58 | |
|
||||||
|
| 2 | 12021 | 12021143 | 75 | false | 1132.5564086943452341656244555 | 611.9778 | 7/1/2021 | Closed | 55 | |
|
||||||
|
| 3 | 2233 | 2233143 | 37 | false | 392.12008534200236229531665461 | 0 | 7/3/2021 | Closed | 33 | |
|
||||||
|
And AddHistoriesAsync is called with 3 history/ies having ActivityType "LoanStatusChange" and AuditDescription "Importing closed loan changed loan status"
|
||||||
|
And ExportChargebacksAsync is called
|
||||||
|
And ExportReservesAsync is called
|
||||||
|
|
||||||
|
Scenario: Import Closed Loans from DNA with loan details, skipping the exports
|
||||||
|
Given an import from DNA that contains
|
||||||
|
| Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Dealer Code | LoanType | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | LoanAmount | Buy Rate | Contract Rate | Gap | Warranty | Mbp | CreditLife | CreditDisability | DealerOrganizationNumber | DealerAccountNumber | ApplicationId | VIN | Make | Model | Year | Mileage | Color | PaidLoanDate | OriginalTermInDays |
|
||||||
|
| 3250 | 3250144 | MUELLER | STEVEN | C | S7 | NC | 2/10/2021 | 02/03/2021 | 03/05/2021 | 05/05/2026 | 27889.51 | 2.03 | 3.39 | True | False | False | False | True | 3434 | 324324324324324 | 2123444 | | | | | | | 6/30/2021 | 1918 |
|
||||||
|
| 12021 | 12021143 | HAYDEN | ALEXANDER | W | H21 | BB | 10/31/2019 | 11/6/2019 | 12/15/2019 | 2/15/2026 | 20171.51 | 3.29 | 4.90 | False | True | False | True | False | 3488 | 9888447543454544 | 232323455 | M233333389Y853128921 | Honda | Civic | 2020 | 1900 | Black | 7/1/2021 | 2294 |
|
||||||
|
| 2233 | 2233143 | JONES | FRED | | S7 | NC | 2/1/2021 | 2/5/2021 | 4/1/2021 | 3/1/2024 | 20000 | 3.5 | 5 | false | true | true | false | false | 3434 | 324324324324324 | 21235 | M34kls | Toyota | Camry | 2019 | 5 | Red | 7/3/2021 | 1121 |
|
||||||
|
And a loan table consisting of
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Dealer Code | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate |Loan Type | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | LoanStatus | RemainingMonthsAtClose |
|
||||||
|
When I process the closed loan import with detail from DNA at "8/1/2021 5:00:00 AM" and skip the export
|
||||||
|
Then the import looks like
|
||||||
|
| StartDate | RecordCount | RecordsSaved | Success | Filename | Import Type |
|
||||||
|
| 8/1/2021 5:00:00 AM | 3 | 3 | true | | Closed |
|
||||||
|
And the import has an end date that is greater or equal to the start date
|
||||||
|
And the loans now look like
|
||||||
|
| LoanId | Member Number | Loan Number | Term | FlatFeePaid | ReserveAmount | Chargeback | Paid Loan Date | LoanStatus | RemainingMonthsAtClose | Adjustment |
|
||||||
|
| 1 | 3250 | 3250144 | 63 | false | 793.9136070432343049958707190 | 0 | 6/30/2021 | Closed | 58 | |
|
||||||
|
| 2 | 12021 | 12021143 | 75 | false | 1132.5564086943452341656244555 | 611.9778 | 7/1/2021 | Closed | 55 | |
|
||||||
|
| 3 | 2233 | 2233143 | 37 | false | 392.12008534200236229531665461 | 0 | 7/3/2021 | Closed | 33 | |
|
||||||
|
And AddHistoriesAsync is called with 3 history/ies having ActivityType "LoanStatusChange" and AuditDescription "Importing closed loan changed loan status"
|
||||||
|
And MarkReservesAndChargebacksAsExportedAsync is called
|
||||||
|
And ExportChargebacksAsync is not called
|
||||||
|
And ExportReservesAsync is not called
|
||||||
|
|
||||||
|
|
||||||
|
Scenario: Import Closed Loans from DNA with loan details, two new loans and one updated (changed member initial)
|
||||||
|
Given an import from DNA that contains
|
||||||
|
| Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Dealer Code | LoanType | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | LoanAmount | Buy Rate | Contract Rate | Gap | Warranty | Mbp | CreditLife | CreditDisability | DealerOrganizationNumber | DealerAccountNumber | ApplicationId | VIN | Make | Model | Year | Mileage | Color | PaidLoanDate | OriginalTermInDays |
|
||||||
|
| 3250 | 3250144 | MUELLER | STEVEN | C | S7 | NC | 2/10/2021 | 02/03/2021 | 03/05/2021 | 05/05/2026 | 27889.51 | 2.03 | 3.39 | True | False | False | False | True | 3434 | 324324324324324 | 2123444 | | | | | | | 6/30/2021 | 1918 |
|
||||||
|
| 12021 | 12021143 | HAYDEN | ALEXANDER | W | H21 | BB | 10/31/2019 | 11/6/2019 | 12/15/2019 | 2/15/2026 | 20171.51 | 3.29 | 4.90 | False | True | False | True | False | 3488 | 9888447543454544 | 232323455 | M233333389Y853128921 | Honda | Civic | 2020 | 1900 | Black | 7/1/2021 | 2294 |
|
||||||
|
| 2233 | 2233143 | JONES | FRED | X | S7 | NC | 2/1/2021 | 2/5/2021 | 4/1/2021 | 3/1/2024 | 20000 | 3.5 | 5 | false | true | true | false | false | 3434 | 324324324324324 | 21235 | M34kls | Toyota | Camry | 2019 | 5 | Red | 7/3/2021 | 1121 |
|
||||||
|
When I process the closed loan import with detail from DNA at "8/1/2021 5:00:00 AM"
|
||||||
|
Then the import looks like
|
||||||
|
| StartDate | RecordCount | RecordsSaved | Success | Filename | Import Type |
|
||||||
|
| 8/1/2021 5:00:00 AM | 3 | 3 | true | | Closed |
|
||||||
|
And the import has an end date that is greater or equal to the start date
|
||||||
|
And the loans now look like
|
||||||
|
| LoanId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Term | FlatFeePaid | ReserveAmount | Chargeback | Paid Loan Date | LoanStatus | RemainingMonthsAtClose | Adjustment |
|
||||||
|
| 1 | 3250 | 3250144 | MUELLER | STEVEN | C | 63 | false | 793.9136070432343049958707190 | 0 | 6/30/2021 | Closed | 58 | |
|
||||||
|
| 2 | 12021 | 12021143 | HAYDEN | ALEXANDER | W | 75 | false | 1132.5564086943452341656244555 | 611.9778 | 7/1/2021 | Closed | 55 | |
|
||||||
|
| 3 | 2233 | 2233143 | JONES | FRED | X | 37 | false | 392.12008534200236229531665461 | 0 | 7/3/2021 | Closed | 33 | |
|
||||||
|
And AddHistoriesAsync is called with 3 history/ies having ActivityType "LoanStatusChange" and AuditDescription "Importing closed loan changed loan status"
|
||||||
|
And ExportChargebacksAsync is called
|
||||||
|
And ExportReservesAsync is called
|
||||||
|
|
||||||
|
Scenario: Import Closed Loans from DNA with loan details, two new loans and one updated (to change contract rate)
|
||||||
|
Given an import from DNA that contains
|
||||||
|
| Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Dealer Code | LoanType | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | LoanAmount | Buy Rate | Contract Rate | Gap | Warranty | Mbp | CreditLife | CreditDisability | DealerOrganizationNumber | DealerAccountNumber | ApplicationId | VIN | Make | Model | Year | Mileage | Color | PaidLoanDate | OriginalTermInDays |
|
||||||
|
| 3250 | 3250144 | MUELLER | STEVEN | C | S7 | NC | 2/10/2021 | 02/03/2021 | 03/05/2021 | 05/05/2026 | 27889.51 | 2.03 | 3.39 | True | False | False | False | True | 3434 | 324324324324324 | 2123444 | | | | | | | 6/30/2021 | 1918 |
|
||||||
|
| 12021 | 12021143 | HAYDEN | ALEXANDER | W | H21 | BB | 10/31/2019 | 11/6/2019 | 12/15/2019 | 2/15/2026 | 20171.51 | 3.29 | 4.90 | False | True | False | True | False | 3488 | 9888447543454544 | 232323455 | M233333389Y853128921 | Honda | Civic | 2020 | 1900 | Black | 7/1/2021 | 2294 |
|
||||||
|
| 2233 | 2233143 | JONES | FRED | Y | S7 | NC | 2/1/2021 | 2/5/2021 | 4/1/2021 | 3/1/2024 | 20000 | 3.5 | 5.5 | false | true | true | false | false | 3434 | 324324324324324 | 21235 | M34kls | Toyota | Camry | 2019 | 5 | Red | 7/3/2021 | 1121 |
|
||||||
|
When I process the closed loan import with detail from DNA at "8/1/2021 5:00:00 AM"
|
||||||
|
Then the import looks like
|
||||||
|
| StartDate | RecordCount | RecordsSaved | Success | Filename | Import Type |
|
||||||
|
| 8/1/2021 5:00:00 AM | 3 | 3 | true | | Closed |
|
||||||
|
And the import has an end date that is greater or equal to the start date
|
||||||
|
And the loans now look like
|
||||||
|
| LoanId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Term | FlatFeePaid | ReserveAmount | Chargeback | Paid Loan Date | LoanStatus | RemainingMonthsAtClose | Adjustment |
|
||||||
|
| 1 | 3250 | 3250144 | MUELLER | STEVEN | C | 63 | false | 793.9136070432343049958707190 | 0 | 6/30/2021 | Closed | 58 | |
|
||||||
|
| 2 | 12021 | 12021143 | HAYDEN | ALEXANDER | W | 75 | false | 1132.5564086943452341656244555 | 611.9778 | 7/1/2021 | Closed | 55 | |
|
||||||
|
| 3 | 2233 | 2233143 | JONES | FRED | Y | 37 | false | 524.41373886682351065543659741 | 0 | 7/3/2021 | Closed | 33 | |
|
||||||
|
And AddHistoriesAsync is called with 3 history/ies having ActivityType "LoanStatusChange" and AuditDescription "Importing closed loan changed loan status"
|
||||||
|
And ExportChargebacksAsync is called
|
||||||
|
And ExportReservesAsync is called
|
||||||
|
|
||||||
|
Scenario: Import Closed Loans from DNA with loan details, with skip the export
|
||||||
|
Given an import from DNA that contains
|
||||||
|
| Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Dealer Code | LoanType | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | LoanAmount | Buy Rate | Contract Rate | Gap | Warranty | Mbp | CreditLife | CreditDisability | DealerOrganizationNumber | DealerAccountNumber | ApplicationId | VIN | Make | Model | Year | Mileage | Color | PaidLoanDate | OriginalTermInDays |
|
||||||
|
| 2233 | 2233143 | JONES | FRED | Y | S7 | NC | 2/1/2021 | 2/5/2021 | 4/1/2021 | 3/1/2024 | 20000 | 3.5 | 5.5 | false | true | true | false | false | 3434 | 324324324324324 | 21235 | M34kls | Toyota | Camry | 2019 | 5 | Red | 7/3/2021 | 1121 |
|
||||||
|
When I process the closed loan import with detail from DNA at "8/1/2021 5:00:00 AM" and skip the export
|
||||||
|
Then the import looks like
|
||||||
|
| StartDate | RecordCount | RecordsSaved | Success | Filename | Import Type |
|
||||||
|
| 8/1/2021 5:00:00 AM | 1 | 1 | true | | Closed |
|
||||||
|
And the import has an end date that is greater or equal to the start date
|
||||||
|
And the loans now look like
|
||||||
|
| LoanId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Term | FlatFeePaid | ReserveAmount | Chargeback | Paid Loan Date | LoanStatus | RemainingMonthsAtClose | Adjustment |
|
||||||
|
| 1 | 2233 | 2233143 | JONES | FRED | Y | 37 | false | 524.41373886682351065543659741 | 0 | 7/3/2021 | Closed | 33 | |
|
||||||
|
And AddHistoriesAsync is called with 1 history/ies having ActivityType "LoanStatusChange" and AuditDescription "Importing closed loan changed loan status"
|
||||||
|
And MarkReservesAndChargebacksAsExportedAsync is called
|
||||||
|
And ExportChargebacksAsync is not called
|
||||||
|
And ExportReservesAsync is not called
|
||||||
|
|
||||||
|
Scenario: Import Closed Loans from DNA with loan details, two new loans and one existing which is already closed with same paid loan date - should ignore that
|
||||||
|
Given an import from DNA that contains
|
||||||
|
| Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Dealer Code | LoanType | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | LoanAmount | Buy Rate | Contract Rate | Gap | Warranty | Mbp | CreditLife | CreditDisability | DealerOrganizationNumber | DealerAccountNumber | ApplicationId | VIN | Make | Model | Year | Mileage | Color | PaidLoanDate | OriginalTermInDays |
|
||||||
|
| 3250 | 3250144 | MUELLER | STEVEN | C | S7 | NC | 2/10/2021 | 02/03/2021 | 03/05/2021 | 05/05/2026 | 27889.51 | 2.03 | 3.39 | True | False | False | False | True | 3434 | 324324324324324 | 2123444 | | | | | | | 6/30/2021 | 1918 |
|
||||||
|
| 12021 | 12021143 | HAYDEN | ALEXANDER | W | H21 | BB | 10/31/2019 | 11/6/2019 | 12/15/2019 | 2/15/2026 | 20171.51 | 3.29 | 4.90 | False | True | False | True | False | 3488 | 9888447543454544 | 232323455 | M233333389Y853128921 | Honda | Civic | 2020 | 1900 | Black | 7/1/2021 | 2294 |
|
||||||
|
| 2233 | 2233143 | JONES | FRED | Y | S7 | NC | 2/1/2021 | 2/5/2021 | 4/1/2021 | 3/1/2024 | 20000 | 3.5 | 5 | false | true | true | false | false | 3434 | 324324324324324 | 21235 | M34kls | Toyota | Camry | 2019 | 5 | Red | 7/3/2021 | 1121 |
|
||||||
|
When I process the closed loan import with detail from DNA at "8/1/2021 5:00:00 AM"
|
||||||
|
Then the import looks like
|
||||||
|
| StartDate | RecordCount | RecordsSaved | Success | Filename | Import Type |
|
||||||
|
| 8/1/2021 5:00:00 AM | 3 | 3 | true | | Closed |
|
||||||
|
And the import has an end date that is greater or equal to the start date
|
||||||
|
And the loans now look like
|
||||||
|
| LoanId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Term | FlatFeePaid | ReserveAmount | Chargeback | Paid Loan Date | LoanStatus | RemainingMonthsAtClose | Adjustment |
|
||||||
|
| 1 | 3250 | 3250144 | MUELLER | STEVEN | C | 63 | false | 793.9136070432343049958707190 | 0 | 6/30/2021 | Closed | 58 | |
|
||||||
|
| 2 | 12021 | 12021143 | HAYDEN | ALEXANDER | W | 75 | false | 1132.5564086943452341656244555 | 611.9778 | 7/1/2021 | Closed | 55 | |
|
||||||
|
| 3 | 2233 | 2233143 | JONES | FRED | Y | 37 | false | 392.12008534200236229531665461 | 0 | 7/3/2021 | Closed | 33 | |
|
||||||
|
And AddHistoriesAsync is called with 3 history/ies having ActivityType "LoanStatusChange" and AuditDescription "Importing closed loan changed loan status"
|
||||||
|
And ExportChargebacksAsync is called
|
||||||
|
And ExportReservesAsync is called
|
||||||
|
|
||||||
|
Scenario: Import Closed Loans from DNA with loan details, two new loans and one existing which is already closed but had a different paid loan date
|
||||||
|
Given an import from DNA that contains
|
||||||
|
| Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Dealer Code | LoanType | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | LoanAmount | Buy Rate | Contract Rate | Gap | Warranty | Mbp | CreditLife | CreditDisability | DealerOrganizationNumber | DealerAccountNumber | ApplicationId | VIN | Make | Model | Year | Mileage | Color | PaidLoanDate | OriginalTermInDays |
|
||||||
|
| 3250 | 3250144 | MUELLER | STEVEN | C | S7 | NC | 2/10/2021 | 02/03/2021 | 03/05/2021 | 05/05/2026 | 27889.51 | 2.03 | 3.39 | True | False | False | False | True | 3434 | 324324324324324 | 2123444 | | | | | | | 6/30/2021 | 1918 |
|
||||||
|
| 12021 | 12021143 | HAYDEN | ALEXANDER | W | H21 | BB | 10/31/2019 | 11/6/2019 | 12/15/2019 | 2/15/2026 | 20171.51 | 3.29 | 4.90 | False | True | False | True | False | 3488 | 9888447543454544 | 232323455 | M233333389Y853128921 | Honda | Civic | 2020 | 1900 | Black | 7/1/2021 | 2294 |
|
||||||
|
| 2233 | 2233143 | JONES | FRED | Y | S7 | NC | 2/1/2021 | 2/5/2021 | 4/1/2021 | 3/1/2024 | 20000 | 3.5 | 5 | false | true | true | false | false | 3434 | 324324324324324 | 21235 | M34kls | Toyota | Camry | 2019 | 5 | Red | 7/3/2021 | 1121 |
|
||||||
|
When I process the closed loan import with detail from DNA at "8/1/2021 5:00:00 AM"
|
||||||
|
Then the import looks like
|
||||||
|
| StartDate | RecordCount | RecordsSaved | Success | Filename | Import Type |
|
||||||
|
| 8/1/2021 5:00:00 AM | 3 | 3 | true | | Closed |
|
||||||
|
And the import has an end date that is greater or equal to the start date
|
||||||
|
And the loans now look like
|
||||||
|
| LoanId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Term | FlatFeePaid | ReserveAmount | Chargeback | Paid Loan Date | LoanStatus | RemainingMonthsAtClose | Adjustment |
|
||||||
|
| 1 | 3250 | 3250144 | MUELLER | STEVEN | C | 63 | false | 793.9136070432343049958707190 | 0 | 6/30/2021 | Closed | 58 | |
|
||||||
|
| 2 | 12021 | 12021143 | HAYDEN | ALEXANDER | W | 75 | false | 1132.5564086943452341656244555 | 611.9778 | 7/1/2021 | Closed | 55 | |
|
||||||
|
| 3 | 2233 | 2233143 | JONES | FRED | Y | 37 | false | 392.12008534200236229531665461 | 0 | 7/3/2021 | Closed | 33 | |
|
||||||
|
And AddHistoriesAsync is called with 3 history/ies having ActivityType "LoanStatusChange" and AuditDescription "Importing closed loan changed loan status"
|
||||||
|
And ExportChargebacksAsync is called
|
||||||
|
And ExportReservesAsync is called
|
||||||
|
|
||||||
|
Scenario: Import Closed Loans from DNA with loan details, Set Action Required = false
|
||||||
|
Given an import from DNA that contains
|
||||||
|
| Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Dealer Code | LoanType | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | LoanAmount | Buy Rate | Contract Rate | Gap | Warranty | Mbp | CreditLife | CreditDisability | DealerOrganizationNumber | DealerAccountNumber | ApplicationId | VIN | Make | Model | Year | Mileage | Color | PaidLoanDate | OriginalTermInDays |
|
||||||
|
| 3250 | 3250144 | MUELLER | STEVEN | C | S7 | NC | 2/10/2021 | 02/03/2021 | 03/05/2021 | 05/05/2026 | 27889.51 | 2.03 | 3.39 | True | False | False | False | True | 3434 | 324324324324324 | 2123444 | | | | | | | 6/30/2021 | 1918 |
|
||||||
|
| 12021 | 12021143 | HAYDEN | ALEXANDER | W | H21 | BB | 10/31/2019 | 11/6/2019 | 12/15/2019 | 2/15/2026 | 20171.51 | 3.29 | 4.90 | False | True | False | True | False | 3488 | 9888447543454544 | 232323455 | M233333389Y853128921 | Honda | Civic | 2020 | 1900 | Black | 7/1/2021 | 2294 |
|
||||||
|
| 2233 | 2233143 | JONES | FRED | Y | S7 | NC | 2/1/2021 | 2/5/2021 | 4/1/2021 | 3/1/2024 | 20000 | 3.5 | 5 | false | true | true | false | false | 3434 | 324324324324324 | 21235 | M34kls | Toyota | Camry | 2019 | 5 | Red | 7/3/2021 | 1121 |
|
||||||
|
When I process the closed loan import with detail from DNA at "8/1/2021 5:00:00 AM"
|
||||||
|
Then the import looks like
|
||||||
|
| StartDate | RecordCount | RecordsSaved | Success | Filename | Import Type |
|
||||||
|
| 8/1/2021 5:00:00 AM | 3 | 3 | true | | Closed |
|
||||||
|
And the import has an end date that is greater or equal to the start date
|
||||||
|
And the loans now look like
|
||||||
|
| LoanId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Term | FlatFeePaid | ReserveAmount | Chargeback | Paid Loan Date | LoanStatus | RemainingMonthsAtClose | Adjustment | ActionRequired |
|
||||||
|
| 1 | 3250 | 3250144 | MUELLER | STEVEN | C | 63 | false | 793.9136070432343049958707190 | 0 | 6/30/2021 | Closed | 58 | | false |
|
||||||
|
| 2 | 12021 | 12021143 | HAYDEN | ALEXANDER | W | 75 | false | 1132.5564086943452341656244555 | 611.9778 | 7/1/2021 | Closed | 55 | | false |
|
||||||
|
| 3 | 2233 | 2233143 | JONES | FRED | Y | 37 | false | 392.12008534200236229531665461 | 0 | 7/3/2021 | Closed | 33 | | false |
|
||||||
|
And AddHistoriesAsync is called with 3 history/ies having ActivityType "LoanStatusChange" and AuditDescription "Importing closed loan changed loan status"
|
||||||
|
And ExportChargebacksAsync is called
|
||||||
|
And ExportReservesAsync is called
|
||||||
|
|
||||||
|
Scenario: Import Closed Loans from DNA with loan details, all dealers are added
|
||||||
|
Given an import from DNA that contains
|
||||||
|
| Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Dealer Code | LoanType | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | LoanAmount | Buy Rate | Contract Rate | Gap | Warranty | Mbp | CreditLife | CreditDisability | DealerOrganizationNumber | DealerAccountNumber | DealerName | ApplicationId | VIN | Make | Model | Year | Mileage | Color | PaidLoanDate | OriginalTermInDays |
|
||||||
|
| 3250 | 3250144 | MUELLER | STEVEN | C | S7 | NC | 2/10/2021 | 02/03/2021 | 03/05/2021 | 05/05/2026 | 27889.51 | 2.03 | 3.39 | True | False | False | False | True | 3434 | 324324324324324 | SUBURBAN MOTORS HARLEY DAVIDSON | 2123444 | | | | | | | 6/30/2021 | 1918 |
|
||||||
|
| 12021 | 12021143 | HAYDEN | ALEXANDER | W | H21 | BB | 10/31/2019 | 11/6/2019 | 12/15/2019 | 2/15/2026 | 20171.51 | 3.29 | 4.90 | False | True | False | True | False | 3488 | 9888447543454544 | HEISER CHEVROLET CADILLAC OF WEST BEND | 232323455 | M233333389Y853128921 | Honda | Civic | 2020 | 1900 | Black | 7/1/2021 | 2294 |
|
||||||
|
| 2233 | 2233143 | JONES | FRED | X | S7 | NC | 2/1/2021 | 2/5/2021 | 4/1/2021 | 3/1/2024 | 20000 | 3.5 | 5 | false | true | true | false | false | 3434 | 324324324324324 | SUBURBAN MOTORS HARLEY DAVIDSON | 21235 | M34kls | Toyota | Camry | 2019 | 5 | Red | 7/3/2021 | 1121 |
|
||||||
|
And dealers that look like
|
||||||
|
| Dealer Code | Name | Address1 | Address2 | City | State | Zip | DealerOrganizationNumber | DealerAccountNumber |
|
||||||
|
When I process the closed loan import with detail from DNA at "8/1/2021 5:00:00 AM"
|
||||||
|
Then the import looks like
|
||||||
|
| StartDate | RecordCount | RecordsSaved | Success | Filename | Import Type |
|
||||||
|
| 8/1/2021 5:00:00 AM | 3 | 3 | true | | Closed |
|
||||||
|
And the import has an end date that is greater or equal to the start date
|
||||||
|
And the loans now look like
|
||||||
|
| LoanId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Term | FlatFeePaid | ReserveAmount | Chargeback | Paid Loan Date | LoanStatus | RemainingMonthsAtClose | Adjustment |
|
||||||
|
| 1 | 3250 | 3250144 | MUELLER | STEVEN | C | 63 | false | 793.9136070432343049958707190 | 0 | 6/30/2021 | Closed | 58 | |
|
||||||
|
| 2 | 12021 | 12021143 | HAYDEN | ALEXANDER | W | 75 | false | 1132.5564086943452341656244555 | 611.9778 | 7/1/2021 | Closed | 55 | |
|
||||||
|
| 3 | 2233 | 2233143 | JONES | FRED | X | 37 | false | 392.12008534200236229531665461 | 0 | 7/3/2021 | Closed | 33 | |
|
||||||
|
And the dealers now look like
|
||||||
|
| Dealer Code | Name | DealerOrganizationNumber | DealerAccountNumber |
|
||||||
|
| S7 | SUBURBAN MOTORS HARLEY DAVIDSON | 3434 | 324324324324324 |
|
||||||
|
| H21 | HEISER CHEVROLET CADILLAC OF WEST BEND | 3488 | 9888447543454544 |
|
||||||
|
|
||||||
|
Scenario: Import Closed Loans from DNA with loan details, all dealers are added, but only dealer information from first loan is added
|
||||||
|
Given an import from DNA that contains
|
||||||
|
| Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Dealer Code | LoanType | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | LoanAmount | Buy Rate | Contract Rate | Gap | Warranty | Mbp | CreditLife | CreditDisability | DealerOrganizationNumber | DealerAccountNumber | DealerName | ApplicationId | VIN | Make | Model | Year | Mileage | Color | PaidLoanDate | OriginalTermInDays |
|
||||||
|
| 3250 | 3250144 | MUELLER | STEVEN | C | S7 | NC | 2/10/2021 | 02/03/2021 | 03/05/2021 | 05/05/2026 | 27889.51 | 2.03 | 3.39 | True | False | False | False | True | 3434 | | | 2123444 | | | | | | | 6/30/2021 | 1918 |
|
||||||
|
| 12021 | 12021143 | HAYDEN | ALEXANDER | W | H21 | BB | 10/31/2019 | 11/6/2019 | 12/15/2019 | 2/15/2026 | 20171.51 | 3.29 | 4.90 | False | True | False | True | False | 3488 | 9888447543454544 | HEISER CHEVROLET CADILLAC OF WEST BEND | 232323455 | M233333389Y853128921 | Honda | Civic | 2020 | 1900 | Black | 7/1/2021 | 2294 |
|
||||||
|
| 2233 | 2233143 | JONES | FRED | X | S7 | NC | 2/1/2021 | 2/5/2021 | 4/1/2021 | 3/1/2024 | 20000 | 3.5 | 5 | false | true | true | false | false | 3434 | 324324324324324 | SUBURBAN MOTORS HARLEY DAVIDSON | 21235 | M34kls | Toyota | Camry | 2019 | 5 | Red | 7/3/2021 | 1120 |
|
||||||
|
And dealers that look like
|
||||||
|
| Dealer Code | Name | Address1 | Address2 | City | State | Zip | DealerOrganizationNumber | DealerAccountNumber |
|
||||||
|
When I process the closed loan import with detail from DNA at "8/1/2021 5:00:00 AM"
|
||||||
|
Then the import looks like
|
||||||
|
| StartDate | RecordCount | RecordsSaved | Success | Filename | Import Type |
|
||||||
|
| 8/1/2021 5:00:00 AM | 3 | 3 | true | | Closed |
|
||||||
|
And the import has an end date that is greater or equal to the start date
|
||||||
|
And the loans now look like
|
||||||
|
| LoanId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Term | FlatFeePaid | ReserveAmount | Chargeback | Paid Loan Date | LoanStatus | RemainingMonthsAtClose | Adjustment |
|
||||||
|
| 1 | 3250 | 3250144 | MUELLER | STEVEN | C | 63 | false | 793.9136070432343049958707190 | 0 | 6/30/2021 | Closed | 58 | |
|
||||||
|
| 2 | 12021 | 12021143 | HAYDEN | ALEXANDER | W | 75 | false | 1132.5564086943452341656244555 | 611.9778 | 7/1/2021 | Closed | 55 | |
|
||||||
|
| 3 | 2233 | 2233143 | JONES | FRED | X | 37 | false | 392.12008534200236229531665461 | 0 | 7/3/2021 | Closed | 33 | |
|
||||||
|
And the dealers now look like
|
||||||
|
| Dealer Code | Name | DealerOrganizationNumber | DealerAccountNumber |
|
||||||
|
| S7 | | 3434 | |
|
||||||
|
| H21 | HEISER CHEVROLET CADILLAC OF WEST BEND | 3488 | 9888447543454544 |
|
||||||
|
|
||||||
|
Scenario: Import Closed Loans from DNA with loan details, dealers are updated
|
||||||
|
Given an import from DNA that contains
|
||||||
|
| Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Dealer Code | LoanType | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | LoanAmount | Buy Rate | Contract Rate | Gap | Warranty | Mbp | CreditLife | CreditDisability | DealerOrganizationNumber | DealerAccountNumber | DealerName | ApplicationId | VIN | Make | Model | Year | Mileage | Color | PaidLoanDate | OriginalTermInDays |
|
||||||
|
| 3250 | 3250144 | MUELLER | STEVEN | C | S7 | NC | 2/10/2021 | 02/03/2021 | 03/05/2021 | 05/05/2026 | 27889.51 | 2.03 | 3.39 | True | False | False | False | True | 3434 | 324324324324324 | SUBURBAN MOTORS HARLEY DAVIDSON | 2123444 | | | | | | | 6/30/2021 | 1918 |
|
||||||
|
| 12021 | 12021143 | HAYDEN | ALEXANDER | W | H21 | BB | 10/31/2019 | 11/6/2019 | 12/15/2019 | 2/15/2026 | 20171.51 | 3.29 | 4.90 | False | True | False | True | False | 3488 | 9888447543454544 | HEISER CHEVROLET CADILLAC OF WEST BEND | 232323455 | M233333389Y853128921 | Honda | Civic | 2020 | 1900 | Black | 7/1/2021 | 2294 |
|
||||||
|
| 2233 | 2233143 | JONES | FRED | X | S7 | NC | 2/1/2021 | 2/5/2021 | 4/1/2021 | 3/1/2024 | 20000 | 3.5 | 5 | false | true | true | false | false | 3434 | 324324324324324 | SUBURBAN MOTORS HARLEY DAVIDSON | 21235 | M34kls | Toyota | Camry | 2019 | 5 | Red | 7/3/2021 | 1120 |
|
||||||
|
And dealers that look like
|
||||||
|
| Dealer Code | Name | DealerOrganizationNumber | DealerAccountNumber |
|
||||||
|
| S7 | SUBURBAN MOTORS HD | 3434 | 324324324324324 |
|
||||||
|
When I process the closed loan import with detail from DNA at "8/1/2021 5:00:00 AM"
|
||||||
|
Then the import looks like
|
||||||
|
| StartDate | RecordCount | RecordsSaved | Success | Filename | Import Type |
|
||||||
|
| 8/1/2021 5:00:00 AM | 3 | 3 | true | | Closed |
|
||||||
|
And the import has an end date that is greater or equal to the start date
|
||||||
|
And the loans now look like
|
||||||
|
| LoanId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Term | FlatFeePaid | ReserveAmount | Chargeback | Paid Loan Date | LoanStatus | RemainingMonthsAtClose | Adjustment |
|
||||||
|
| 1 | 3250 | 3250144 | MUELLER | STEVEN | C | 63 | false | 793.9136070432343049958707190 | 0 | 6/30/2021 | Closed | 58 | |
|
||||||
|
| 2 | 12021 | 12021143 | HAYDEN | ALEXANDER | W | 75 | false | 1132.5564086943452341656244555 | 611.9778 | 7/1/2021 | Closed | 55 | |
|
||||||
|
| 3 | 2233 | 2233143 | JONES | FRED | X | 37 | false | 392.12008534200236229531665461 | 0 | 7/3/2021 | Closed | 33 | |
|
||||||
|
And the dealers now look like
|
||||||
|
| Dealer Code | Name | DealerOrganizationNumber | DealerAccountNumber |
|
||||||
|
| S7 | SUBURBAN MOTORS HARLEY DAVIDSON | 3434 | 324324324324324 |
|
||||||
|
| H21 | HEISER CHEVROLET CADILLAC OF WEST BEND | 3488 | 9888447543454544 |
|
||||||
|
|
||||||
+194
@@ -0,0 +1,194 @@
|
|||||||
|
Feature: Import Read Service - Closed Loans
|
||||||
|
Gets closed loans from a stream of csv data, reads loans into memory, calculates chargebacks, saves loans, saves import information
|
||||||
|
|
||||||
|
Scenario: AddImport for Closed Loans - all loans are saved
|
||||||
|
Given an import file named "ClosedLoans 2021-03-01.txt" that contains
|
||||||
|
"""
|
||||||
|
LoanNumber,PaidLoanDate
|
||||||
|
147,02/25/2021
|
||||||
|
143,02/12/2021
|
||||||
|
144,02/12/2021
|
||||||
|
"""
|
||||||
|
And a loan table consisting of
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Dealer Code | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | LoanStatus | RemainingMonthsAtClose |
|
||||||
|
| 1 | 1 | 5841 | 147 | Smith | Joe | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | New | |
|
||||||
|
| 2 | 2 | 10094 | 143 | Jones | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | NC | 60 | 1450.2923 | 500 | false | | | Message | Updated | |
|
||||||
|
| 3 | 2 | 100947 | 144 | Johnson | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | NC | 60 | 1450.2923 | 500 | false | | | Message | New | |
|
||||||
|
When I read this closed loan import file at "3/5/2021 5:00:00 AM"
|
||||||
|
Then the import looks like
|
||||||
|
| StartDate | RecordCount | RecordsSaved | Success | Filename | Import Type |
|
||||||
|
| 3/5/2021 5:00:00 AM | 3 | 3 | true | ClosedLoans 2021-03-01.txt | Closed |
|
||||||
|
And the import has an end date that is greater or equal to the start date
|
||||||
|
And the loans now look like
|
||||||
|
| LoanId | Member Number | Loan Number | Chargeback | Paid Loan Date | LoanStatus | RemainingMonthsAtClose |
|
||||||
|
| 1 | 5841 | 147 | 210.0375 | 2/25/2021 | Closed | 63 |
|
||||||
|
| 2 | 10094 | 143 | 1498.6354 | 2/12/2021 | Closed | 61 |
|
||||||
|
| 3 | 100947 | 144 | 1498.6354 | 2/12/2021 | Closed | 61 |
|
||||||
|
And AddHistoriesAsync is called with 2 history/ies having OldValue "New" and NewValue "Closed"
|
||||||
|
And AddHistoriesAsync is called with 1 history/ies having OldValue "Updated" and NewValue "Closed"
|
||||||
|
And AddHistoriesAsync is called with 3 history/ies having ActivityType "LoanStatusChange" and AuditDescription "Importing closed loan changed loan status"
|
||||||
|
And ExportChargebacksAsync is called
|
||||||
|
|
||||||
|
Scenario: AddImport for Closed Loans - trim fields and header
|
||||||
|
Given an import file named "ClosedLoans 2021-03-01.txt" that contains
|
||||||
|
"""
|
||||||
|
LoanNumber,PaidLoanDate
|
||||||
|
147, 02/25/2021
|
||||||
|
143, 02/12/2021
|
||||||
|
144, 02/12/2021
|
||||||
|
"""
|
||||||
|
And a loan table consisting of
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Dealer Code | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | LoanStatus |
|
||||||
|
| 1 | 1 | 5841 | 147 | Smith | Joe | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | New |
|
||||||
|
| 2 | 2 | 10094 | 143 | Jones | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | New |
|
||||||
|
| 3 | 2 | 10621 | 144 | Johnson | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | New |
|
||||||
|
When I read this closed loan import file at "3/5/2021 5:00:00 AM"
|
||||||
|
Then the import looks like
|
||||||
|
| StartDate | RecordCount | RecordsSaved | Success | Filename | Import Type |
|
||||||
|
| 3/5/2021 5:00:00 AM | 3 | 3 | true | ClosedLoans 2021-03-01.txt | Closed |
|
||||||
|
And the import has an end date that is greater or equal to the start date
|
||||||
|
And the loans now look like
|
||||||
|
| LoanId | Member Number | Loan Number | Chargeback | Paid Loan Date | LoanStatus | RemainingMonthsAtClose |
|
||||||
|
| 1 | 5841 | 147 | 210.0375 | 2/25/2021 | Closed | 63 |
|
||||||
|
| 2 | 10094 | 143 | 1498.6354 | 2/12/2021 | Closed | 61 |
|
||||||
|
| 3 | 10621 | 144 | 1498.6354 | 2/12/2021 | Closed | 61 |
|
||||||
|
And AddHistoriesAsync is called with 3 history/ies having OldValue "New" and NewValue "Closed"
|
||||||
|
And AddHistoriesAsync is called with 3 history/ies having ActivityType "LoanStatusChange" and AuditDescription "Importing closed loan changed loan status"
|
||||||
|
And ExportChargebacksAsync is called
|
||||||
|
|
||||||
|
Scenario: AddImport for Closed Loans - Set Action Required to False
|
||||||
|
Given an import file named "ClosedLoans 2021-03-01.txt" that contains
|
||||||
|
"""
|
||||||
|
LoanNumber,PaidLoanDate
|
||||||
|
147, 02/25/2021
|
||||||
|
143, 02/12/2021
|
||||||
|
144, 02/12/2021
|
||||||
|
"""
|
||||||
|
And a loan table consisting of
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Dealer Code | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | LoanStatus | ActionRequired |
|
||||||
|
| 1 | 1 | 5841 | 147 | Smith | Joe | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | New | true |
|
||||||
|
| 2 | 2 | 10094 | 143 | Jones | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | New | false |
|
||||||
|
| 3 | 2 | 10621 | 144 | Johnson | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | New | true |
|
||||||
|
When I read this closed loan import file at "3/5/2021 5:00:00 AM"
|
||||||
|
Then the import looks like
|
||||||
|
| StartDate | RecordCount | RecordsSaved | Success | Filename | Import Type |
|
||||||
|
| 3/5/2021 5:00:00 AM | 3 | 3 | true | ClosedLoans 2021-03-01.txt | Closed |
|
||||||
|
And the import has an end date that is greater or equal to the start date
|
||||||
|
And the loans now look like
|
||||||
|
| LoanId | Member Number | Loan Number | Chargeback | Paid Loan Date | LoanStatus | RemainingMonthsAtClose | ActionRequired |
|
||||||
|
| 1 | 5841 | 147 | 210.0375 | 2/25/2021 | Closed | 63 | false |
|
||||||
|
| 2 | 10094 | 143 | 1498.6354 | 2/12/2021 | Closed | 61 | false |
|
||||||
|
| 3 | 10621 | 144 | 1498.6354 | 2/12/2021 | Closed | 61 | false |
|
||||||
|
And AddHistoriesAsync is called with 3 history/ies having OldValue "New" and NewValue "Closed"
|
||||||
|
And AddHistoriesAsync is called with 3 history/ies having ActivityType "LoanStatusChange" and AuditDescription "Importing closed loan changed loan status"
|
||||||
|
And ExportChargebacksAsync is called
|
||||||
|
|
||||||
|
Scenario: AddImport for Closed Loans - header case insensitive
|
||||||
|
Given an import file named "ClosedLoans 2021-03-01.txt" that contains
|
||||||
|
"""
|
||||||
|
loannumber,PaidLoanDate
|
||||||
|
147, 02/25/2021
|
||||||
|
143, 02/12/2021
|
||||||
|
144, 02/12/2021
|
||||||
|
"""
|
||||||
|
And a loan table consisting of
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Dealer Code | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | LoanStatus |
|
||||||
|
| 1 | 1 | 5841 | 147 | Smith | Joe | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | New |
|
||||||
|
| 2 | 2 | 10094 | 143 | Jones | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | New |
|
||||||
|
| 3 | 2 | 10621 | 144 | Johnson | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | New |
|
||||||
|
When I read this closed loan import file at "3/5/2021 5:00:00 AM"
|
||||||
|
Then the import looks like
|
||||||
|
| StartDate | RecordCount | RecordsSaved | Success | Filename | Import Type |
|
||||||
|
| 3/5/2021 5:00:00 AM | 3 | 3 | true | ClosedLoans 2021-03-01.txt | Closed |
|
||||||
|
And the loans now look like
|
||||||
|
| LoanId | Member Number | Loan Number | Chargeback | Paid Loan Date | LoanStatus | RemainingMonthsAtClose |
|
||||||
|
| 1 | 5841 | 147 | 210.0375 | 2/25/2021 | Closed | 63 |
|
||||||
|
| 2 | 10094 | 143 | 1498.6354 | 2/12/2021 | Closed | 61 |
|
||||||
|
| 3 | 10621 | 144 | 1498.6354 | 2/12/2021 | Closed | 61 |
|
||||||
|
And the import has an end date that is greater or equal to the start date
|
||||||
|
And AddHistoriesAsync is called with 3 history/ies having OldValue "New" and NewValue "Closed"
|
||||||
|
And AddHistoriesAsync is called with 3 history/ies having ActivityType "LoanStatusChange" and AuditDescription "Importing closed loan changed loan status"
|
||||||
|
And ExportChargebacksAsync is called
|
||||||
|
|
||||||
|
Scenario: AddImport for Closed Loans - saves two loans that are in the loan table
|
||||||
|
Given an import file named "ClosedLoans 2021-03-01.txt" that contains
|
||||||
|
"""
|
||||||
|
LoanNumber,PaidLoanDate
|
||||||
|
149,02/25/2021
|
||||||
|
143,02/12/2021
|
||||||
|
144,02/12/2021
|
||||||
|
"""
|
||||||
|
And a loan table consisting of
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Dealer Code | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | LoanStatus |
|
||||||
|
| 1 | 1 | 12 | 3 | Smith | Joe | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | New |
|
||||||
|
| 2 | 2 | 10094 | 143 | Jones | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | New |
|
||||||
|
| 3 | 2 | 10621 | 144 | Johnson | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | New |
|
||||||
|
When I read this closed loan import file at "3/5/2021 5:00:00 AM"
|
||||||
|
Then the import looks like
|
||||||
|
| StartDate | RecordCount | RecordsSaved | Success | Filename | Import Type |
|
||||||
|
| 3/5/2021 5:00:00 AM | 3 | 2 | true | ClosedLoans 2021-03-01.txt | Closed |
|
||||||
|
And the import has an end date that is greater or equal to the start date
|
||||||
|
And the loans now look like
|
||||||
|
| LoanId | Member Number | Loan Number | Chargeback | Paid Loan Date | LoanStatus | RemainingMonthsAtClose |
|
||||||
|
| 1 | 12 | 3 | | | New | |
|
||||||
|
| 2 | 10094 | 143 | 1498.6354 | 2/12/2021 | Closed | 61 |
|
||||||
|
| 3 | 10621 | 144 | 1498.6354 | 2/12/2021 | Closed | 61 |
|
||||||
|
And AddHistoriesAsync is called with 2 history/ies having OldValue "New" and NewValue "Closed"
|
||||||
|
And AddHistoriesAsync is called with 2 history/ies having ActivityType "LoanStatusChange" and AuditDescription "Importing closed loan changed loan status"
|
||||||
|
And AddHistoriesAsync is called with 1 history/ies having ActivityType "Error" and AuditDescription "Loan in closed import not found"
|
||||||
|
And ExportChargebacksAsync is called
|
||||||
|
|
||||||
|
Scenario: AddImport for Closed Boat Loans - saves two loans that are in the loan table
|
||||||
|
Given an import file named "ClosedLoans 2021-03-01.txt" that contains
|
||||||
|
"""
|
||||||
|
LoanNumber,PaidLoanDate,AccountType
|
||||||
|
151,02/25/2021,DL10
|
||||||
|
143,04/12/2021,DL11
|
||||||
|
144,04/12/2021,DL12
|
||||||
|
"""
|
||||||
|
And a loan table consisting of
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Dealer Code | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | LoanStatus | AccountType |
|
||||||
|
| 1 | 1 | 12 | 3 | Smith | Joe | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | New | DL10 |
|
||||||
|
| 2 | 2 | 10094 | 143 | Jones | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | NC | 60 | 1450.2923 | 500 | false | | | Message | New | DL11 |
|
||||||
|
| 3 | 2 | 10621 | 144 | Johnson | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 1/10/2027 | 21274.24 | 2.490 | 4.470 | NC | 70 | 1063.7120 | 500 | false | | | Message | New | DL12 |
|
||||||
|
When I read this closed loan import file at "3/5/2021 5:00:00 AM"
|
||||||
|
Then the import looks like
|
||||||
|
| StartDate | RecordCount | RecordsSaved | Success | Filename | Import Type |
|
||||||
|
| 3/5/2021 5:00:00 AM | 3 | 2 | true | ClosedLoans 2021-03-01.txt | Closed |
|
||||||
|
And the import has an end date that is greater or equal to the start date
|
||||||
|
And the loans now look like
|
||||||
|
| LoanId | Member Number | Loan Number | Chargeback | Paid Loan Date | LoanStatus | RemainingMonthsAtClose |
|
||||||
|
| 1 | 12 | 3 | | | New | |
|
||||||
|
| 2 | 10094 | 143 | 1402.7417 | 4/12/2021 | Closed | 59 |
|
||||||
|
| 3 | 10621 | 144 | 1033.7483 | 4/12/2021 | Closed | 69 |
|
||||||
|
And AddHistoriesAsync is called with 2 history/ies having OldValue "New" and NewValue "Closed"
|
||||||
|
And AddHistoriesAsync is called with 2 history/ies having ActivityType "LoanStatusChange" and AuditDescription "Importing closed loan changed loan status"
|
||||||
|
And AddHistoriesAsync is called with 1 history/ies having ActivityType "Error" and AuditDescription "Loan in closed import not found"
|
||||||
|
And ExportChargebacksAsync is called
|
||||||
|
|
||||||
|
Scenario: AddImport - file has a header with one column named incorrectly
|
||||||
|
Given an import file named "ClosedLoans 2021-03-01.txt" that contains
|
||||||
|
"""
|
||||||
|
LoanNumber,PaidDate
|
||||||
|
147,02/25/2021
|
||||||
|
143,02/12/2021
|
||||||
|
144,02/12/2021
|
||||||
|
"""
|
||||||
|
When I read this closed loan import file at "3/5/2021 5:00:00 AM"
|
||||||
|
And I get the record from the ImportTable
|
||||||
|
Then the import looks like
|
||||||
|
| StartDate | EndDate | RecordCount | RecordsSaved | Success | Filename | Import Type |
|
||||||
|
| 3/5/2021 5:00:00 AM | | 0 | 0 | false | ClosedLoans 2021-03-01.txt | Closed |
|
||||||
|
|
||||||
|
Scenario: AddImport - file is missing the header
|
||||||
|
Given an import file named "ClosedLoans 2021-03-01.txt" that contains
|
||||||
|
"""
|
||||||
|
147,02/25/2021
|
||||||
|
143,02/12/2021
|
||||||
|
144,02/12/2021
|
||||||
|
"""
|
||||||
|
When I read this closed loan import file at "3/5/2021 5:00:00 AM"
|
||||||
|
And I get the record from the ImportTable
|
||||||
|
Then the import looks like
|
||||||
|
| StartDate | EndDate | RecordCount | RecordsSaved | Success | Filename | Import Type |
|
||||||
|
| 3/5/2021 5:00:00 AM | | 0 | 0 | false | ClosedLoans 2021-03-01.txt | Closed |
|
||||||
+1753
File diff suppressed because it is too large
Load Diff
+234
@@ -0,0 +1,234 @@
|
|||||||
|
Feature: Import Read Service - New Loans
|
||||||
|
Gets loans from a stream of csv data, reads loans into memory, calculates reserve, saves loans, saves import information
|
||||||
|
|
||||||
|
Scenario: AddImport - happy path
|
||||||
|
Given an import file named "NewLoans 2021-03-01.txt" that contains
|
||||||
|
"""
|
||||||
|
3434,3250,144,MUELLER, STEVEN C,02/10/2021,02/12/2021,03/12/2021,2/12/2025,25989.97,2.03,3.39,579.76,NC,XX,N,1462
|
||||||
|
4545,12021,143,HAYDEN, ALEXANDER W,01/23/2021,02/02/2021,03/09/2021,2/9/2027,14975.57,4.39,6.39,251.61,NC,XX,N,2189
|
||||||
|
"""
|
||||||
|
When I read this new loan import file at "3/5/2021 5:00:00 AM"
|
||||||
|
Then the import looks like
|
||||||
|
| StartDate | RecordCount | RecordsSaved | Success | Filename | Import Type |
|
||||||
|
| 3/5/2021 5:00:00 AM | 2 | 2 | true | NewLoans 2021-03-01.txt | Active |
|
||||||
|
And the import has an end date that is greater or equal to the start date
|
||||||
|
And the loans now look like
|
||||||
|
| ImportId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | DealerOrganizationNumber | Loan Date | Buy Rate | Contract Rate | Loan Status | ExportedReserveDate | Term |
|
||||||
|
| 1 | 3250 | 144 | MUELLER | STEVEN | C | 3434 | 2/10/2021 | 2.03 | 3.39 | New | | 48 |
|
||||||
|
| 1 | 12021 | 143 | HAYDEN | ALEXANDER | W | 4545 | 1/23/2021 | 4.39 | 6.39 | New | | 72 |
|
||||||
|
And ExportReservesAsync is called
|
||||||
|
|
||||||
|
Scenario: AddImport with Boat Loan Account Type
|
||||||
|
Given an import file named "NewLoans 2021-03-01.txt" that contains
|
||||||
|
"""
|
||||||
|
3434,71229741,143,WILLIAMS,SAM R,01/06/2021,02/03/2021,03/05/2021,05/05/2026,27889.51,2.49,4.49,472.71,NC,XX,N,1918,M233333389Y85312,Honda,Civic,2020,1900,Black,1245988,false,false,false,false,false,DL10
|
||||||
|
"""
|
||||||
|
When I read this new loan import file at "3/5/2021 5:00:00 AM"
|
||||||
|
Then the import looks like
|
||||||
|
| StartDate | RecordCount | RecordsSaved | Success | Filename | Import Type |
|
||||||
|
| 3/5/2021 5:00:00 AM | 1 | 1 | true | NewLoans 2021-03-01.txt | Active |
|
||||||
|
And the import has an end date that is greater or equal to the start date
|
||||||
|
And the loans now look like
|
||||||
|
| ImportId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | DealerOrganizationNumber | Loan Date | Buy Rate | Contract Rate | Loan Status | ExportedReserveDate | ReserveAmount | ReserveMessage | Term |
|
||||||
|
| 1 | 71229741 | 143 | WILLIAMS | SAM | R | 3434 | 1/06/2021 | 2.49 | 4.49 | New | | 1673.3706 | Standard Reserve | 63 |
|
||||||
|
And ExportReservesAsync is called
|
||||||
|
|
||||||
|
Scenario: AddImport - file is wrong format (missing column, etc.) - note that this doesn't return the import that was saved but it is in the table
|
||||||
|
Given an import file named "NewLoans 2021-03-01.txt" that contains
|
||||||
|
"""
|
||||||
|
C9,3250,144,MUELLER, STEVEN C,02/10/2021,03/12/2021,2/12/2025,25989.97,2.03,3.39,579.76,NC,XX,N
|
||||||
|
R23,12021,143,HAYDEN, ALEXANDER W,01/23/2021,03/09/2021,2/9/2027,14975.57,4.39,6.39,251.61,NC,XX,N
|
||||||
|
"""
|
||||||
|
When I read this new loan import file at "3/5/2021 5:00:00 AM"
|
||||||
|
And I get the record from the ImportTable
|
||||||
|
Then the import looks like
|
||||||
|
| StartDate | EndDate | RecordCount | RecordsSaved | Success | Filename | Import Type |
|
||||||
|
| 3/5/2021 5:00:00 AM | | 0 | 0 | false | NewLoans 2021-03-01.txt | Active |
|
||||||
|
And ExportReservesAsync is not called
|
||||||
|
|
||||||
|
Scenario: AddImport - file name has more than 50 characters
|
||||||
|
Given an import file named "NewLoans 2021-03-011234567890123456789012345678901234567890.txt" that contains
|
||||||
|
"""
|
||||||
|
1234,3250,144,MUELLER, STEVEN C,02/10/2021,02/12/2021,03/12/2021,2/12/2025,25989.97,2.03,3.39,579.76,NC,XX,N,1462
|
||||||
|
5678,12021,143,HAYDEN, ALEXANDER W,01/23/2021,02/02/2021,03/09/2021,2/9/2027,14975.57,4.39,6.39,251.61,NC,XX,N,2189
|
||||||
|
"""
|
||||||
|
When I read this new loan import file at "3/5/2021 5:00:00 AM"
|
||||||
|
Then the import looks like
|
||||||
|
| StartDate | RecordCount | RecordsSaved | Success | Filename |
|
||||||
|
| 3/5/2021 5:00:00 AM | 2 | 2 | true | NewLoans 2021-03-011234567890123456789012345678901 |
|
||||||
|
And the import has an end date that is greater or equal to the start date
|
||||||
|
And the loans now look like
|
||||||
|
| ImportId | Member Number | Loan Number | Member LastName | Member First Name | Member Initial | DealerOrganizationNumber | Loan Date | Buy Rate | Contract Rate | Loan Status | ExportedReserveDate | Term |
|
||||||
|
| 1 | 3250 | 144 | MUELLER | STEVEN | C | 1234 | 2/10/2021 | 2.03 | 3.39 | New | | 48 |
|
||||||
|
| 1 | 12021 | 143 | HAYDEN | ALEXANDER | W | 5678 | 1/23/2021 | 4.39 | 6.39 | New | | 72 |
|
||||||
|
And ExportReservesAsync is called
|
||||||
|
|
||||||
|
Scenario: AddImport for Update Loans - updates three new loans that are in the loan table, saves one brand new loan
|
||||||
|
Given an import file named "NewLoans 2021-03-01.txt" that contains
|
||||||
|
"""
|
||||||
|
3434,13,3,SMITH, JOE,02/25/2021,02/28/2021,04/11/2021,6/11/2026,12615.87,4.03,5.790,579.76,NC,XX,N,1930
|
||||||
|
4545,3250,144,MUELLER, STEVEN C,02/10/2021,02/12/2021,03/12/2021,2/12/2025,25989.97,2.03,3.39,579.76,NC,XX,N,1462
|
||||||
|
1212,12021,143,HAYDEN, ALEXANDER W,01/23/2021,02/02/2021,03/09/2021,2/9/2027,14975.57,4.39,6.39,251.61,NC,XX,N,2199
|
||||||
|
7878,13991,145,RUTHENBERG, RICHARD J,01/22/2021,02/02/2021,03/08/2021,5/8/2027,32891.50,2.43,3.19,484.92,NC,XX,N,2287
|
||||||
|
"""
|
||||||
|
And a loan table consisting of
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | DealerOrganizationNumber | Loan Date | Buy Rate | Contract Rate | LoanStatus | ExportedReserveDate | Term |
|
||||||
|
| 1 | 1 | 13 | 3 | SMITH | JOE | | 3434 | 2/25/2021 | 4.030 | 4.790 | New | 5/2/2021 | 63 |
|
||||||
|
| 2 | 1 | 3250 | 144 | MUELLER | STEVEN | C | 4545 | 2/10/2021 | 2.03 | 3.39 | New | 5/2/2021 | 48 |
|
||||||
|
| 3 | 1 | 12021 | 143 | HAYDEN | ALEXANDER | W | 1212 | 1/23/2021 | 4.39 | 6.39 | New | 5/2/2021 | 72 |
|
||||||
|
When I read this new loan import file at "3/5/2021 5:00:00 AM"
|
||||||
|
Then the import looks like
|
||||||
|
| StartDate | RecordCount | RecordsSaved | Success | Filename |
|
||||||
|
| 3/5/2021 5:00:00 AM | 4 | 4 | true | NewLoans 2021-03-01.txt |
|
||||||
|
And the import has an end date that is greater or equal to the start date
|
||||||
|
And the loans now look like
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | DealerOrganizationNumber | Loan Date | Buy Rate | Contract Rate | LoanStatus | ExportedReserveDate | Term |
|
||||||
|
| 1 | 1 | 13 | 3 | SMITH | JOE | | 3434 | 2/25/2021 12:00:00 AM | 4.03 | 5.790 | Updated | | 63 |
|
||||||
|
| 2 | 1 | 3250 | 144 | MUELLER | STEVEN | C | 4545 | 2/10/2021 12:00:00 AM | 2.03 | 3.39 | Updated | | 48 |
|
||||||
|
| 3 | 1 | 12021 | 143 | HAYDEN | ALEXANDER | W | 1212 | 1/23/2021 12:00:00 AM | 4.39 | 6.39 | Updated | | 72 |
|
||||||
|
| 4 | 1 | 13991 | 145 | RUTHENBERG | RICHARD | J | 7878 | 1/22/2021 12:00:00 AM | 2.43 | 3.19 | New | | 75 |
|
||||||
|
And AddHistoriesAsync is called with 3 history/ies having ActivityType "NewLoanUpdate" and AuditDescription "Loan found in table, record updated"
|
||||||
|
And AddHistoriesAsync is called with 1 history/ies having LoanNumber "3" and MemberNumber "13"
|
||||||
|
And ExportReservesAsync is called
|
||||||
|
|
||||||
|
Scenario: AddImport for Update Loans - updates three new loans that are in the loan table, one loan has ten thousandth decimal place difference in buy rate, and same with contract rate, round down
|
||||||
|
Given an import file named "NewLoans 2021-03-01.txt" that contains
|
||||||
|
"""
|
||||||
|
3434,13,3,SMITH, JOE,02/25/2021,02/28/2021,04/11/2021,6/11/2026,12615.87,4.03124,5.790,579.76,NC,XX,N,1930
|
||||||
|
4545,3250,144,MUELLER, STEVEN C,02/10/2021,02/12/2021,03/12/2021,2/12/2025,25989.97,2.03,3.39,579.76,NC,XX,N,1462
|
||||||
|
1212,12021,143,HAYDEN, ALEXANDER W,01/23/2021,02/02/2021,03/09/2021,2/9/2027,14975.57,4.39,6.39,251.61,NC,XX,N,2199
|
||||||
|
7878,13991,145,RUTHENBERG, RICHARD J,01/22/2021,02/02/2021,03/08/2021,5/8/2027,32891.50,2.43,3.19,484.92,NC,XX,N,2287
|
||||||
|
"""
|
||||||
|
And a loan table consisting of
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | DealerOrganizationNumber | Loan Date | Buy Rate | Contract Rate | LoanStatus | ExportedReserveDate | Term |
|
||||||
|
| 1 | 1 | 13 | 3 | SMITH | JOE | | 3434 | 2/25/2021 | 4.031 | 4.790 | New | 5/2/2021 | 63 |
|
||||||
|
| 2 | 1 | 3250 | 144 | MUELLER | STEVEN | C | 4545 | 2/10/2021 | 2.03 | 3.39 | New | 5/2/2021 | 48 |
|
||||||
|
| 3 | 1 | 12021 | 143 | HAYDEN | ALEXANDER | W | 1212 | 1/23/2021 | 4.39 | 6.39 | New | 5/2/2021 | 72 |
|
||||||
|
When I read this new loan import file at "3/5/2021 5:00:00 AM"
|
||||||
|
Then the import looks like
|
||||||
|
| StartDate | RecordCount | RecordsSaved | Success | Filename |
|
||||||
|
| 3/5/2021 5:00:00 AM | 4 | 4 | true | NewLoans 2021-03-01.txt |
|
||||||
|
And the import has an end date that is greater or equal to the start date
|
||||||
|
And the loans now look like
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | DealerOrganizationNumber | Loan Date | Buy Rate | Contract Rate | LoanStatus | ExportedReserveDate | Term |
|
||||||
|
| 1 | 1 | 13 | 3 | SMITH | JOE | | 3434 | 2/25/2021 12:00:00 AM | 4.031 | 5.790 | Updated | | 63 |
|
||||||
|
| 2 | 1 | 3250 | 144 | MUELLER | STEVEN | C | 4545 | 2/10/2021 12:00:00 AM | 2.03 | 3.39 | Updated | | 48 |
|
||||||
|
| 3 | 1 | 12021 | 143 | HAYDEN | ALEXANDER | W | 1212 | 1/23/2021 12:00:00 AM | 4.39 | 6.39 | Updated | | 72 |
|
||||||
|
| 4 | 1 | 13991 | 145 | RUTHENBERG | RICHARD | J | 7878 | 1/22/2021 12:00:00 AM | 2.43 | 3.19 | New | | 75 |
|
||||||
|
And AddHistoriesAsync is called with 3 history/ies having ActivityType "NewLoanUpdate" and AuditDescription "Loan found in table, record updated"
|
||||||
|
And AddHistoriesAsync is called with 1 history/ies having LoanNumber "3" and MemberNumber "13"
|
||||||
|
And ExportReservesAsync is called
|
||||||
|
|
||||||
|
Scenario: AddImport for Update Loans - updates three new loans that are in the loan table, one loan has ten thousandth decimal place difference in buy rate, and same with contract rate, round up
|
||||||
|
Given an import file named "NewLoans 2021-03-01.txt" that contains
|
||||||
|
"""
|
||||||
|
3434,13,3,SMITH, JOE,02/25/2021,02/28/2021,04/11/2021,6/11/2026,12615.87,4.03155,5.790,579.76,NC,XX,N,1930
|
||||||
|
4545,3250,144,MUELLER, STEVEN C,02/10/2021,02/12/2021,03/12/2021,2/12/2025,25989.97,2.03,3.39,579.76,NC,XX,N,1462
|
||||||
|
1212,12021,143,HAYDEN, ALEXANDER W,01/23/2021,02/02/2021,03/09/2021,2/9/2027,14975.57,4.39,6.2465,251.61,NC,XX,N,2199
|
||||||
|
7878,13991,145,RUTHENBERG, RICHARD J,01/22/2021,02/02/2021,03/08/2021,5/8/2027,32891.50,2.43,3.19,484.92,NC,XX,N,2287
|
||||||
|
"""
|
||||||
|
And a loan table consisting of
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | DealerOrganizationNumber | Loan Date | Buy Rate | Contract Rate | LoanStatus | ExportedReserveDate | Term |
|
||||||
|
| 1 | 1 | 13 | 3 | SMITH | JOE | | 3434 | 2/25/2021 | 4.031 | 5.790 | New | 5/2/2021 | 63 |
|
||||||
|
| 2 | 1 | 3250 | 144 | MUELLER | STEVEN | C | 4545 | 2/10/2021 | 2.03 | 3.39 | New | 5/2/2021 | 48 |
|
||||||
|
| 3 | 1 | 12021 | 143 | HAYDEN | ALEXANDER | W | 1212 | 1/23/2021 | 4.39 | 6.246 | New | 5/2/2021 | 72 |
|
||||||
|
When I read this new loan import file at "3/5/2021 5:00:00 AM"
|
||||||
|
Then the import looks like
|
||||||
|
| StartDate | RecordCount | RecordsSaved | Success | Filename |
|
||||||
|
| 3/5/2021 5:00:00 AM | 4 | 4 | true | NewLoans 2021-03-01.txt |
|
||||||
|
And the import has an end date that is greater or equal to the start date
|
||||||
|
And the loans now look like
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | DealerOrganizationNumber | Loan Date | Buy Rate | Contract Rate | LoanStatus | ExportedReserveDate | Term |
|
||||||
|
| 1 | 1 | 13 | 3 | SMITH | JOE | | 3434 | 2/25/2021 12:00:00 AM | 4.032 | 5.790 | Updated | | 63 |
|
||||||
|
| 2 | 1 | 3250 | 144 | MUELLER | STEVEN | C | 4545 | 2/10/2021 12:00:00 AM | 2.03 | 3.39 | Updated | | 48 |
|
||||||
|
| 3 | 1 | 12021 | 143 | HAYDEN | ALEXANDER | W | 1212 | 1/23/2021 12:00:00 AM | 4.39 | 6.247 | Updated | | 72 |
|
||||||
|
| 4 | 1 | 13991 | 145 | RUTHENBERG | RICHARD | J | 7878 | 1/22/2021 12:00:00 AM | 2.43 | 3.19 | New | | 75 |
|
||||||
|
And AddHistoriesAsync is called with 3 history/ies having ActivityType "NewLoanUpdate" and AuditDescription "Loan found in table, record updated"
|
||||||
|
And AddHistoriesAsync is called with 1 history/ies having LoanNumber "3" and MemberNumber "13"
|
||||||
|
And ExportReservesAsync is called
|
||||||
|
|
||||||
|
Scenario: AddImport for Update Loans - updates one loan that is in the loan table, 1 records to audit table for updates
|
||||||
|
Given an import file named "NewLoans 2021-03-01.txt" that contains
|
||||||
|
"""
|
||||||
|
3434,12,3,SMITH, JOE,02/25/2021,02/28/2021,04/11/2021,6/11/2026,12615.87,4.03,5.790,579.76,NC,XX,N,1930
|
||||||
|
"""
|
||||||
|
And a loan table consisting of
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | DealerOrganizationNumber | Loan Date | Buy Rate | Contract Rate | LoanStatus | ExportedReserveDate | Term |
|
||||||
|
| 1 | 1 | 12 | 3 | SMITH | JOE | | 3434 | 2/25/2021 | 4.030 | 4.790 | New | 5/2/2021 | 63 |
|
||||||
|
When I read this new loan import file at "3/5/2021 5:00:00 AM"
|
||||||
|
Then the import looks like
|
||||||
|
| StartDate | RecordCount | RecordsSaved | Success | Filename | Import Type |
|
||||||
|
| 3/5/2021 5:00:00 AM | 1 | 1 | true | NewLoans 2021-03-01.txt | Active |
|
||||||
|
And the import has an end date that is greater or equal to the start date
|
||||||
|
And the loans now look like
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | DealerOrganizationNumber | Loan Date | Buy Rate | Contract Rate | LoanStatus | ExportedReserveDate | Term |
|
||||||
|
| 1 | 1 | 12 | 3 | SMITH | JOE | | 3434 | 2/25/2021 12:00:00 AM | 4.03 | 5.790 | Updated | | 63 |
|
||||||
|
And AddHistoriesAsync is called with 1 history/ies having ActivityType "NewLoanUpdate" and AuditDescription "Loan found in table, record updated"
|
||||||
|
And AddHistoriesAsync is called with 1 history/ies having LoanNumber "3" and MemberNumber "12"
|
||||||
|
And ExportReservesAsync is called
|
||||||
|
|
||||||
|
Scenario: AddImport - Vehicle Info - One record populated with VIN, one record optional, Not checking for invalid dealer code any more, Two Invalid Missing VIN action required True
|
||||||
|
Given an import file named "NewLoans 2021-05-19.txt" that contains
|
||||||
|
"""
|
||||||
|
3434,71229741,143,WILLIAMS,SAM R,01/06/2021,02/03/2021,03/05/2021,05/05/2026,27889.51,2.49,2.49,472.71,NC,XX,N,1918,M233333389Y85312,Honda,Civic,2020,1900,Black
|
||||||
|
4545,7488740,144,STERLING, JIM C,01/06/2021,02/03/2021,03/05/2021,05/05/2026,27889.51,2.49,2.49,472.71,NC,XX,N,1918
|
||||||
|
4545,8488740,144,STERLING, KIM C,01/06/2021,02/03/2021,03/05/2021,05/05/2026,27889.51,2.49,2.49,472.71,NC,XX,N,1918,,Honda,Civic,2020,1900,Black
|
||||||
|
"""
|
||||||
|
And dealers that look like
|
||||||
|
| Dealer Code | Name | DealerOrganizationNumber |
|
||||||
|
| S7 | SUBURBAN MOTORS HARLEY DAVIDSON | 3333 |
|
||||||
|
| H21 | HEISER CHEVROLET CADILLAC OF WEST BEND | 4545 |
|
||||||
|
When I read this new loan import file at "5/19/2021 1:00:00 PM"
|
||||||
|
Then the import looks like
|
||||||
|
| StartDate | RecordCount | RecordsSaved | Success | Filename | Import Type |
|
||||||
|
| 5/19/2021 1:00:00 PM | 3 | 3 | true | NewLoans 2021-05-19.txt | Active |
|
||||||
|
And the loans now look like
|
||||||
|
| ImportId | LoanId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | DealerOrganizationNumber | Loan Date | Buy Rate | Contract Rate | Loan Status | Action Required | ExportedReserveDate | Term |
|
||||||
|
| 1 | 1 | 71229741 | 143 | WILLIAMS | SAM | R | 3434 | 1/06/2021 | 2.49 | 2.49 | New | False | | 63 |
|
||||||
|
| 1 | 2 | 7488740 | 144 | STERLING | JIM | C | 4545 | 1/06/2021 | 2.49 | 2.49 | New | True | | 63 |
|
||||||
|
| 1 | 3 | 8488740 | 144 | STERLING | KIM | C | 4545 | 1/06/2021 | 2.49 | 2.49 | New | True | | 63 |
|
||||||
|
And ExportReservesAsync is called
|
||||||
|
|
||||||
|
Scenario: AddImport - Vehicle Info - One record populated with VIN, one record optional
|
||||||
|
Given an import file named "NewLoans 2021-05-19.txt" that contains
|
||||||
|
"""
|
||||||
|
3434,71229741,143,WILLIAMS,SAM R,01/06/2021,02/03/2021,03/05/2021,05/05/2026,27889.51,2.49,2.49,472.71,NC,XX,N,1918
|
||||||
|
4545,7488740,144,STERLING, JIM C,01/06/2021,02/03/2021,03/05/2021,05/05/2026,27889.51,2.49,2.49,472.71,NC,XX,N,1918,M233333389Y85312,Honda,Civic,2020,1900,Black
|
||||||
|
"""
|
||||||
|
When I read this new loan import file at "5/19/2021 1:00:00 PM"
|
||||||
|
Then the import looks like
|
||||||
|
| StartDate | RecordCount | RecordsSaved | Success | Filename | Import Type |
|
||||||
|
| 5/19/2021 1:00:00 PM | 2 | 2 | true | NewLoans 2021-05-19.txt | Active |
|
||||||
|
And the loans now look like
|
||||||
|
| ImportId | LoanId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | DealerOrganizationNumber | Loan Date | Buy Rate | Contract Rate | Loan Status | ExportedReserveDate | Term |
|
||||||
|
| 1 | 1 | 71229741 | 143 | WILLIAMS | SAM | R | 3434 | 1/06/2021 | 2.49 | 2.49 | New | | 63 |
|
||||||
|
| 1 | 2 | 7488740 | 144 | STERLING | JIM | C | 4545 | 1/06/2021 | 2.49 | 2.49 | New | | 63 |
|
||||||
|
And the vehicle for LoanId 2 looks like this
|
||||||
|
| VIN Number | LoanId | Make | Model | Year | Mileage | Color |
|
||||||
|
| M233333389Y85312 | 2 | Honda | Civic | 2020 | 1900 | Black |
|
||||||
|
And the vehicle for LoanId 1 looks like this
|
||||||
|
| VIN Number | LoanId | Make | Model | Year | Mileage | Color |
|
||||||
|
| | 1 | | | | 0 | |
|
||||||
|
And ExportReservesAsync is called
|
||||||
|
|
||||||
|
Scenario: AddImport - Vehicle Info - Both records populated with VIN, can handle VIN longer than 17 characters
|
||||||
|
Given an import file named "NewLoans 2021-05-19-2.txt" that contains
|
||||||
|
"""
|
||||||
|
3434,7488740,144,SWEENEY, JIM C,01/06/2021,02/03/2021,03/05/2021,05/05/2026,27889.51,2.49,2.49,472.71,NC,XX,N,1918,M733P33389Y85216,Chevrolet,Cruze,2013,10K,White
|
||||||
|
4545,71229741,143,BARNES,BILL R,01/06/2021,02/03/2021,03/05/2021,05/05/2026,27889.51,2.49,2.49,472.71,NC,XX,N,1918,M233333389Y853128921,Buick,LaCrosse,2017,56000,Burgundy
|
||||||
|
"""
|
||||||
|
When I read this new loan import file at "5/19/2021 1:00:00 PM"
|
||||||
|
Then the import looks like
|
||||||
|
| StartDate | RecordCount | RecordsSaved | Success | Filename | Import Type |
|
||||||
|
| 5/19/2021 1:00:00 PM | 2 | 2 | true | NewLoans 2021-05-19-2.txt | Active |
|
||||||
|
And the loans now look like
|
||||||
|
| ImportId | LoanId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | DealerOrganizationNumber | Loan Date | Buy Rate | Contract Rate | Loan Status | ExportedReserveDate | Term |
|
||||||
|
| 1 | 1 | 7488740 | 144 | SWEENEY | JIM | C | 3434 | 1/06/2021 | 2.49 | 2.49 | New | | 63 |
|
||||||
|
| 1 | 2 | 71229741 | 143 | BARNES | BILL | R | 4545 | 1/06/2021 | 2.49 | 2.49 | New | | 63 |
|
||||||
|
And the vehicle for LoanId 1 looks like this
|
||||||
|
| VehicleId | VIN Number | LoanId | Make | Model | Year | Mileage | Color |
|
||||||
|
| 1 | M733P33389Y85216 | 1 | Chevrolet | Cruze | 2013 | 0 | White |
|
||||||
|
And the vehicle for LoanId 2 looks like this
|
||||||
|
| VehicleId | VIN Number | LoanId | Make | Model | Year | Mileage | Color |
|
||||||
|
| 2 | M233333389Y853128921 | 2 | Buick | LaCrosse | 2017 | 56000 | Burgundy |
|
||||||
|
And ExportReservesAsync is called
|
||||||
+434
@@ -0,0 +1,434 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Moq;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Text;
|
||||||
|
using TechTalk.SpecFlow;
|
||||||
|
using TechTalk.SpecFlow.Assist;
|
||||||
|
using TechTalk.SpecFlow.Assist.ValueRetrievers;
|
||||||
|
using Xunit;
|
||||||
|
using ReserveManagementSystemApi.ServiceClients;
|
||||||
|
using ReserveManagementSystemApi.Services;
|
||||||
|
using ReserveManagementSystemLib.Configuration;
|
||||||
|
using ReserveManagementSystemLib.Models;
|
||||||
|
using ReserveManagementSystemLib.Persistence;
|
||||||
|
using ReserveManagementSystemLib.Repositories;
|
||||||
|
using LCU.Library.Internal.ApiSecurity.Enums;
|
||||||
|
using LCU.Library.Internal.ApiSecurity.Models;
|
||||||
|
using LCU.Library.Internal.CoreApiWrapperModel.CoreModels.IndirectLoan;
|
||||||
|
using LCU.Library.Internal.LcuHttpClient.HttpRequest;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi.Tests.Features
|
||||||
|
{
|
||||||
|
[Binding]
|
||||||
|
public sealed class ImportReadServiceSteps
|
||||||
|
{
|
||||||
|
// For additional details on SpecFlow step definitions see https://go.specflow.org/doc-stepdef
|
||||||
|
|
||||||
|
private readonly ScenarioContext _scenarioContext;
|
||||||
|
private ApiSecurityConfiguration _apiSecurityConfiguration;
|
||||||
|
private ImportReadService _importReadService;
|
||||||
|
private LoanRepository _loanRepository;
|
||||||
|
private LoanTypeRepository _loanTypeRepository;
|
||||||
|
private DealerRepository _dealerRepository;
|
||||||
|
private DealerService _dealerService;
|
||||||
|
private Mock<IAuditHistoryRepository> _mockAuditHistRepo;
|
||||||
|
private Mock<IExportService> _mockExportService;
|
||||||
|
private LoanService _loanService;
|
||||||
|
private ImportRepository _importRepository;
|
||||||
|
private ImportService _importService;
|
||||||
|
private AppDbContext _appDbContext;
|
||||||
|
private Import _importResult;
|
||||||
|
private Exception _exception;
|
||||||
|
private string _importFileName;
|
||||||
|
private StreamReader _importStreamReader;
|
||||||
|
private List<Loan> _loansResult;
|
||||||
|
private List<Dealer> _dealersResult;
|
||||||
|
private List<IndirectLoanDetail> _loanDetailsFromDNA;
|
||||||
|
private List<ClosedIndirectLoan> _closedLoansFromDNA;
|
||||||
|
private Mock<CoreApiConfiguration> _mockCoreApiConfiguration;
|
||||||
|
private Mock<IGetRequest> _mockgetRequest;
|
||||||
|
private Mock<IPostRequest> _mockpostRequest;
|
||||||
|
private Mock<IPutRequest> _mockputRequest;
|
||||||
|
|
||||||
|
public ImportReadServiceSteps(ScenarioContext scenarioContext)
|
||||||
|
{
|
||||||
|
_scenarioContext = scenarioContext;
|
||||||
|
Service.Instance.ValueRetrievers.Register(new NullValueRetriever("<null>"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[BeforeScenario]
|
||||||
|
public void CreateDatabase()
|
||||||
|
{
|
||||||
|
var options = new DbContextOptionsBuilder<AppDbContext>()
|
||||||
|
.UseInMemoryDatabase(Guid.NewGuid().ToString())
|
||||||
|
.Options;
|
||||||
|
_apiSecurityConfiguration = new ApiSecurityConfiguration(ApiKeyAuthenticationFailureBehavior.Warn);
|
||||||
|
_mockCoreApiConfiguration = new Mock<CoreApiConfiguration>();
|
||||||
|
_mockCoreApiConfiguration.Object.ApiTimeOutInSeconds = "420";
|
||||||
|
_mockpostRequest = new Mock<IPostRequest>();
|
||||||
|
_mockputRequest = new Mock<IPutRequest>();
|
||||||
|
_mockgetRequest = new Mock<IGetRequest>();
|
||||||
|
_appDbContext = new AppDbContext(options);
|
||||||
|
_loanRepository = new LoanRepository(_appDbContext);
|
||||||
|
_loanTypeRepository = new LoanTypeRepository(_appDbContext);
|
||||||
|
_dealerRepository = new DealerRepository(_appDbContext);
|
||||||
|
_importRepository = new ImportRepository(_appDbContext);
|
||||||
|
_mockAuditHistRepo = new Mock<IAuditHistoryRepository>();
|
||||||
|
_mockExportService = new Mock<IExportService>();
|
||||||
|
_dealerService = new DealerService(_dealerRepository);
|
||||||
|
_loanService = new LoanService(_loanRepository, _loanTypeRepository, new AuditHistoryService(_mockAuditHistRepo.Object),
|
||||||
|
new Mock<ICoreApiServiceClient>().Object);
|
||||||
|
_importService = new ImportService(_importRepository);
|
||||||
|
_importReadService = new ImportReadService(
|
||||||
|
_loanService, _importService,
|
||||||
|
_dealerService,
|
||||||
|
_mockExportService.Object,
|
||||||
|
new CoreApiServiceClient(_apiSecurityConfiguration, _mockCoreApiConfiguration.Object, _mockgetRequest.Object, _mockpostRequest.Object, _mockputRequest.Object),
|
||||||
|
new Mock<RmsApiConfiguration>().Object
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[AfterScenario]
|
||||||
|
public void DisposeAppDbContext()
|
||||||
|
{
|
||||||
|
_appDbContext.Database.EnsureDeleted();
|
||||||
|
_appDbContext.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Given(@"an import file named ""(.*)"" that contains")]
|
||||||
|
public void GivenAnImportFileNamedThatContains(string fileName, string fileContent)
|
||||||
|
{
|
||||||
|
_importFileName = fileName;
|
||||||
|
var byteArray = Encoding.UTF8.GetBytes(fileContent);
|
||||||
|
var stream = new MemoryStream(byteArray);
|
||||||
|
_importStreamReader = new StreamReader(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Given(@"that I get these closed loans back from DNA")]
|
||||||
|
public void GivenThatIGetTheseClosedLoansBackFromDNA(Table table)
|
||||||
|
{
|
||||||
|
_closedLoansFromDNA = table.CreateSet<ClosedIndirectLoan>().ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Given(@"an import from DNA that contains")]
|
||||||
|
public void GivenAnImportFromDNAThatContains(Table table)
|
||||||
|
{
|
||||||
|
_loanDetailsFromDNA = table.CreateSet<IndirectLoanDetail>().ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Given(@"a loan table consisting of")]
|
||||||
|
public void GivenALoanTableConsistingOf(Table table)
|
||||||
|
{
|
||||||
|
var loans = table.CreateSet<Loan>().ToList();
|
||||||
|
_appDbContext.Loans.AddRange(loans);
|
||||||
|
_appDbContext.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Given(@"a loan type table consisting of")]
|
||||||
|
public void GivenALoanTypeTableConsistingOf(Table table)
|
||||||
|
{
|
||||||
|
var types = table.CreateSet<LoanType>().ToList();
|
||||||
|
_appDbContext.LoanTypes.AddRange(types);
|
||||||
|
_appDbContext.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Given(@"dealers that look like")]
|
||||||
|
public void GivenDealersThatLookLike(Table table)
|
||||||
|
{
|
||||||
|
var dealers = table.CreateSet<Dealer>().ToList();
|
||||||
|
_appDbContext.Dealers.AddRange(dealers);
|
||||||
|
_appDbContext.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Given(@"the current vehicle for loanId (.*) is")]
|
||||||
|
public void GivenTheCurrentVehicleForLoanIdIs(int loanId, Table table)
|
||||||
|
{
|
||||||
|
var vehicle = table.CreateInstance<Vehicle>();
|
||||||
|
vehicle.LoanId = loanId;
|
||||||
|
_appDbContext.Vehicles.Add(vehicle);
|
||||||
|
_appDbContext.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
[When(@"I read this new loan import file at ""(.*)""")]
|
||||||
|
public async void WhenIReadThisNewLoanImportFileAt(DateTime currentTime)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_importResult = await _importReadService.ReadNewLoanImportFile(_importStreamReader, _importFileName, currentTime);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_exception = ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[When(@"I process this DNA new/updated loan import at ""(.*)""")]
|
||||||
|
public async void WhenIReadThisNewDNALoanImportFileAt(DateTime currentTime)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_importResult = await _importReadService.ProcessActiveLoanImport(_loanDetailsFromDNA, currentTime);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_exception = ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[When(@"I process this DNA new/updated loan import at ""(.*)"" and skip the export")]
|
||||||
|
public async void WhenIProcessThisDNANewUpdatedLoanImportAtAndSkipTheExport(DateTime currentTime)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_importResult = await _importReadService.ProcessActiveLoanImport(_loanDetailsFromDNA, currentTime, true);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_exception = ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[When(@"I process the closed loan import from DNA at ""(.*)""")]
|
||||||
|
public async void WhenIReadTheClosedLoanImportFromDNAAt(DateTime currentTime)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_importResult = await _importReadService.ProcessClosedLoanImport(_closedLoansFromDNA, currentTime, string.Empty);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_exception = ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[When(@"I process the closed loan import with missing loan ""(.*)"" with date from DNA at ""(.*)"" and select from ""(.*)""")]
|
||||||
|
public async void WhenIProcessTheClosedLoanImportWithMissingLoanWithDateFromDNAAt(string missingLoanNumber, DateTime currentTime, DateTime newerThan)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var stringDate = newerThan.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture);
|
||||||
|
_importResult = await _importReadService.ProcessClosedLoanImport(_closedLoansFromDNA.Where(l => l.LoanNumber != missingLoanNumber).ToList(),
|
||||||
|
currentTime, stringDate);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_exception = ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[When(@"I process the missing active loans with detail from DNA at ""(.*)"" and export")]
|
||||||
|
public async void WhenIProcessTheMissingActiveLoansWithDetailFromDNAAtAndExport(DateTime currentTime)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_importResult = await _importReadService.ProcessClosedLoansWithUpdates(_loanDetailsFromDNA, currentTime, false);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_exception = ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[When(@"I process the closed loan import with detail from DNA at ""(.*)""")]
|
||||||
|
public async void WhenIReadTheInitialClosedLoanImportFromDNAAt(DateTime currentTime)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_importResult = await _importReadService.ProcessClosedLoansWithUpdates(_loanDetailsFromDNA, currentTime, false);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_exception = ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[When(@"I process the closed loan import with detail from DNA at ""(.*)"" and skip the export")]
|
||||||
|
public async void WhenIReadTheInitialClosedLoanImportFromDNAAtAndSkipTheExport(DateTime currentTime)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_importResult = await _importReadService.ProcessClosedLoansWithUpdates(_loanDetailsFromDNA, currentTime, true);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_exception = ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[When(@"I read this closed loan import file at ""(.*)""")]
|
||||||
|
public async void WhenIReadThisClosedLoanImportFileAt(DateTime currentTime)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_importResult = await _importReadService.ReadClosedLoanImportFile(_importStreamReader, _importFileName, currentTime);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_exception = ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[When(@"I get the record from the ImportTable")]
|
||||||
|
public async void WhenIGetTheRecordFromTheImportTable()
|
||||||
|
{
|
||||||
|
_importResult = (await _importRepository.GetAll().ToListAsync()).First();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the import has start date ""(.*)""")]
|
||||||
|
public void ThenTheImportHasStartDate(DateTime startDate)
|
||||||
|
{
|
||||||
|
Assert.Equal(startDate, _importResult.StartDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the import has an end date that is greater or equal to the start date")]
|
||||||
|
public void ThenTheImportHasAnEndDateThatIsGreaterOrEqualToTheStartDate()
|
||||||
|
{
|
||||||
|
Assert.True(_importResult.EndDate >= _importResult.StartDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the import has record count (.*)")]
|
||||||
|
public void ThenTheImportHasRecordCount(int recordCount)
|
||||||
|
{
|
||||||
|
Assert.Equal(recordCount, _importResult.RecordCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the import has success ""(.*)""")]
|
||||||
|
public void ThenTheImportHasSuccess(bool success)
|
||||||
|
{
|
||||||
|
Assert.Equal(success, _importResult.Success);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the import has file name ""(.*)""")]
|
||||||
|
public void ThenTheImportHasFileName(string fileName)
|
||||||
|
{
|
||||||
|
Assert.Equal(fileName, _importResult.FileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"an exception is thrown")]
|
||||||
|
public void ThenAnExceptionIsThrown()
|
||||||
|
{
|
||||||
|
Assert.NotNull(_exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the import looks like")]
|
||||||
|
public void ThenTheImportLooksLike(Table table)
|
||||||
|
{
|
||||||
|
table.CompareToInstance(_importResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"there is a record added to the Audit History table")]
|
||||||
|
public void ThenThereIsARecordAddedToTheAuditHistoryTable()
|
||||||
|
{
|
||||||
|
_mockAuditHistRepo.Verify(x => x.AddHistoriesAsync(It.IsAny<List<AuditHistory>>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"no audit history record is added")]
|
||||||
|
public void ThenNoAuditHistoryRecordIsAdded()
|
||||||
|
{
|
||||||
|
_mockAuditHistRepo.Verify(x => x.AddHistoriesAsync(It.IsAny<List<AuditHistory>>()), Times.Never);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"AddHistoriesAsync is called with (.*) history/ies having OldValue ""(.*)"" and NewValue ""(.*)""")]
|
||||||
|
public void ThenAddHistoriesAsyncIsCalledWithHistoryIesHavingOldValueAndNewValue(int number, string oldValue, string newValue)
|
||||||
|
{
|
||||||
|
_mockAuditHistRepo.Verify(x =>
|
||||||
|
x.AddHistoriesAsync(It.Is<List<AuditHistory>>(a => a.Count(x => x.NewValue == newValue && x.OldValue == oldValue) == number)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"AddHistoriesAsync is called with (.*) history/ies having ActivityType ""(.*)"" and AuditDescription ""(.*)""")]
|
||||||
|
public void ThenAddHistoriesAsyncIsCalledWithHistoryHavingActivityTypeAndAuditDescription(int number, string type, string description)
|
||||||
|
{
|
||||||
|
_mockAuditHistRepo.Verify(x =>
|
||||||
|
x.AddHistoriesAsync(It.Is<List<AuditHistory>>(a => a.Count(x => x.ActivityType == type && x.AuditDescription == description) == number)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"AddHistoriesAsync is called with (.*) history/ies having LoanNumber ""(.*)"" and MemberNumber ""(.*)""")]
|
||||||
|
public void ThenAddHistoriesAsyncIsCalledWithHistoryHavingLoanNumberAndMemberNumber(int number, string loanNumber, string memberNumber)
|
||||||
|
{
|
||||||
|
_mockAuditHistRepo.Verify(x =>
|
||||||
|
x.AddHistoriesAsync(It.Is<List<AuditHistory>>(a => a.Count(x => x.MemberNumber == memberNumber && x.LoanNumber == loanNumber) == number)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"ExportChargebacksAsync is called")]
|
||||||
|
public void ThenExportChargebacksAsyncIsCalled()
|
||||||
|
{
|
||||||
|
_mockExportService.Verify(x => x.ExportChargebacksAsync(It.IsAny<DateTime>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"ExportChargebacksAsync is not called")]
|
||||||
|
public void ThenExportChargebacksAsyncIsNotCalled()
|
||||||
|
{
|
||||||
|
_mockExportService.Verify(x => x.ExportChargebacksAsync(It.IsAny<DateTime>()), Times.Never);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"MarkReservesAndChargebacksAsExportedAsync is called")]
|
||||||
|
public void ThenMarkReservesAndChargebacksAsExportedAsyncIsCalled()
|
||||||
|
{
|
||||||
|
_mockExportService.Verify(x => x.MarkReservesAndChargebacksAsExportedAsync(It.IsAny<List<Loan>>(), It.IsAny<DateTime>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"all loans have non-null ExportedChargebackDate")]
|
||||||
|
public void ThenAllLoansHaveNon_NullExportedChargebackDate()
|
||||||
|
{
|
||||||
|
Assert.DoesNotContain(_loansResult, l => l.ExportedChargebackDate == null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"ExportReservesAsync is called")]
|
||||||
|
public void ThenExportReservesAsyncIsCalled()
|
||||||
|
{
|
||||||
|
_mockExportService.Verify(x => x.ExportReservesAsync(It.IsAny<DateTime>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"ExportReservesAsync is not called")]
|
||||||
|
public void ThenExportReservesAsyncIsNotCalled()
|
||||||
|
{
|
||||||
|
_mockExportService.Verify(x => x.ExportReservesAsync(It.IsAny<DateTime>()), Times.Never);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"MarkReservesAsExportedAsync is called")]
|
||||||
|
public void ThenMarkReservesAsExportedAsyncIsCalled()
|
||||||
|
{
|
||||||
|
_mockExportService.Verify(x => x.MarkReservesAsExportedAsync(It.IsAny<List<Loan>>(), It.IsAny<DateTime>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"all loans have non-null ExportedReserveDate")]
|
||||||
|
public void ThenAllLoansHaveNon_NullExportedReserveDate()
|
||||||
|
{
|
||||||
|
Assert.DoesNotContain(_loansResult, l => l.ExportedReserveDate == null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the loans now look like")]
|
||||||
|
public async void ThenTheLoansNowLookLike(Table table)
|
||||||
|
{
|
||||||
|
_loansResult = await _loanRepository.GetAll().AsNoTracking().ToListAsync();
|
||||||
|
table.CompareToSet(_loansResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the dealers now look like")]
|
||||||
|
public async void ThenTheDealersNowLookLike(Table table)
|
||||||
|
{
|
||||||
|
_dealersResult = await _dealerRepository.GetAll().ToListAsync();
|
||||||
|
table.CompareToSet(_dealersResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the vehicle for LoanId (.*) looks like this")]
|
||||||
|
public void ThenTheVehicleForLoanIdLooksLikeThis(int loanId, Table table)
|
||||||
|
{
|
||||||
|
var result = _loansResult.FirstOrDefault(v => v.LoanId == loanId)?.Vehicle;
|
||||||
|
table.CompareToInstance<Vehicle>(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the vehicle for LoanId (.*) is null")]
|
||||||
|
public void ThenTheVehicleForLoanIdIsNull(int loanId)
|
||||||
|
{
|
||||||
|
Assert.Null(_loansResult.FirstOrDefault(v => v.LoanId == loanId).Vehicle);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the loans with details now look like")]
|
||||||
|
public void ThenTheLoansWithDetailsNowLookLike(Table table)
|
||||||
|
{
|
||||||
|
var loans = table.CreateInstance<Loan>();
|
||||||
|
_loansResult.Add(loans);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+92
@@ -0,0 +1,92 @@
|
|||||||
|
Feature: ImportService
|
||||||
|
Gets Imports from database
|
||||||
|
|
||||||
|
Scenario: GetAllAsync Success
|
||||||
|
Given the Import table has the following imports
|
||||||
|
| ImportId | Start Date | End Date | RecordCount | Success | FileName |
|
||||||
|
| 1 | 1/2/2021 5:00:00 AM | 1/2/2021 5:10:00 AM | 25 | true | New Loans 1-2-2021.txt |
|
||||||
|
| 2 | 1/3/2021 5:00:00 AM | 1/3/2021 5:15:00 AM | 50 | false | New Loans 1-3-2021.txt |
|
||||||
|
| 3 | 1/4/2021 5:00:00 AM | 1/4/2021 5:05:00 AM | 75 | true | New Loans 1-4-2021.txt |
|
||||||
|
When I get the list of all imports with the import service
|
||||||
|
Then the result from the import service should have 3 imports
|
||||||
|
And the first import from the import service has ImportId 3
|
||||||
|
|
||||||
|
Scenario: GetAllAsync Exception
|
||||||
|
Given the Import Repository throws an exception in ListAll
|
||||||
|
When I get the list of all imports with the import service
|
||||||
|
Then the Import Service throws an exception with the message "Exception of type 'System.Exception' was thrown."
|
||||||
|
|
||||||
|
Scenario: GetRecentAsync Success
|
||||||
|
Given the Import table has the following imports
|
||||||
|
| ImportId | Start Date | End Date | RecordCount | Success | FileName | ImportType |
|
||||||
|
| 1 | 1/2/2021 5:00:00 AM | 1/2/2021 5:10:00 AM | 25 | true | New Loans 1-2-2021.txt | Active |
|
||||||
|
| 2 | 1/3/2021 5:00:00 AM | 1/3/2021 5:15:00 AM | 50 | false | New Loans 1-3-2021.txt | Active |
|
||||||
|
| 3 | 1/4/2021 5:00:00 AM | 1/4/2021 5:05:00 AM | 75 | true | New Loans 1-4-2021.txt | Active |
|
||||||
|
When I get the list of the top 2 imports with the import service
|
||||||
|
Then the result from the import service should have 2 imports
|
||||||
|
And the first import from the import service has ImportId 3
|
||||||
|
|
||||||
|
Scenario: GetRecentAsync Success - more imports asked for then are in the table
|
||||||
|
Given the Import table has the following imports
|
||||||
|
| ImportId | Start Date | End Date | RecordCount | Success | FileName |ImportType |
|
||||||
|
| 1 | 1/2/2021 5:00:00 AM | 1/2/2021 5:10:00 AM | 25 | true | New Loans 1-2-2021.txt |Active |
|
||||||
|
| 2 | 1/3/2021 5:00:00 AM | 1/3/2021 5:15:00 AM | 50 | false | New Loans 1-3-2021.txt |Active |
|
||||||
|
| 3 | 1/4/2021 5:00:00 AM | 1/4/2021 5:05:00 AM | 75 | true | New Loans 1-4-2021.txt |Active |
|
||||||
|
When I get the list of the top 5 imports with the import service
|
||||||
|
Then the result from the import service should have 3 imports
|
||||||
|
And the first import from the import service has ImportId 3
|
||||||
|
|
||||||
|
Scenario: GetRecentAsync Exception
|
||||||
|
Given the Import Repository throws an exception in ListAll
|
||||||
|
When I get the list of the top 5 imports with the import service
|
||||||
|
Then the Import Service throws an exception with the message "Exception of type 'System.Exception' was thrown."
|
||||||
|
|
||||||
|
Scenario: GetByIdAsync Success
|
||||||
|
Given the Import table has the following imports
|
||||||
|
| ImportId | Start Date | End Date | RecordCount | Success | FileName |ImportType |
|
||||||
|
| 1 | 1/2/2021 5:00:00 AM | 1/2/2021 5:10:00 AM | 25 | true | New Loans 1-2-2021.txt |Active |
|
||||||
|
| 2 | 1/3/2021 5:00:00 AM | 1/3/2021 5:15:00 AM | 50 | false | New Loans 1-3-2021.txt |Active |
|
||||||
|
| 3 | 1/4/2021 5:00:00 AM | 1/4/2021 5:05:00 AM | 75 | true | New Loans 1-4-2021.txt |Active |
|
||||||
|
When I get the import with the importId 2 from the import service
|
||||||
|
Then the import from the import service has ImportId 2
|
||||||
|
|
||||||
|
Scenario: GetByIdAsync Exception - Not Found
|
||||||
|
Given the Import table has the following imports
|
||||||
|
| ImportId | Start Date | End Date | RecordCount | Success | FileName |ImportType |
|
||||||
|
| 1 | 1/2/2021 5:00:00 AM | 1/2/2021 5:10:00 AM | 25 | true | New Loans 1-2-2021.txt |Active |
|
||||||
|
| 2 | 1/3/2021 5:00:00 AM | 1/3/2021 5:15:00 AM | 50 | false | New Loans 1-3-2021.txt |Active |
|
||||||
|
| 3 | 1/4/2021 5:00:00 AM | 1/4/2021 5:05:00 AM | 75 | true | New Loans 1-4-2021.txt |Active |
|
||||||
|
When I get the import with the importId 4 from the import service
|
||||||
|
Then the Import Service throws an exception with the message "Import with id 4 not found."
|
||||||
|
|
||||||
|
Scenario: GetByIdAsync Exception - Import Repository exception
|
||||||
|
Given the Import Repository throws an exception in FindByIdAsync
|
||||||
|
When I get the import with the importId 3 from the import service
|
||||||
|
Then the Import Service throws an exception with the message "Exception of type 'System.Exception' was thrown."
|
||||||
|
|
||||||
|
Scenario: GetLastLoanImport - active when there are only active
|
||||||
|
Given the Import table has the following imports
|
||||||
|
| ImportId | Start Date | End Date | RecordCount | Success | FileName | ImportType |
|
||||||
|
| 1 | 1/2/2021 5:00:00 AM | 1/2/2021 5:10:00 AM | 25 | true | <null> | Active |
|
||||||
|
| 2 | 1/3/2021 5:00:00 AM | 1/3/2021 5:15:00 AM | 50 | false | <null> | Active |
|
||||||
|
| 3 | 1/4/2021 5:00:00 AM | 1/4/2021 5:05:00 AM | 75 | true | <null> | Active |
|
||||||
|
When I get the last loan import of type "Active"
|
||||||
|
Then the import from the import service has ImportId 3
|
||||||
|
|
||||||
|
Scenario: GetLastLoanImport - ignore imports that have a non-null filename
|
||||||
|
Given the Import table has the following imports
|
||||||
|
| ImportId | Start Date | End Date | RecordCount | Success | FileName | ImportType |
|
||||||
|
| 1 | 1/2/2021 5:00:00 AM | 1/2/2021 5:10:00 AM | 25 | true | <null> | Active |
|
||||||
|
| 2 | 1/3/2021 5:00:00 AM | 1/3/2021 5:15:00 AM | 50 | false | <null> | Active |
|
||||||
|
| 3 | 1/4/2021 5:00:00 AM | 1/4/2021 5:05:00 AM | 75 | true | New Loans 1-4-2021.txt | Active |
|
||||||
|
When I get the last loan import of type "Active"
|
||||||
|
Then the import from the import service has ImportId 1
|
||||||
|
|
||||||
|
Scenario: GetLastLoanImport - closed when there are both types
|
||||||
|
Given the Import table has the following imports
|
||||||
|
| ImportId | Start Date | End Date | RecordCount | Success | FileName | ImportType |
|
||||||
|
| 1 | 1/2/2021 5:00:00 AM | 1/2/2021 5:10:00 AM | 25 | true | <null> | Closed |
|
||||||
|
| 2 | 1/3/2021 5:00:00 AM | 1/3/2021 5:15:00 AM | 50 | false | <null> | Active |
|
||||||
|
| 3 | 1/4/2021 5:00:00 AM | 1/4/2021 5:05:00 AM | 75 | true | <null> | Active |
|
||||||
|
When I get the last loan import of type "Closed"
|
||||||
|
Then the import from the import service has ImportId 1
|
||||||
+149
@@ -0,0 +1,149 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Moq;
|
||||||
|
using ReserveManagementSystemApi.Services;
|
||||||
|
using ReserveManagementSystemLib.Models;
|
||||||
|
using ReserveManagementSystemLib.Persistence;
|
||||||
|
using ReserveManagementSystemLib.Repositories;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using TechTalk.SpecFlow;
|
||||||
|
using TechTalk.SpecFlow.Assist;
|
||||||
|
using TechTalk.SpecFlow.Assist.ValueRetrievers;
|
||||||
|
using Xunit;
|
||||||
|
using ReserveManagementSystemLib.Enums;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi.Tests.ServiceTests
|
||||||
|
{
|
||||||
|
[Binding]
|
||||||
|
public sealed class ImportServiceSteps
|
||||||
|
{
|
||||||
|
// For additional details on SpecFlow step definitions see https://go.specflow.org/doc-stepdef
|
||||||
|
|
||||||
|
private readonly ScenarioContext _scenarioContext;
|
||||||
|
private ImportService _importService;
|
||||||
|
private AppDbContext _appDbContext;
|
||||||
|
private IEnumerable<Import> _importsResult;
|
||||||
|
private Import _importResult;
|
||||||
|
private Exception _exception;
|
||||||
|
|
||||||
|
public ImportServiceSteps(ScenarioContext scenarioContext)
|
||||||
|
{
|
||||||
|
_scenarioContext = scenarioContext;
|
||||||
|
Service.Instance.ValueRetrievers.Register(new NullValueRetriever("<null>"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[BeforeScenario]
|
||||||
|
public void CreateDatabase()
|
||||||
|
{
|
||||||
|
var options = new DbContextOptionsBuilder<AppDbContext>()
|
||||||
|
.UseInMemoryDatabase(Guid.NewGuid().ToString())
|
||||||
|
.Options;
|
||||||
|
_appDbContext = new AppDbContext(options);
|
||||||
|
_importService = new ImportService(new ImportRepository(_appDbContext));
|
||||||
|
}
|
||||||
|
|
||||||
|
[AfterScenario]
|
||||||
|
public void DisposeAppDbContext()
|
||||||
|
{
|
||||||
|
_appDbContext.Database.EnsureDeleted();
|
||||||
|
_appDbContext.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Given(@"the Import table has the following imports")]
|
||||||
|
public void GivenTheImportTableHasTheFollowingImports(Table table)
|
||||||
|
{
|
||||||
|
var imports = table.CreateSet<Import>();
|
||||||
|
|
||||||
|
_appDbContext.Imports.AddRange(imports);
|
||||||
|
_appDbContext.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Given(@"the Import Repository throws an exception in ListAll")]
|
||||||
|
public void GivenTheImportRepositoryThrowsAnExceptionInListAll()
|
||||||
|
{
|
||||||
|
var mockImportRepo = new Mock<IImportRepository>();
|
||||||
|
mockImportRepo.Setup(a => a.GetAll()).Throws(new Exception());
|
||||||
|
_importService = new ImportService(mockImportRepo.Object);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Given(@"the Import Repository throws an exception in FindByIdAsync")]
|
||||||
|
public void GivenTheImportRepositoryThrowsAnExceptionInFindByIdAsync()
|
||||||
|
{
|
||||||
|
var mockImportRepo = new Mock<IImportRepository>();
|
||||||
|
mockImportRepo.Setup(a => a.FindByIdAsync(It.IsAny<int>())).Throws(new Exception());
|
||||||
|
_importService = new ImportService(mockImportRepo.Object);
|
||||||
|
}
|
||||||
|
|
||||||
|
[When(@"I get the list of all imports with the import service")]
|
||||||
|
public async void WhenIGetTheListOfAllImportsWithTheImportService()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_importsResult = await _importService.GetAllAsync();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_exception = ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[When(@"I get the list of the top (.*) imports with the import service")]
|
||||||
|
public async void WhenIGetTheListOfAllImportsWithTheImportService(int numberOfImports)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_importsResult = await _importService.GetRecentAsync(numberOfImports);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_exception = ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[When(@"I get the import with the importId (.*) from the import service")]
|
||||||
|
public async void WhenIGetTheImportWithTheImportIdFromTheImportService(int importId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_importResult = await _importService.GetByIdAsync(importId);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_exception = ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[When(@"I get the last loan import of type ""(.*)""")]
|
||||||
|
public async void WhenIGetTheLastLoanImportOfType(string importType)
|
||||||
|
{
|
||||||
|
var type = (ImportType)Enum.Parse(typeof(ImportType), importType, true);
|
||||||
|
_importResult = await _importService.GetLastLoanImportByType(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the result from the import service should have (.*) imports")]
|
||||||
|
public void ThenTheResultFromTheImportServiceShouldHaveImports(int importCount)
|
||||||
|
{
|
||||||
|
Assert.Equal(importCount, _importsResult.Count());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the first import from the import service has ImportId (.*)")]
|
||||||
|
public void ThenTheFirstImportFromTheImportServiceHasImportId(int importId)
|
||||||
|
{
|
||||||
|
Assert.Equal(importId, _importsResult.First().ImportId);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the Import Service throws an exception with the message ""(.*)""")]
|
||||||
|
public void ThenTheImportServiceThrowsAnExceptionWithTheMessage(string message)
|
||||||
|
{
|
||||||
|
Assert.NotNull(_exception);
|
||||||
|
Assert.Equal(message, _exception.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the import from the import service has ImportId (.*)")]
|
||||||
|
public void ThenTheImportFromTheImportServiceHasImportId(int importId)
|
||||||
|
{
|
||||||
|
Assert.Equal(importId, _importResult.ImportId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+104
@@ -0,0 +1,104 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Moq;
|
||||||
|
using ReserveManagementSystemApi.Services;
|
||||||
|
using ReserveManagementSystemLib.Models;
|
||||||
|
using ReserveManagementSystemLib.Persistence;
|
||||||
|
using ReserveManagementSystemLib.Repositories;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using TechTalk.SpecFlow;
|
||||||
|
using TechTalk.SpecFlow.Assist;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi.Tests
|
||||||
|
{
|
||||||
|
[Binding]
|
||||||
|
public sealed class LoanCalculationServiceSteps
|
||||||
|
{
|
||||||
|
// For additional details on SpecFlow step definitions see https://go.specflow.org/doc-stepdef
|
||||||
|
|
||||||
|
private readonly ScenarioContext _scenarioContext;
|
||||||
|
private Loan _loan;
|
||||||
|
private LoanReserve _reserve;
|
||||||
|
private LoanChargeback _chargeback;
|
||||||
|
private List<LoanType> _loanTypes;
|
||||||
|
private AppDbContext _appDbContext;
|
||||||
|
|
||||||
|
public LoanCalculationServiceSteps(ScenarioContext scenarioContext)
|
||||||
|
{
|
||||||
|
_scenarioContext = scenarioContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BeforeScenario]
|
||||||
|
public void CreateDatabase()
|
||||||
|
{
|
||||||
|
var options = new DbContextOptionsBuilder<AppDbContext>()
|
||||||
|
.UseInMemoryDatabase(Guid.NewGuid().ToString())
|
||||||
|
.Options;
|
||||||
|
_appDbContext = new AppDbContext(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
[AfterScenario]
|
||||||
|
public void DisposeAppDbContext()
|
||||||
|
{
|
||||||
|
_appDbContext.Database.EnsureDeleted();
|
||||||
|
_appDbContext.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Given(@"a loan that looks like")]
|
||||||
|
public void GivenALoanThatLooksLike(Table table)
|
||||||
|
{
|
||||||
|
_loan = table.CreateInstance<Loan>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Given(@"a loan type table that looks like")]
|
||||||
|
public void GivenALoanTypeTableThatLooksLike(Table table)
|
||||||
|
{
|
||||||
|
_loanTypes = table.CreateSet<LoanType>().ToList();
|
||||||
|
_appDbContext.LoanTypes.AddRange(_loanTypes);
|
||||||
|
_appDbContext.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
[When(@"the reserve is calculated")]
|
||||||
|
public async void WhenTheReserveIsCalculated()
|
||||||
|
{
|
||||||
|
_loan.LoanType = await new LoanTypeRepository(_appDbContext).GetLoanTypeAsync(_loan.LoanTypeId);
|
||||||
|
var loanCalculationService = new LoanCalculationService();
|
||||||
|
_reserve = loanCalculationService.CalculateSingleReserve(_loan);
|
||||||
|
}
|
||||||
|
|
||||||
|
[When(@"the chargeback is calculated")]
|
||||||
|
public async void WhenTheChargebackIsCalculated()
|
||||||
|
{
|
||||||
|
_loan.LoanType = await new LoanTypeRepository(_appDbContext).GetLoanTypeAsync(_loan.LoanTypeId);
|
||||||
|
var loanCalculationService = new LoanCalculationService();
|
||||||
|
_chargeback = loanCalculationService.CalculateSingleChargeback(_loan);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"FlatFeePaid should be ""(.*)""")]
|
||||||
|
public void ThenFlatFeePaidShouldBe(bool flatFeePaid)
|
||||||
|
{
|
||||||
|
Assert.Equal(flatFeePaid, _reserve.FlatFeePaid);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the reserve amount should be (.*)")]
|
||||||
|
public void ThenTheReserveAmountShouldBe(decimal reserve)
|
||||||
|
{
|
||||||
|
Assert.Equal(reserve, _reserve.ReserveAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the reserve message should be (.*)")]
|
||||||
|
public void ThenTheReserveMessageShouldBe(string message)
|
||||||
|
{
|
||||||
|
Assert.Equal(message, _reserve.ReserveTypeMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the chargeback returned is")]
|
||||||
|
public void ThenTheChargebackReturnedIs(Table table)
|
||||||
|
{
|
||||||
|
table.CompareToInstance<LoanChargeback>(_chargeback);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
+475
@@ -0,0 +1,475 @@
|
|||||||
|
Feature: Loan Service - Filtering, Pagination
|
||||||
|
Get filtered list of loans, get paginated list of loans
|
||||||
|
|
||||||
|
Scenario: GetFilteredAsync Success - ImportId - sorting will be by Dealer Code ASC importid descending and then by member number ascending
|
||||||
|
Given the Loan table has the following loans
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number | Application Id | Member Last Name | Member First Name | Member Initial | Dealer Code | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type Id | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | Action Required |
|
||||||
|
| 1 | 1 | 12 | 3 | 345 | Smith | Joe | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 0 |
|
||||||
|
| 2 | 2 | 45 | 2 | 678 | Jones | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 3 | 2 | 22 | 6 | 901 | Johnson | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 1 |
|
||||||
|
And a loan filter that looks like
|
||||||
|
| MemberNumberText | MemberNameText | ImportId | DealerCodeText | ActionRequired | LoanNumberText | ApplicationIdText | LoanDateStart | LoanDateEnd | SortField | SortDirection | MaxRecordsPerPage | MaxPagesPerRange |
|
||||||
|
| | | 2 | | | | | | | DealerCode | ASC | 15 | 7 |
|
||||||
|
When I get the list of the filtered loans with the loan service
|
||||||
|
Then the loan ids from the loan service look like "3,2"
|
||||||
|
|
||||||
|
Scenario: GetFilteredAsync Success - MemberNumber - sorting will be by Action Required DESC importid descending and then by member number ascending
|
||||||
|
Given the Loan table has the following loans
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number | Application Id | Member Last Name | Member First Name | Member Initial | Dealer Code | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type Id | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | Action Required |
|
||||||
|
| 1 | 1 | 12 | 3 | 345 | Smith | Joe | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 0 |
|
||||||
|
| 2 | 2 | 45 | 6 | 678 | Jones | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 1 |
|
||||||
|
| 3 | 2 | 12 | 4 | 901 | Smith | Joe | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 1 |
|
||||||
|
And a loan filter that looks like
|
||||||
|
| MemberNumberText | MemberNameText | LoanNumberText | ApplicationIdText | LoanDateStart | LoanDateEnd | ImportId | DealerCodeText | ActionRequired | SortField | SortDirection | MaxRecordsPerPage | MaxPagesPerRange |
|
||||||
|
| 12 | | | | | | | | | ActionRequired | DESC | 15 | 7 |
|
||||||
|
When I get the list of the filtered loans with the loan service
|
||||||
|
Then the loan ids from the loan service look like "3,1"
|
||||||
|
|
||||||
|
Scenario: GetFilteredAsync Success - MemberName, searches both first and last name - sorting will be by MemberLastName DESC importid descending and then by member number ascending
|
||||||
|
Given the Loan table has the following loans
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number | Application Id | Member Last Name | Member First Name | Member Initial | Dealer Code | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type Id | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | Action Required |
|
||||||
|
| 1 | 1 | 12 | 3 | 345 | SMITH | JOE | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 0 |
|
||||||
|
| 2 | 2 | 45 | 6 | 678 | JONES | LAURA | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 1 |
|
||||||
|
| 3 | 2 | 12 | 4 | 901 | SMITH | JOE | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 1 |
|
||||||
|
And a loan filter that looks like
|
||||||
|
| MemberNumberText | MemberNameText | LoanNumberText | ApplicationIdText | LoanDateStart | LoanDateEnd | ImportId | DealerCodeText | ActionRequired | SortField | SortDirection | MaxRecordsPerPage | MaxPagesPerRange |
|
||||||
|
| | Jo | | | | | | | | MemberLastName | ASC | 15 | 7 |
|
||||||
|
When I get the list of the filtered loans with the loan service
|
||||||
|
Then the loan ids from the loan service look like "2,3,1"
|
||||||
|
|
||||||
|
Scenario: GetFilteredAsync Success - MemberName, returns one - sorting will be by MemberLastName DESC importid descending and then by member number ascending
|
||||||
|
Given the Loan table has the following loans
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number |Application Id | Member Last Name | Member First Name | Member Initial | Dealer Code | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type Id | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | Action Required |
|
||||||
|
| 1 | 1 | 12 | 3 |345 | SMITH | JOE | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 0 |
|
||||||
|
| 2 | 2 | 45 | 6 |678 | JONES | LAURA | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 1 |
|
||||||
|
| 3 | 2 | 12 | 4 |901 | SMITH | JOE | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 1 |
|
||||||
|
And a loan filter that looks like
|
||||||
|
| MemberNumberText | MemberNameText | LoanNumberText | ApplicationIdText | LoanDateStart | LoanDateEnd | ImportId | DealerCodeText | ActionRequired | SortField | SortDirection | MaxRecordsPerPage | MaxPagesPerRange |
|
||||||
|
| | Jon | | | | | | | | MemberLastName | ASC | 15 | 7 |
|
||||||
|
When I get the list of the filtered loans with the loan service
|
||||||
|
Then the loan ids from the loan service look like "2"
|
||||||
|
|
||||||
|
Scenario: GetFilteredAsync Success - LoanNumber - sorting will be by Action Required DESC importid descending and then by member number ascending
|
||||||
|
Given the Loan table has the following loans
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number |Application Id | Member Last Name | Member First Name | Member Initial | Dealer Code | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type Id | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | Action Required |
|
||||||
|
| 1 | 1 | 12 | 3 |345 | Smith | Joe | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 0 |
|
||||||
|
| 2 | 2 | 45 | 6 |678 | Jones | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 1 |
|
||||||
|
| 3 | 2 | 56 | 3 |901 | Johnson | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 1 |
|
||||||
|
And a loan filter that looks like
|
||||||
|
| MemberNumberText | MemberNameText | LoanNumberText | ApplicationIdText | LoanDateStart | LoanDateEnd | ImportId | DealerCodeText | ActionRequired | SortField | SortDirection | MaxRecordsPerPage | MaxPagesPerRange |
|
||||||
|
| | | 3 | | | | | | | ActionRequired | DESC | 15 | 7 |
|
||||||
|
When I get the list of the filtered loans with the loan service
|
||||||
|
Then the loan ids from the loan service look like "3,1"
|
||||||
|
|
||||||
|
Scenario: GetFilteredAsync Success - Application Id - sorting will be by Action Required DESC importid descending and then by member number ascending
|
||||||
|
Given the Loan table has the following loans
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number |Application Id | Member Last Name | Member First Name | Member Initial | Dealer Code | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type Id | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | Action Required |
|
||||||
|
| 1 | 1 | 12 | 3 |345 | Smith | Joe | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 0 |
|
||||||
|
| 2 | 2 | 45 | 6 |378 | Jones | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 1 |
|
||||||
|
| 3 | 2 | 56 | 3 |901 | Johnson | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 1 |
|
||||||
|
And a loan filter that looks like
|
||||||
|
| MemberNumberText | MemberNameText | LoanNumberText | ApplicationIdText | LoanDateStart | LoanDateEnd | ImportId | DealerCodeText | ActionRequired | SortField | SortDirection | MaxRecordsPerPage | MaxPagesPerRange |
|
||||||
|
| | | | 3 | | | | | | ActionRequired | DESC | 15 | 7 |
|
||||||
|
When I get the list of the filtered loans with the loan service
|
||||||
|
Then the loan ids from the loan service look like "2,1"
|
||||||
|
|
||||||
|
Scenario: GetFilteredAsync Success - DealerCode - sorting will be by Action Required ASC then importid descending and then by member number ascending
|
||||||
|
Given the Loan table has the following loans
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number | Application Id | Member Last Name | Member First Name | Member Initial | DealerOrganizationNumber | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type Id | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | Action Required |
|
||||||
|
| 1 | 1 | 12 | 3 | 345 | Smith | Joe | | 1234 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 0 |
|
||||||
|
| 2 | 2 | 45 | 6 | 678 | Jones | Laura | M | 1111 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 3 | 2 | 22 | 2 | 901 | Johnson | Laura | M | 1111 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 1 |
|
||||||
|
And the dealer table has these dealers
|
||||||
|
| Dealer Code | Name | DealerOrganizationNumber |
|
||||||
|
| H21 | HEISER CHEVROLET CADILLAC OF WEST BEND | 1111 |
|
||||||
|
| A1 | ACURA OF BROOKFIELD | 5678 |
|
||||||
|
| S7 | SUBURBAN MOTORS HARLEY DAVIDSON | 1234 |
|
||||||
|
And a loan filter that looks like
|
||||||
|
| MemberNumberText | MemberNameText | LoanNumberText | ApplicationIdText | LoanDateStart | LoanDateEnd | ImportId | DealerCodeText | ActionRequired | SortField | SortDirection | MaxRecordsPerPage | MaxPagesPerRange |
|
||||||
|
| | | | | | | | H21 | | ActionRequired | ASC | 15 | 7 |
|
||||||
|
When I get the list of the filtered loans with the loan service
|
||||||
|
Then the loan ids from the loan service look like "2,3"
|
||||||
|
|
||||||
|
Scenario: GetFilteredAsync Success - ActionRequired - sorting will be by Dealer Code ASC then importid descending and then by member number ascending
|
||||||
|
Given the Loan table has the following loans
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number |Application Id | Member Last Name | Member First Name | Member Initial | Dealer Code | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate |Loan Type Id | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | Action Required |
|
||||||
|
| 1 | 1 | 12 | 3 |345 | SMITH | JOE | | H21 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 |NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 2 | 2 | 45 | 6 |678 | JONES | LAURA | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 |BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 3 | 2 | 22 | 2 |901 | JOHNSON | LAURA | M | S7 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 |BB | 60 | 1450.2923 | 500 | false | | | Message | 1 |
|
||||||
|
And a loan filter that looks like
|
||||||
|
| MemberNumberText | MemberNameText | LoanNumberText | ApplicationIdText | LoanDateStart | LoanDateEnd | ImportId | DealerCodeText | ActionRequired | SortField | SortDirection | MaxRecordsPerPage | MaxPagesPerRange |
|
||||||
|
| | | | | | | | | 1 | DealerCode | ASC | 15 | 7 |
|
||||||
|
When I get the list of the filtered loans with the loan service
|
||||||
|
Then the loan ids from the loan service look like "1,3"
|
||||||
|
|
||||||
|
Scenario: GetFilteredAsync Success - Loan Date - start and end - sorting will be by Dealer Code ASC then importid descending and then by member number ascending
|
||||||
|
Given the Loan table has the following loans
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number | Application Id |Member Last Name | Member First Name | Member Initial | Dealer Code | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type Id | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | Action Required |
|
||||||
|
| 1 | 1 | 12 | 3 | 345 |SMITH | JOE | | H21 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 2 | 2 | 45 | 6 | 678 |JONES | LAURA | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 3 | 2 | 22 | 2 | 901 |JOHNSON | LAURA | M | S7 | 2/23/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 1 |
|
||||||
|
And a loan filter that looks like
|
||||||
|
| MemberNumberText | LoanNumberText | ApplicationIdText | LoanDateStart | LoanDateEnd | ImportId | DealerCodeText | ActionRequired | SortField | SortDirection | MaxRecordsPerPage | MaxPagesPerRange |
|
||||||
|
| | | |2/23/2021 | 2/24/2021 | | | | DealerCode | ASC | 15 | 7 |
|
||||||
|
When I get the list of the filtered loans with the loan service
|
||||||
|
Then the loan ids from the loan service look like "2,3"
|
||||||
|
|
||||||
|
Scenario: GetFilteredAsync Success - Loan Date - only start date - sorting will be by Dealer Code ASC then importid descending and then by member number ascending
|
||||||
|
Given the Loan table has the following loans
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number |Application Id | Member Last Name | Member First Name | Member Initial | Dealer Code | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type Id | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | Action Required |
|
||||||
|
| 1 | 1 | 12 | 3 |345 | SMITH | JOE | | H21 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 2 | 2 | 45 | 6 |678 | JONES | LAURA | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 3 | 2 | 22 | 2 |901 | JOHNSON | LAURA | M | S7 | 2/23/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 1 |
|
||||||
|
And a loan filter that looks like
|
||||||
|
| MemberNumberText | MemberNameText |LoanNumberText | LoanDateStart | LoanDateEnd | ImportId | DealerCodeText | ActionRequired | SortField | SortDirection | MaxRecordsPerPage | MaxPagesPerRange |
|
||||||
|
| | | | 2/24/2021 | | | | | DealerCode | ASC | 15 | 7 |
|
||||||
|
When I get the list of the filtered loans with the loan service
|
||||||
|
Then the loan ids from the loan service look like "2,1"
|
||||||
|
|
||||||
|
Scenario: GetFilteredAsync Success - Loan Date - only end date - sorting will be by Dealer Code ASC then importid descending and then by member number ascending
|
||||||
|
Given the Loan table has the following loans
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Dealer Code | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type Id | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | Action Required |
|
||||||
|
| 1 | 1 | 12 | 3 | SMITH | JOE | | H21 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 2 | 2 | 45 | 6 | JONES | LAURA | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 3 | 2 | 22 | 2 | JOHNSON | LAURA | M | S7 | 2/23/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 1 |
|
||||||
|
And a loan filter that looks like
|
||||||
|
| MemberNumberText | MemberNameText | LoanNumberText | ApplicationIdText | LoanDateStart | LoanDateEnd | ImportId | DealerCodeText | ActionRequired | SortField | SortDirection | MaxRecordsPerPage | MaxPagesPerRange |
|
||||||
|
| | | | | | 2/24/2021 | | | | DealerCode | ASC | 15 | 7 |
|
||||||
|
When I get the list of the filtered loans with the loan service
|
||||||
|
Then the loan ids from the loan service look like "2,3"
|
||||||
|
|
||||||
|
Scenario: GetFilteredAsync Success - all filters used - sorting will be by DealerCode ASC then importid descending and then by member number ascending
|
||||||
|
Given the Loan table has the following loans
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number | Application Id | Member Last Name | Member First Name | Member Initial | DealerOrganizationNumber | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type Id | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | Action Required |
|
||||||
|
| 1 | 1 | 12 | 3 | 345 | SMITH | JOE | | 1234 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 2 | 2 | 45 | 6 | 678 | JONES | LAURA | M | 1111 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 3 | 2 | 22 | 2 | 901 | JOHNSON | LAURA | M | 1111 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 1 |
|
||||||
|
And the dealer table has these dealers
|
||||||
|
| Dealer Code | Name | DealerOrganizationNumber |
|
||||||
|
| H21 | HEISER CHEVROLET CADILLAC OF WEST BEND | 1111 |
|
||||||
|
| A1 | ACURA OF BROOKFIELD | 5678 |
|
||||||
|
| S7 | SUBURBAN MOTORS HARLEY DAVIDSON | 1234 |
|
||||||
|
And a loan filter that looks like
|
||||||
|
| MemberNumberText | MemberNameText | LoanNumberText | ApplicationIdText | ImportId | LoanDateStart | LoanDateEnd | DealerCodeText | ActionRequired | SortField | SortDirection | MaxRecordsPerPage | MaxPagesPerRange |
|
||||||
|
| 22 | Joh | 2 | 9 | 2 | 2/24/2021 | 2/24/2021 | H21 | 1 | DealerCode | ASC | 15 | 7 |
|
||||||
|
When I get the list of the filtered loans with the loan service
|
||||||
|
Then the loan ids from the loan service look like "3"
|
||||||
|
|
||||||
|
Scenario: GetFilteredAsync Success - returning nothing - sorting will be by Dealer Code DESC then importid descending and then by member number ascending
|
||||||
|
Given the Loan table has the following loans
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number | Application Id |Member Last Name | Member First Name | Member Initial | Dealer Code | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type Id | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | Action Required |
|
||||||
|
| 1 | 1 | 12 | 3 | 345 |SMITH | JOE | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 2 | 2 | 45 | 6 | 678 |JONES | LAURA | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 1 |
|
||||||
|
| 3 | 2 | 22 | 2 | 901 |JOHNSON | LAURA | M | H22 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
And a loan filter that looks like
|
||||||
|
| MemberNumberText | MemberNameText | LoanNumberText | ApplicationIdText | ImportId | LoanDateStart | LoanDateEnd | DealerCodeText | ActionRequired | SortField | SortDirection | MaxRecordsPerPage | MaxPagesPerRange |
|
||||||
|
| | | | |1 | | | H21 | 0 | DealerCode | DESC | 15 | 7 |
|
||||||
|
When I get the list of the filtered loans with the loan service
|
||||||
|
Then the result from the loan service should have 0 loans
|
||||||
|
|
||||||
|
Scenario: GetPagedListAsync Success - returning page count with one index and one record validation - no filtering sorting will be by MemberFirstName DESC then importid descending and then by member number ascending
|
||||||
|
Given the Loan table has the following loans
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number | Application Id | Member Last Name | Member First Name | Member Initial | Dealer Code | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | Action Required |
|
||||||
|
| 1 | 1 | 12 | 3 | 1 | Smith | Joe | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 2 | 2 | 45 | 6 | 2 | Jones | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 1 |
|
||||||
|
| 3 | 2 | 22 | 2 | 3 | Johnson | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 4 | 1 | 55 | 5 | 4 | Gallagher | Frank | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 5 | 2 | 99 | 8 | 5 | Luke | Dwight | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 6 | 2 | 78 | 9 | 6 | Patterson | Sandy | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 7 | 1 | 34 | 3 | 7 | Best | Ronald | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 8 | 2 | 11 | 1 | 8 | Hayes | Willie | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 9 | 2 | 11 | 2 | 9 | McGuire | Jerry | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 10 | 1 | 12 | 3 | 10 | Smith | Joey | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 11 | 2 | 45 | 6 | 11 | Jones | Loren | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 1 |
|
||||||
|
| 12 | 2 | 22 | 2 | 12 | Johnson | Lizzie | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 13 | 1 | 55 | 5 | 13 | Gallagher | Farrah | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 14 | 2 | 99 | 8 | 14 | Luke | Delilah | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 15 | 2 | 78 | 9 | 15 | Patterson | Steve | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 16 | 1 | 34 | 3 | 16 | Best | Rainier | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 17 | 2 | 11 | 1 | 17 | Hayes | Wendy | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 18 | 2 | 11 | 2 | 18 | McGuire | Sara | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
And a loan filter that looks like
|
||||||
|
| MemberNumberText | MemberNameText | LoanNumberText | ApplicationIdText | ImportId | LoanDateStart | LoanDateEnd | DealerCodeText | ActionRequired | SortField | SortDirection | PageIndex | MaxRecordsPerPage | MaxPagesPerRange |
|
||||||
|
| | | | | | | | | | MemberFirstName | DESC | 2 | 15 | 7 |
|
||||||
|
When I get the list of paged loans
|
||||||
|
Then the result from the loan service should have 2 pages
|
||||||
|
And the first result from the loan service should have loanid 13
|
||||||
|
|
||||||
|
Scenario: GetPagedListAsync Success - returning one index record count and one record validation - no filtering sorting will be by MemberLastName DESC then importid descending and then by member number ascending
|
||||||
|
Given the Loan table has the following loans
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number | Application Id |Member Last Name | Member First Name | Member Initial | Dealer Code | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | Action Required |
|
||||||
|
| 1 | 1 | 12 | 3 | 1 |Smith | Joe | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 2 | 2 | 45 | 6 | 2 |Jones | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 1 |
|
||||||
|
| 3 | 2 | 22 | 2 | 3 |Johnson | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 4 | 1 | 55 | 5 | 4 |Gallagher | Frank | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 5 | 2 | 99 | 8 | 5 |Luke | Dwight | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 6 | 2 | 78 | 9 | 6 |Patterson | Sandy | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 7 | 1 | 34 | 3 | 7 |Best | Ronald | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 8 | 2 | 11 | 1 | 8 |Hayes | Willie | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 9 | 2 | 11 | 2 | 9 |McGuire | Jerry | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 10 | 1 | 12 | 3 | 10 |Smith | Joey | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 11 | 2 | 45 | 6 | 11 |Jones | Loren | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 1 |
|
||||||
|
| 12 | 2 | 22 | 2 | 12 |Johnson | Lizzie | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 13 | 1 | 55 | 5 | 13 |Gallagher | Farrah | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 14 | 2 | 99 | 8 | 14 |Luke | Delilah | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 15 | 2 | 78 | 9 | 15 |Patterson | Steve | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 16 | 1 | 34 | 3 | 16 |Best | Rainier | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 17 | 2 | 11 | 1 | 17 |Hayes | Wendy | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 18 | 2 | 11 | 2 | 18 |McGuire | Sara | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
And a loan filter that looks like
|
||||||
|
| MemberNumberText | MemberNameText | LoanNumberText | ApplicationIdText | ImportId | LoanDateStart | LoanDateEnd | DealerCodeText | ActionRequired | SortField | SortDirection | PageIndex | MaxRecordsPerPage | MaxPagesPerRange |
|
||||||
|
| | | | | | | | | | MemberLastName | DESC | 1 | 15 | 7 |
|
||||||
|
When I get the list of paged loans
|
||||||
|
Then the result from the loan service should have 15 records
|
||||||
|
And the first result from the loan service should have loanid 1
|
||||||
|
|
||||||
|
Scenario: GetPagedListAsync Fail - not returning pages no records - no sorting or filtering
|
||||||
|
Given the Loan table has the following loans
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number | Application Id |Member Last Name | Member First Name | Member Initial | Dealer Code | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | Action Required |
|
||||||
|
| 1 | 1 | 12 | 3 | 1 |Smith | Joe | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 2 | 2 | 45 | 6 | 2 |Jones | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 1 |
|
||||||
|
| 3 | 2 | 22 | 2 | 3 |Johnson | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 4 | 1 | 55 | 5 | 4 |Gallagher | Frank | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 5 | 2 | 99 | 8 | 5 |Luke | Dwight | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 6 | 2 | 78 | 9 | 6 |Patterson | Sandy | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 7 | 1 | 34 | 3 | 7 |Best | Ronald | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 8 | 2 | 11 | 1 | 8 |Hayes | Willie | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 9 | 2 | 11 | 2 | 9 |McGuire | Jerry | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 10 | 1 | 12 | 3 | 10 |Smith | Joey | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 11 | 2 | 45 | 6 | 11 |Jones | Loren | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 1 |
|
||||||
|
| 12 | 2 | 22 | 2 | 12 |Johnson | Lizzie | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 13 | 1 | 55 | 5 | 13 |Gallagher | Farrah | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 14 | 2 | 99 | 8 | 14 |Luke | Delilah | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 15 | 2 | 78 | 9 | 15 |Patterson | Steve | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 16 | 1 | 34 | 3 | 16 |Best | Rainier | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 17 | 2 | 11 | 1 | 17 |Hayes | Wendy | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 18 | 2 | 11 | 2 | 18 |McGuire | Sara | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
Then the result from the loan service should have 0 total items
|
||||||
|
|
||||||
|
Scenario: GetPagedListAsync HasPrevious Page Success HasNext Page Fail - returning one index record count checking previous next - no sorting or filtering
|
||||||
|
Given the Loan table has the following loans
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number | Application Id | Member Last Name | Member First Name | Member Initial | Dealer Code | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | Action Required |
|
||||||
|
| 1 | 1 | 12 | 3 | 1 | Smith | Joe | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 2 | 2 | 45 | 6 | 2 | Jones | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 1 |
|
||||||
|
| 3 | 2 | 22 | 2 | 3 | Johnson | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 4 | 1 | 55 | 5 | 4 | Gallagher | Frank | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 5 | 2 | 99 | 8 | 5 | Luke | Dwight | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 6 | 2 | 78 | 9 | 6 | Patterson | Sandy | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 7 | 1 | 34 | 3 | 7 | Best | Ronald | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 8 | 2 | 11 | 1 | 8 | Hayes | Willie | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 9 | 2 | 11 | 2 | 9 | McGuire | Jerry | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 10 | 1 | 12 | 3 | 10 | Smith | Joey | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 11 | 2 | 45 | 6 | 11 | Jones | Loren | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 1 |
|
||||||
|
| 12 | 2 | 22 | 2 | 12 | Johnson | Lizzie | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 13 | 1 | 55 | 5 | 13 | Gallagher | Farrah | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 14 | 2 | 99 | 8 | 14 | Luke | Delilah | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 15 | 2 | 78 | 9 | 15 | Patterson | Steve | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 16 | 1 | 34 | 3 | 16 | Best | Rainier | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 17 | 2 | 11 | 1 | 17 | Hayes | Wendy | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 18 | 2 | 11 | 2 | 18 | McGuire | Sara | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
And a loan filter that looks like
|
||||||
|
| MemberNumberText | MemberNameText | LoanNumberText | ApplicationIdText | ImportId | LoanDateStart | LoanDateEnd | DealerCodeText | ActionRequired | SortField | SortDirection | PageIndex | MaxRecordsPerPage | MaxPagesPerRange |
|
||||||
|
| | | | | | | | | | | | 2 | 15 | 7 |
|
||||||
|
When I get the list of paged loans
|
||||||
|
Then the result from the loan service should have 3 records
|
||||||
|
And the result from the loan service has previous page should be true
|
||||||
|
And the result from the loan service has next page should be false
|
||||||
|
|
||||||
|
Scenario: GetPagedListAsync HasPrevious Page Fail HasNext Page Success - returning one index record count checking previous next - no sorting or filtering
|
||||||
|
Given the Loan table has the following loans
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number | Application Id |Member Last Name | Member First Name | Member Initial | Dealer Code | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | Action Required |
|
||||||
|
| 1 | 1 | 12 | 3 | 1 |Smith | Joe | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 2 | 2 | 45 | 6 | 2 |Jones | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 1 |
|
||||||
|
| 3 | 2 | 22 | 2 | 3 |Johnson | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 4 | 1 | 55 | 5 | 4 |Gallagher | Frank | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 5 | 2 | 99 | 8 | 5 |Luke | Dwight | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 6 | 2 | 78 | 9 | 6 |Patterson | Sandy | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 7 | 1 | 34 | 3 | 7 |Best | Ronald | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 8 | 2 | 11 | 1 | 8 |Hayes | Willie | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 9 | 2 | 11 | 2 | 9 |McGuire | Jerry | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 10 | 1 | 12 | 3 | 10 |Smith | Joey | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 11 | 2 | 45 | 6 | 11 |Jones | Loren | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 1 |
|
||||||
|
| 12 | 2 | 22 | 2 | 12 |Johnson | Lizzie | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 13 | 1 | 55 | 5 | 13 |Gallagher | Farrah | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 14 | 2 | 99 | 8 | 14 |Luke | Delilah | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 15 | 2 | 78 | 9 | 15 |Patterson | Steve | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 16 | 1 | 34 | 3 | 16 |Best | Rainier | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 17 | 2 | 11 | 1 | 17 |Hayes | Wendy | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 18 | 2 | 11 | 2 | 18 |McGuire | Sara | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
And a loan filter that looks like
|
||||||
|
| MemberNumberText | MemberNameText | LoanNumberText | ApplicationIdText | ImportId | LoanDateStart | LoanDateEnd | DealerCodeText | ActionRequired | SortField | SortDirection | PageIndex | MaxRecordsPerPage | MaxPagesPerRange |
|
||||||
|
| | | | | | | | | | | | 1 | 15 | 7 |
|
||||||
|
When I get the list of paged loans
|
||||||
|
Then the result from the loan service should have 15 records
|
||||||
|
And the result from the loan service has previous page should be false
|
||||||
|
And the result from the loan service has next page should be true
|
||||||
|
|
||||||
|
Scenario: GetPagedListAsync Success - returning page count with one index and one record validation - Filter by DealerCodeText sorting will be by MemberFirstName DESC then importid descending and then by member number ascending
|
||||||
|
Given the Loan table has the following loans
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number | Application Id | Member Last Name | Member First Name | Member Initial | DealerOrganizationNumber | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | Action Required |
|
||||||
|
| 1 | 1 | 12 | 3 | 1 | Smith | Joe | | 1234 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 2 | 2 | 45 | 6 | 2 | Jones | Laura | M | 1111 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 1 |
|
||||||
|
| 3 | 2 | 22 | 2 | 3 | Johnson | Laura | M | 1111 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 4 | 1 | 55 | 5 | 4 | Gallagher | Frank | | 1234 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 5 | 2 | 99 | 8 | 5 | Luke | Dwight | M | 1111 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 6 | 2 | 78 | 9 | 6 | Patterson | Sandy | M | 1111 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 7 | 1 | 34 | 3 | 7 | Best | Ronald | | 1234 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 8 | 2 | 11 | 1 | 8 | Hayes | Willie | M | 1111 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 9 | 2 | 11 | 2 | 9 | McGuire | Jerry | M | 1111 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 10 | 1 | 12 | 3 | 10 | Smith | Joey | | 1234 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 11 | 2 | 45 | 6 | 11 | Jones | Loren | M | 1111 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 1 |
|
||||||
|
| 12 | 2 | 22 | 2 | 12 | Johnson | Lizzie | M | 1111 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 13 | 1 | 55 | 5 | 13 | Gallagher | Farrah | | 1234 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 14 | 2 | 99 | 8 | 14 | Luke | Delilah | M | 1111 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 15 | 2 | 78 | 9 | 15 | Patterson | Steve | M | 1111 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 16 | 1 | 34 | 3 | 16 | Best | Rainier | | 1234 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 17 | 2 | 11 | 1 | 17 | Hayes | Wendy | M | 1111 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 18 | 2 | 11 | 2 | 18 | McGuire | Sara | M | 1111 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
And the dealer table has these dealers
|
||||||
|
| Dealer Code | Name | DealerOrganizationNumber |
|
||||||
|
| H21 | HEISER CHEVROLET CADILLAC OF WEST BEND | 1111 |
|
||||||
|
| A1 | ACURA OF BROOKFIELD | 5678 |
|
||||||
|
| S7 | SUBURBAN MOTORS HARLEY DAVIDSON | 1234 |
|
||||||
|
And a loan filter that looks like
|
||||||
|
| MemberNumberText | MemberFirstNameText | MemberLastNameText | ApplicationIdText | LoanNumberText | ImportId | LoanDateStart | LoanDateEnd | DealerCodeText | ActionRequired | SortField | SortDirection | PageIndex | MaxRecordsPerPage | MaxPagesPerRange |
|
||||||
|
| | | | | | | | | H21 | | MemberFirstName | DESC | 1 | 15 | 7 |
|
||||||
|
When I get the list of paged loans
|
||||||
|
Then the result from the loan service should have 1 pages
|
||||||
|
And the first result from the loan service should have loanid 8
|
||||||
|
|
||||||
|
Scenario: GetPagedListAsync Success - returning one index record count and one record validation - Filtering by ActionRequired sorting will be by MemberLastName DESC then importid descending and then by member number ascending
|
||||||
|
Given the Loan table has the following loans
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number | Application Id | Member Last Name | Member First Name | Member Initial | Dealer Code | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | Action Required |
|
||||||
|
| 1 | 1 | 12 | 3 | 1 | Smith | Joe | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 2 | 2 | 45 | 6 | 2 | Jones | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 1 |
|
||||||
|
| 3 | 2 | 22 | 2 | 3 | Johnson | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 4 | 1 | 55 | 5 | 4 | Gallagher | Frank | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 5 | 2 | 99 | 8 | 5 | Luke | Dwight | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 6 | 2 | 78 | 9 | 6 | Patterson | Sandy | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 7 | 1 | 34 | 3 | 7 | Best | Ronald | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 8 | 2 | 11 | 1 | 8 | Hayes | Willie | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 9 | 2 | 11 | 2 | 9 | McGuire | Jerry | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 10 | 1 | 12 | 3 | 10 | Smith | Joey | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 11 | 2 | 45 | 6 | 11 | Jones | Loren | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 1 |
|
||||||
|
| 12 | 2 | 22 | 2 | 12 | Johnson | Lizzie | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 13 | 1 | 55 | 5 | 13 | Gallagher | Farrah | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 14 | 2 | 99 | 8 | 14 | Luke | Delilah | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 15 | 2 | 78 | 9 | 15 | Patterson | Steve | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 16 | 1 | 34 | 3 | 16 | Best | Rainier | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 17 | 2 | 11 | 1 | 17 | Hayes | Wendy | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 18 | 2 | 11 | 2 | 18 | McGuire | Sara | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
And a loan filter that looks like
|
||||||
|
| MemberNumberText | MemberNameText | LoanNumberText | ApplicationIdText | ImportId | LoanDateStart | LoanDateEnd | DealerCodeText | ActionRequired | SortField | SortDirection | PageIndex | MaxRecordsPerPage | MaxPagesPerRange |
|
||||||
|
| | | | | | | | | 1 | MemberLastName | DESC | 1 | 15 | 7 |
|
||||||
|
When I get the list of paged loans
|
||||||
|
Then the result from the loan service should have 8 records
|
||||||
|
And the first result from the loan service should have loanid 1
|
||||||
|
|
||||||
|
Scenario: GetPagedListAsync Success Page Range Values Check Last Page Index First and Last Page - returning one index record count and one record validation - Filtering by ImportId sorting will be by MemberLastName DESC then importid descending and then by member number ascending
|
||||||
|
Given the Loan table has the following loans
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number | Application Id | Member Last Name | Member First Name | Member Initial | Dealer Code | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | Action Required |
|
||||||
|
| 1 | 1 | 12 | 3 | 1 | Zeman | Joe | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 2 | 1 | 45 | 6 | 2 | Jones | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 1 |
|
||||||
|
| 3 | 1 | 22 | 2 | 3 | Johnson | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 4 | 1 | 55 | 5 | 4 | Gallagher | Frank | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 5 | 1 | 99 | 8 | 5 | Luke | Dwight | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 6 | 1 | 78 | 9 | 6 | Patterson | Sandy | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 7 | 1 | 34 | 3 | 7 | Best | Ronald | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 8 | 1 | 11 | 1 | 8 | Hayes | Willie | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 9 | 1 | 11 | 2 | 9 | McGuire | Jerry | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 10 | 1 | 12 | 3 | 10 | Smith | Joey | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 11 | 1 | 45 | 6 | 11 | Jones | Loren | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 1 |
|
||||||
|
| 12 | 1 | 22 | 2 | 12 | Johnson | Lizzie | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 13 | 1 | 55 | 5 | 13 | Gallagher | Farrah | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 14 | 1 | 99 | 8 | 14 | Luke | Delilah | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 15 | 1 | 78 | 9 | 15 | Patterson | Steve | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 16 | 1 | 34 | 3 | 16 | Best | Rainier | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 17 | 1 | 11 | 1 | 17 | Hayes | Wendy | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 18 | 1 | 11 | 2 | 18 | McGuire | Sara | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 19 | 2 | 11 | 1 | 19 | Sorenson | Jill | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 20 | 2 | 11 | 2 | 20 | Berry | Bill | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
|
||||||
|
And a loan filter that looks like
|
||||||
|
| MemberNumberText | MemberNameText | LoanNumberText | ApplicationIdText | ImportId | LoanDateStart | LoanDateEnd | DealerCodeText | ActionRequired | SortField | SortDirection | PageIndex | MaxRecordsPerPage | MaxPagesPerRange |
|
||||||
|
| | | | | 1 | | | | | MemberLastName | DESC | 9 | 2 | 3 |
|
||||||
|
When I get the list of paged loans
|
||||||
|
Then the result from the loan service should have 2 records
|
||||||
|
And the first result from the loan service should have loanid 7
|
||||||
|
And the result from the loan service has previous page should be true
|
||||||
|
And the result from the loan service has next page should be false
|
||||||
|
And the result from the loan service first page should be 7
|
||||||
|
And the result from the loan service last page should be 9
|
||||||
|
|
||||||
|
Scenario: GetPagedListAsync Success - Page Range Values Check First and Last Page - returning one index record count and one record validation - Filtering by Dealer Code sorting will be by MemberLastName DESC then importid descending and then by member number ascending
|
||||||
|
Given the Loan table has the following loans
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number | Application Id | Member Last Name | Member First Name | Member Initial | DealerOrganizationNumber | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | Action Required |
|
||||||
|
| 1 | 1 | 12 | 3 | 1 | Smith | Joe | | 1234 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 2 | 2 | 45 | 6 | 2 | Jones | Laura | M | 1234 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 1 |
|
||||||
|
| 3 | 2 | 22 | 2 | 3 | Johnson | Laura | M | 1234 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 4 | 1 | 55 | 5 | 4 | Gallagher | Frank | | 1234 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 5 | 2 | 99 | 8 | 5 | Luke | Dwight | M | 1234 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 6 | 2 | 78 | 9 | 6 | Patterson | Sandy | M | 1234 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 7 | 1 | 34 | 3 | 7 | Best | Ronald | | 1234 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 8 | 2 | 11 | 1 | 8 | Hayes | Willie | M | 1234 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 9 | 2 | 11 | 2 | 9 | McGuire | Jerry | M | 1234 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 10 | 1 | 12 | 3 | 10 | Smith | Joey | | 1234 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 11 | 2 | 45 | 6 | 11 | Jones | Loren | M | 1234 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 1 |
|
||||||
|
| 12 | 2 | 22 | 2 | 12 | Johnson | Lizzie | M | 1234 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 13 | 1 | 55 | 5 | 13 | Gallagher | Farrah | | 1234 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 14 | 2 | 99 | 8 | 14 | Luke | Delilah | M | 1234 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 15 | 2 | 78 | 9 | 15 | Patterson | Steve | M | 1234 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 16 | 1 | 34 | 3 | 16 | Best | Rainier | | 1234 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 17 | 2 | 11 | 1 | 17 | Hayes | Wendy | M | 1111 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 18 | 2 | 11 | 2 | 18 | McGuire | Sara | M | 1111 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
And the dealer table has these dealers
|
||||||
|
| Dealer Code | Name | DealerOrganizationNumber |
|
||||||
|
| H21 | HEISER CHEVROLET CADILLAC OF WEST BEND | 1111 |
|
||||||
|
| A1 | ACURA OF BROOKFIELD | 5678 |
|
||||||
|
| S21 | SUBURBAN MOTORS HARLEY DAVIDSON | 1234 |
|
||||||
|
And a loan filter that looks like
|
||||||
|
| MemberNumberText | MemberNameText | LoanNumberText | ApplicationIdText | ImportId | LoanDateStart | LoanDateEnd | DealerCodeText | ActionRequired | SortField | SortDirection | PageIndex | MaxRecordsPerPage | MaxPagesPerRange |
|
||||||
|
| | | | | | | | S21 | | MemberLastName | DESC | 5 | 2 | 3 |
|
||||||
|
When I get the list of paged loans
|
||||||
|
Then the result from the loan service should have 2 records
|
||||||
|
And the first result from the loan service should have loanid 11
|
||||||
|
And the result from the loan service has previous page should be true
|
||||||
|
And the result from the loan service has next page should be true
|
||||||
|
And the result from the loan service first page should be 4
|
||||||
|
And the result from the loan service last page should be 6
|
||||||
|
|
||||||
|
Scenario: GetPagedListAsync Success - Page Range Values Check Below Page Range Max - returning one index record count and one record validation - Filtering by Dealer Code sorting will be by MemberLastName DESC then importid descending and then by member number ascending
|
||||||
|
Given the Loan table has the following loans
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number | Application Id | Member Last Name | Member First Name | Member Initial | DealerOrganizationNumber | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | Action Required |
|
||||||
|
| 1 | 1 | 12 | 3 | 1 | Smith | Joe | | 1234 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 2 | 2 | 45 | 6 | 2 | Jones | Laura | M | 1234 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 1 |
|
||||||
|
| 3 | 2 | 22 | 2 | 3 | Johnson | Laura | M | 1234 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 4 | 1 | 55 | 5 | 4 | Gallagher | Frank | | 1234 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 5 | 2 | 99 | 8 | 5 | Luke | Dwight | M | 1234 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 6 | 2 | 78 | 9 | 6 | Patterson | Sandy | M | 1234 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 7 | 1 | 34 | 3 | 7 | Best | Ronald | | 1234 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 8 | 2 | 11 | 1 | 8 | Hayes | Willie | M | 1234 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 9 | 2 | 11 | 2 | 9 | McGuire | Jerry | M | 1234 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 10 | 1 | 12 | 3 | 10 | Smith | Joey | | 1234 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 11 | 2 | 45 | 6 | 11 | Jones | Loren | M | 1234 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 1 |
|
||||||
|
| 12 | 2 | 22 | 2 | 12 | Johnson | Lizzie | M | 1234 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 13 | 1 | 55 | 5 | 13 | Gallagher | Farrah | | 1234 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 14 | 2 | 99 | 8 | 14 | Luke | Delilah | M | 1234 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 15 | 2 | 78 | 9 | 15 | Patterson | Steve | M | 1234 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
| 16 | 1 | 34 | 3 | 16 | Best | Rainier | | 1234 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard | 1 |
|
||||||
|
| 17 | 2 | 11 | 1 | 17 | Hayes | Wendy | M | 1111 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | 0 |
|
||||||
|
| 18 | 2 | 11 | 2 | 18 | McGuire | Sara | M | 1111 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message | |
|
||||||
|
And the dealer table has these dealers
|
||||||
|
| Dealer Code | Name | DealerOrganizationNumber |
|
||||||
|
| H21 | HEISER CHEVROLET CADILLAC OF WEST BEND | 1111 |
|
||||||
|
| A1 | ACURA OF BROOKFIELD | 5678 |
|
||||||
|
| S21 | SUBURBAN MOTORS HARLEY DAVIDSON | 1234 |
|
||||||
|
And a loan filter that looks like
|
||||||
|
| MemberNumberText | MemberNameText | LoanNumberText | ApplicationIdText | ImportId | LoanDateStart | LoanDateEnd | DealerCodeText | ActionRequired | SortField | SortDirection | PageIndex | MaxRecordsPerPage | MaxPagesPerRange |
|
||||||
|
| | | | | | | | S21 | 1 | MemberLastName | DESC | 2 | 4 | 4 |
|
||||||
|
When I get the list of paged loans
|
||||||
|
Then the result from the loan service should have 4 records
|
||||||
|
And the first result from the loan service should have loanid 4
|
||||||
|
And the result from the loan service has previous page should be true
|
||||||
|
And the result from the loan service has next page should be false
|
||||||
|
And the result from the loan service first page should be 1
|
||||||
|
And the result from the loan service last page should be 2
|
||||||
+183
@@ -0,0 +1,183 @@
|
|||||||
|
Feature: Loan Service Get all, Get By Id
|
||||||
|
Gets all loans, get loan by loanId
|
||||||
|
|
||||||
|
Scenario: GetListAsync Success and sorting will be by importid descending and then by member number ascending
|
||||||
|
Given the Loan table has the following loans
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Dealer Code | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type Id | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message |
|
||||||
|
| 1 | 1 | 12 | 3 | Smith | Joe | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard |
|
||||||
|
| 2 | 2 | 45 | 6 | Jones | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message |
|
||||||
|
| 3 | 2 | 22 | 2 | Johnson | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message |
|
||||||
|
When I get the list of all loans with the loan service
|
||||||
|
Then the result from the loan service should have 3 loans
|
||||||
|
And the first loan from the loan service has LoanId 3
|
||||||
|
|
||||||
|
Scenario: GetListAsync Exception
|
||||||
|
Given the Loan Repository throws an exception in ListAll
|
||||||
|
When I get the list of all loans with the loan service with the mock loan repo
|
||||||
|
Then the Loan Service throws an exception with the message "Exception of type 'System.Exception' was thrown."
|
||||||
|
|
||||||
|
Scenario: GetListAsync - get dealer info
|
||||||
|
Given the Loan table has the following loans
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | DealerOrganizationNumber | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type Id | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message |
|
||||||
|
| 1 | 1 | 12 | 3 | Smith | Joe | | 1234 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard |
|
||||||
|
| 2 | 2 | 45 | 6 | Jones | Laura | M | 1111 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message |
|
||||||
|
| 3 | 2 | 22 | 2 | Johnson | Laura | M | 5678 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message |
|
||||||
|
And the dealer table has these dealers
|
||||||
|
| Dealer Code | Name | DealerOrganizationNumber |
|
||||||
|
| H21 | HEISER CHEVROLET CADILLAC OF WEST BEND | 1111 |
|
||||||
|
| A1 | ACURA OF BROOKFIELD | 5678 |
|
||||||
|
| S7 | SUBURBAN MOTORS HARLEY DAVIDSON | 1234 |
|
||||||
|
|
||||||
|
When I get the list of all loans with the loan service
|
||||||
|
Then the result from the loan service should have 3 loans
|
||||||
|
And the first loan from the loan service has LoanId 3
|
||||||
|
And the loan with LoanId 1 has dealer name "SUBURBAN MOTORS HARLEY DAVIDSON"
|
||||||
|
And the loan with LoanId 2 has dealer name "HEISER CHEVROLET CADILLAC OF WEST BEND"
|
||||||
|
|
||||||
|
Scenario: GetByIdAsync Success
|
||||||
|
Given the Loan table has the following loans
|
||||||
|
| LoanId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | DealerOrganizationNumber | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type Id | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message |
|
||||||
|
| 1 | 12 | 3 | Smith | Joe | | 1234 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | BB | 63 | 210.0375 | 200 | false | | | Standard |
|
||||||
|
| 2 | 45 | 6 | Jones | Laura | M | 5678 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | NC | 60 | 1450.2923 | 500 | false | | | Message |
|
||||||
|
And the dealer table has these dealers
|
||||||
|
| Dealer Code | Name | DealerOrganizationNumber |
|
||||||
|
| S7 | SUBURBAN MOTORS HARLEY DAVIDSON | 1234 |
|
||||||
|
| H21 | HEISER CHEVROLET CADILLAC OF WEST BEND | 5678 |
|
||||||
|
And loan types that look like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
| BB | Standard | S | 0 | 0 | 0 | 1.00 | 0.25 |
|
||||||
|
When I get the loan with the loanId 2 from the loan service
|
||||||
|
Then the loan from the loan service has LoanId 2
|
||||||
|
And the loan from the loan service has LoanType.LoanComment "75% Reserve"
|
||||||
|
And the loan from the loan service has dealer name "HEISER CHEVROLET CADILLAC OF WEST BEND"
|
||||||
|
|
||||||
|
Scenario: GetByIdAsync - unknown loan type
|
||||||
|
Given the Loan table has the following loans
|
||||||
|
| LoanId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Dealer Code | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type Id | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message |
|
||||||
|
| 1 | 12 | 3 | Smith | Joe | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | BB | 63 | 210.0375 | 200 | false | | | Standard |
|
||||||
|
| 2 | 45 | 6 | Jones | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | NC | 60 | 1450.2923 | 500 | false | | | Message |
|
||||||
|
And loan types that look like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When I get the loan with the loanId 1 from the loan service
|
||||||
|
Then the loan from the loan service has LoanId 1
|
||||||
|
And the loan from the loan service has LoanType.LoanComment ""
|
||||||
|
|
||||||
|
Scenario: GetByIdAsync Exception - Not Found
|
||||||
|
Given the Loan table has the following loans
|
||||||
|
| LoanId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Dealer Code | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type Id | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message |
|
||||||
|
| 1 | 12 | 3 | Smith | Joe | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard |
|
||||||
|
| 2 | 45 | 6 | Jones | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message |
|
||||||
|
And loan types that look like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When I get the loan with the loanId 3 from the loan service
|
||||||
|
Then the Loan Service throws an exception with the message "Loan with id 3 not found."
|
||||||
|
|
||||||
|
Scenario: GetByIdAsync Exception - Loan Repository exception
|
||||||
|
Given the Loan Repository throws an exception in FindByIdAsync
|
||||||
|
When I get the loan with the loanId 2 from the loan service using the Mock Loan Repo
|
||||||
|
Then the Loan Service throws an exception with the message "Exception of type 'System.Exception' was thrown."
|
||||||
|
|
||||||
|
Scenario: Get Members - searching member number, don't return duplicates
|
||||||
|
Given the Loan table has the following loans
|
||||||
|
| LoanId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Dealer Code | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type Id | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message |
|
||||||
|
| 1 | 452 | 3 | Smith | Joe | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard |
|
||||||
|
| 2 | 451 | 6 | Jones | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message |
|
||||||
|
| 3 | 451 | 7 | Jones | Laura | M | H21 | 2/24/2023 | 2/27/2023 | 4/10/2023 | 3/10/2028 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message |
|
||||||
|
When I get the list of members with search string "45"
|
||||||
|
Then the list of members returned is in this order
|
||||||
|
| Member Number |
|
||||||
|
| 451 |
|
||||||
|
| 452 |
|
||||||
|
|
||||||
|
Scenario: Get Members - searching member number, return in number order, not string order
|
||||||
|
Given the Loan table has the following loans
|
||||||
|
| LoanId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Dealer Code | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate |Loan Type Id | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message |
|
||||||
|
| 1 | 452 | 3 | Smith | Joe | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 |NC | 63 | 210.0375 | 200 | false | | | Standard |
|
||||||
|
| 2 | 4510 | 6 | Jones | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 |BB | 60 | 1450.2923 | 500 | false | | | Message |
|
||||||
|
When I get the list of members with search string "45"
|
||||||
|
Then the list of members returned is in this order
|
||||||
|
| Member Number |
|
||||||
|
| 452 |
|
||||||
|
| 4510 |
|
||||||
|
|
||||||
|
Scenario: Get Members - only get numbers starting with the search string
|
||||||
|
Given the Loan table has the following loans
|
||||||
|
| LoanId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Dealer Code | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type Id | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message |
|
||||||
|
| 1 | 245 | 3 | Smith | Joe | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard |
|
||||||
|
| 2 | 451 | 6 | Jones | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message |
|
||||||
|
| 3 | 451 | 7 | Jones | Laura | M | H21 | 2/24/2023 | 2/27/2023 | 4/10/2023 | 3/10/2028 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message |
|
||||||
|
When I get the list of members with search string "45"
|
||||||
|
Then the list of members returned is in this order
|
||||||
|
| Member Number |
|
||||||
|
| 451 |
|
||||||
|
|
||||||
|
Scenario: Get Members - not searching name
|
||||||
|
Given the Loan table has the following loans
|
||||||
|
| LoanId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Dealer Code | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate |Loan Type Id | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message |
|
||||||
|
| 1 | 452 | 3 | Smith | Joe | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 |NC | 63 | 210.0375 | 200 | false | | | Standard |
|
||||||
|
| 2 | 451 | 6 | Jones | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 |BB | 60 | 1450.2923 | 500 | false | | | Message |
|
||||||
|
| 3 | 451 | 7 | Jones | Laura | M | H21 | 2/24/2023 | 2/27/2023 | 4/10/2023 | 3/10/2028 | 21274.24 | 2.490 | 4.970 |BB | 60 | 1450.2923 | 500 | false | | | Message |
|
||||||
|
When I get the list of members with search string "Jo"
|
||||||
|
Then the list of members returned is in this order
|
||||||
|
| Member Number |
|
||||||
|
|
||||||
|
Scenario: Get Loan Numbers
|
||||||
|
Given the Loan table has the following loans
|
||||||
|
| LoanId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Dealer Code | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type Id | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message |
|
||||||
|
| 1 | 452 | 731 | Smith | Joe | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard |
|
||||||
|
| 2 | 451 | 6 | Jones | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message |
|
||||||
|
| 3 | 451 | 73 | Jones | Laura | M | H21 | 2/24/2023 | 2/27/2023 | 4/10/2023 | 3/10/2028 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message |
|
||||||
|
When I get the list of loan numbers with search string "73"
|
||||||
|
Then the list of loan numbers looks like
|
||||||
|
| Loan Number |
|
||||||
|
| 73 |
|
||||||
|
| 731 |
|
||||||
|
|
||||||
|
Scenario: Get Loan Numbers, return in number order, not string order
|
||||||
|
Given the Loan table has the following loans
|
||||||
|
| LoanId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Dealer Code | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type Id | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message |
|
||||||
|
| 1 | 452 | 731 | Smith | Joe | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard |
|
||||||
|
| 2 | 451 | 6 | Jones | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message |
|
||||||
|
| 3 | 451 | 7307 | Jones | Laura | M | H21 | 2/24/2023 | 2/27/2023 | 4/10/2023 | 3/10/2028 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message |
|
||||||
|
When I get the list of loan numbers with search string "73"
|
||||||
|
Then the list of loan numbers looks like
|
||||||
|
| Loan Number |
|
||||||
|
| 731 |
|
||||||
|
| 7307 |
|
||||||
|
|
||||||
|
Scenario: Get Loan Numbers - only get numbers starting with the search string
|
||||||
|
Given the Loan table has the following loans
|
||||||
|
| LoanId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | Dealer Code | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type Id | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message |
|
||||||
|
| 1 | 452 | 173 | Smith | Joe | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard |
|
||||||
|
| 2 | 451 | 6 | Jones | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message |
|
||||||
|
| 3 | 451 | 73 | Jones | Laura | M | H21 | 2/24/2023 | 2/27/2023 | 4/10/2023 | 3/10/2028 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message |
|
||||||
|
When I get the list of loan numbers with search string "73"
|
||||||
|
Then the list of loan numbers looks like
|
||||||
|
| Loan Number |
|
||||||
|
| 73 |
|
||||||
|
|
||||||
|
Scenario: Get Application Ids, return in number order
|
||||||
|
Given the Loan table has the following loans
|
||||||
|
| LoanId | Member Number | Loan Number | Application Id | Member Last Name | Member First Name | Member Initial | Dealer Code | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type Id | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message |
|
||||||
|
| 1 | 452 | 731 | 112 | Smith | Joe | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard |
|
||||||
|
| 2 | 451 | 6 | 334 | Jones | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message |
|
||||||
|
| 3 | 451 | 73 | 35 | Jones | Laura | M | H21 | 2/24/2023 | 2/27/2023 | 4/10/2023 | 3/10/2028 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message |
|
||||||
|
When I get the list of application ids with search string "3"
|
||||||
|
Then the list of application ids looks like
|
||||||
|
|Application Id |
|
||||||
|
| 35 |
|
||||||
|
| 334 |
|
||||||
|
|
||||||
|
Scenario: Get Application Ids - only get ids starting with the search string
|
||||||
|
Given the Loan table has the following loans
|
||||||
|
| LoanId | Member Number | Loan Number | Application Id | Member Last Name | Member First Name | Member Initial | Dealer Code | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Amount | Buy Rate | Contract Rate | Loan Type Id | Term | Reserve Amount | MonthlyPmt | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message |
|
||||||
|
| 1 | 452 | 173 | 133 | Smith | Joe | | S7 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | 12615.87 | 4.030 | 4.790 | NC | 63 | 210.0375 | 200 | false | | | Standard |
|
||||||
|
| 2 | 451 | 6 | 334 | Jones | Laura | M | H21 | 2/24/2021 | 2/27/2021 | 4/10/2021 | 3/10/2026 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message |
|
||||||
|
| 3 | 451 | 73 | 35 | Jones | Laura | M | H21 | 2/24/2023 | 2/27/2023 | 4/10/2023 | 3/10/2028 | 21274.24 | 2.490 | 4.970 | BB | 60 | 1450.2923 | 500 | false | | | Message |
|
||||||
|
When I get the list of application ids with search string "33"
|
||||||
|
Then the list of application ids looks like
|
||||||
|
|Application Id |
|
||||||
|
| 334 |
|
||||||
+77
@@ -0,0 +1,77 @@
|
|||||||
|
Feature: Loan Service - Saving
|
||||||
|
Save loan with Reserve, save loan with chargeback
|
||||||
|
|
||||||
|
Background:
|
||||||
|
Given dealers that look like
|
||||||
|
| Dealer Code | Name | DealerOrganizationNumber | DealerAccountNumber |
|
||||||
|
| S7 | SUBURBAN MOTORS HARLEY DAVIDSON | 3434 | 324324324324324 |
|
||||||
|
| H21 | HEISER CHEVROLET CADILLAC OF WEST BEND | 1111 | |
|
||||||
|
| | | 1234 | 924324324324324 |
|
||||||
|
And loan types that look like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
|
||||||
|
|
||||||
|
Scenario: Save with Reserve Success
|
||||||
|
Given I have these loans to save
|
||||||
|
| ImportId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial |DealerOrganizationNumber | Loan Date | FirstPmtDate | FinalPmtDate | Posted Date | Loan Amount | Buy Rate | Contract Rate | MonthlyPmt | Loan Type Id | Term | Reserve Amount | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | Loan Status |
|
||||||
|
| 1 | 3250 | 144 | MUELLER | STEVEN | C |1234 | 2/10/2021 | 3/20/2021 | 2/10/2025 | 02/12/2021 | 25989.97 | 2.03 | 3.39 | 579.76 | NC | 48 | 0 | false | 0.00 | | | New |
|
||||||
|
When I save the loan with the reserve
|
||||||
|
Then the loans from the loan service look like
|
||||||
|
| ImportId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | DealerOrganizationNumber | Loan Date | FirstPmtDate | FinalPmtDate | Posted Date | Loan Amount | Buy Rate | Contract Rate | MonthlyPmt | Loan Type Id | Term | Reserve Amount | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | Loan Status |
|
||||||
|
| 1 | 3250 | 144 | MUELLER | STEVEN | C | 1234 | 2/10/2021 | 3/20/2021 | 2/10/2025 | 02/12/2021 | 25989.97 | 2.03 | 3.39 | 579.76 | NC | 48 | 566.98877654773011071101556050 | false | 0.00 | | Standard Reserve | New |
|
||||||
|
|
||||||
|
Scenario: Save with Reserve Failure
|
||||||
|
Given the Loan Repository throws an exception in UpdateAsync
|
||||||
|
And I have these loans to save
|
||||||
|
| ImportId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | DealerOrganizationNumber | Loan Date | FirstPmtDate | FinalPmtDate | Posted Date | Loan Amount | Buy Rate | Contract Rate | MonthlyPmt | Loan Type Id | Term | Reserve Amount | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | Loan Status |
|
||||||
|
| 1 | 3250 | 144 | MUELLER | STEVEN | C | 1234 | 2/10/2021 | 3/15/2021 | 3/12/2025 | 02/12/2021 | 25989.97 | 2.03 | 3.39 | 579.76 | NC | | | false | 0.00 | | | New |
|
||||||
|
When I save the loan with the reserve with the mock loan repo
|
||||||
|
Then the Loan Service throws an exception with the message "Exception of type 'System.Exception' was thrown."
|
||||||
|
|
||||||
|
Scenario: Save with Reserve - Set ActionRequired - Dealer organization null
|
||||||
|
Given I have these loans to save
|
||||||
|
| ImportId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial |DealerOrganizationNumber | Loan Date | FirstPmtDate | FinalPmtDate | Posted Date | Loan Amount | Buy Rate | Contract Rate | MonthlyPmt | Loan Type Id | Term | Reserve Amount | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | Loan Status | VIN Number | Make | Model | Year | Mileage | Color |
|
||||||
|
| 1 | 3250 | 144 | MUELLER | STEVEN | C |<null> | 2/10/2021 | 3/20/2021 | 2/10/2025 | 02/12/2021 | 25989.97 | 2.03 | 3.39 | 579.76 | NC | 48 | 0 | false | 0.00 | | | New | M733P33389Y85216 | | | | | |
|
||||||
|
When I save the loan with the reserve
|
||||||
|
Then the loans from the loan service look like
|
||||||
|
| ImportId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | DealerOrganizationNumber | Loan Date | FirstPmtDate | FinalPmtDate | Posted Date | Loan Amount | Buy Rate | Contract Rate | MonthlyPmt | Loan Type Id | Term | Reserve Amount | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | ActionRequired | Loan Status |
|
||||||
|
| 1 | 3250 | 144 | MUELLER | STEVEN | C | | 2/10/2021 | 3/20/2021 | 2/10/2025 | 02/12/2021 | 25989.97 | 2.03 | 3.39 | 579.76 | NC | 48 | 566.98877654773011071101556050 | false | 0.00 | | Standard Reserve | true | New |
|
||||||
|
|
||||||
|
Scenario: Save with Reserve - Set ActionRequired - first payment date before loan date
|
||||||
|
Given I have these loans to save
|
||||||
|
| ImportId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | DealerOrganizationNumber | Loan Date | FirstPmtDate | FinalPmtDate | Posted Date | Loan Amount | Buy Rate | Contract Rate | MonthlyPmt | Loan Type Id | Term | Reserve Amount | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | Loan Status | OriginalTermInDays |
|
||||||
|
| 1 | 3250 | 144 | MUELLER | STEVEN | C | 1234 | 2/10/2021 | 1/12/2021 | 2/10/2025 | 02/12/2021 | 25989.97 | 2.03 | 3.39 | 579.76 | NC | 50 | 0 | false | 0.00 | | | New | 1491 |
|
||||||
|
When I save the loan with the reserve
|
||||||
|
Then the loans from the loan service look like
|
||||||
|
| ImportId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | DealerOrganizationNumber | Loan Date | FirstPmtDate | FinalPmtDate | Posted Date | Loan Amount | Buy Rate | Contract Rate | MonthlyPmt | Loan Type Id | Term | Reserve Amount | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | ActionRequired | Loan Status |
|
||||||
|
| 1 | 3250 | 144 | MUELLER | STEVEN | C | 1234 | 2/10/2021 | 1/12/2021 | 2/10/2025 | 02/12/2021 | 25989.97 | 2.03 | 3.39 | 579.76 | NC | 50 | 584.06654602341792014440573200 | false | 0.00 | | Standard Reserve | true | New |
|
||||||
|
|
||||||
|
Scenario: Save with Reserve - Set ActionRequired True - Invalid Dealer Code
|
||||||
|
Given I have these loans to save
|
||||||
|
| ImportId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | DealerOrganizationNumber | Loan Date | FirstPmtDate | FinalPmtDate | Posted Date | Loan Amount | Buy Rate | Contract Rate | MonthlyPmt | Loan Type Id | Term | Reserve Amount | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | Loan Status | DealerOrganizationNumber | OriginalTermInDays |
|
||||||
|
| 1 | 3250 | 144 | MUELLER | STEVEN | C | 6222 | 2/10/2021 | 1/12/2021 | 2/10/2025 | 02/12/2021 | 25989.97 | 2.03 | 3.39 | 579.76 | NC | 50 | 0 | false | 0.00 | | | New | 2345 | 1491 |
|
||||||
|
When I save the loan with the reserve
|
||||||
|
Then the loans from the loan service look like
|
||||||
|
| ImportId | Member Number | Loan Number | Member Last Name | Member First Name | Member Initial | DealerOrganizationNumber | Loan Date | FirstPmtDate | FinalPmtDate | Posted Date | Loan Amount | Buy Rate | Contract Rate | MonthlyPmt | Loan Type Id | Term | Reserve Amount | Flat Fee Paid | Chargeback | Paid Loan Date | Reserve Message | ActionRequired | Loan Status |
|
||||||
|
| 1 | 3250 | 144 | MUELLER | STEVEN | C | 6222 | 2/10/2021 | 1/12/2021 | 2/10/2025 | 02/12/2021 | 25989.97 | 2.03 | 3.39 | 579.76 | NC | 50 | 584.06654602341792014440573200 | false | 0.00 | | Standard Reserve | true | New |
|
||||||
|
|
||||||
|
Scenario: SaveWithChargeback
|
||||||
|
Given I have these loans to save with chargebacks
|
||||||
|
| ImportId | Member Number | Loan Number | PaidLoanDate |
|
||||||
|
| 2 | 5841 | 147 | 2/19/2021 |
|
||||||
|
| 2 | 10094 | 143 | 12/22/2020 |
|
||||||
|
And the Loan table has the following loans
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Type Id | Term | Reserve Amount | Chargeback | Paid Loan Date | Reserve Message | Loan Status |
|
||||||
|
| 1 | 1 | 12 | 3 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | NC | 63 | 210.0375 | | | Standard | New |
|
||||||
|
| 2 | 1 | 5841 | 147 | 2/10/2021 | 2/27/2021 | 3/12/2021 | 2/12/2028 | NC | 84 | 1206.8106 | | | Message | New |
|
||||||
|
| 3 | 1 | 10094 | 143 | 12/7/2020 | 12/15/2020 | 1/21/2021 | 12/21/2025 | NC | 60 | 878.8602 | | | Message | New |
|
||||||
|
When I save the loans with chargebacks
|
||||||
|
And I get the list of all loans with the loan service
|
||||||
|
Then the loans in the loan table will look like
|
||||||
|
| LoanId | ImportId | Member Number | Loan Number | Loan Date | PostedDate | FirstPmtDate | FinalPmtDate | Loan Type Id | Term | Reserve Amount | Chargeback | Chargeback Message | Paid Loan Date | Reserve Message | Loan Status | Remaining Months at Close |
|
||||||
|
| 1 | 1 | 12 | 3 | 2/25/2021 | 2/28/2021 | 4/11/2021 | 6/11/2026 | NC | 63 | 210.0375 | | | | Standard | New | |
|
||||||
|
| 2 | 2 | 5841 | 147 | 2/10/2021 | 2/27/2021 | 3/12/2021 | 2/12/2028 | NC | 84 | 1206.8106 | 1206.8106 | Paid On or Before Chargeback Date | 2/19/2021 | Message | Closed | 84 |
|
||||||
|
| 3 | 2 | 10094 | 143 | 12/7/2020 | 12/15/2020 | 1/21/2021 | 12/21/2025 | NC | 60 | 878.8602 | 878.8602 | Paid On or Before Chargeback Date | 12/22/2020 | Message | Closed | 60 |
|
||||||
|
|
||||||
|
|
||||||
+436
@@ -0,0 +1,436 @@
|
|||||||
|
using FluentAssertions;
|
||||||
|
using FluentValidation;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Moq;
|
||||||
|
using ReserveManagementSystemApi.Models;
|
||||||
|
using ReserveManagementSystemApi.ServiceClients;
|
||||||
|
using ReserveManagementSystemApi.Services;
|
||||||
|
using ReserveManagementSystemLib.Models;
|
||||||
|
using ReserveManagementSystemLib.Persistence;
|
||||||
|
using ReserveManagementSystemLib.Repositories;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using TechTalk.SpecFlow;
|
||||||
|
using TechTalk.SpecFlow.Assist;
|
||||||
|
using TechTalk.SpecFlow.Assist.ValueRetrievers;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi.Tests.ServiceTests
|
||||||
|
{
|
||||||
|
[Binding]
|
||||||
|
public sealed class LoanServiceSteps
|
||||||
|
{
|
||||||
|
// For additional details on SpecFlow step definitions see https://go.specflow.org/doc-stepdef
|
||||||
|
|
||||||
|
private readonly ScenarioContext _scenarioContext;
|
||||||
|
private LoanService _loanService;
|
||||||
|
private AppDbContext _appDbContext;
|
||||||
|
private IEnumerable<Loan> _loansResult;
|
||||||
|
private List<Loan> _loansToSave;
|
||||||
|
private Loan _loanResult;
|
||||||
|
private Exception _exception;
|
||||||
|
private LoanFilter _loanFilter;
|
||||||
|
private List<string> _memberResult;
|
||||||
|
private List<string> _loanNumberResult;
|
||||||
|
private List<string> _applicationIdResult;
|
||||||
|
PaginatedListResponse _pagedListResponse = new PaginatedListResponse();
|
||||||
|
private IEnumerable<Loan> _closedLoans;
|
||||||
|
private IEnumerable<Loan> _loansInSystem;
|
||||||
|
private IEnumerable<Loan> _loansNotInSystem;
|
||||||
|
private Mock<ILoanRepository> _mockLoanRepo = new Mock<ILoanRepository>();
|
||||||
|
private Mock<IAuditHistoryRepository> _mockAuditHistRepo = new Mock<IAuditHistoryRepository>();
|
||||||
|
|
||||||
|
public LoanServiceSteps(ScenarioContext scenarioContext)
|
||||||
|
{
|
||||||
|
_scenarioContext = scenarioContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BeforeScenario]
|
||||||
|
public void CreateDatabase()
|
||||||
|
{
|
||||||
|
var options = new DbContextOptionsBuilder<AppDbContext>()
|
||||||
|
.UseInMemoryDatabase(Guid.NewGuid().ToString())
|
||||||
|
.Options;
|
||||||
|
_appDbContext = new AppDbContext(options);
|
||||||
|
_loanService = new LoanService(new LoanRepository(_appDbContext), new LoanTypeRepository(_appDbContext), new AuditHistoryService(_mockAuditHistRepo.Object), new Mock<ICoreApiServiceClient>().Object);
|
||||||
|
}
|
||||||
|
|
||||||
|
[AfterScenario]
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_appDbContext.Database.EnsureDeleted();
|
||||||
|
_appDbContext.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Given(@"the Loan table has the following loans")]
|
||||||
|
public void GivenTheLoanTableHasTheFollowingLoans(Table table)
|
||||||
|
{
|
||||||
|
var loans = table.CreateSet<Loan>();
|
||||||
|
|
||||||
|
_appDbContext.Loans.AddRange(loans);
|
||||||
|
_appDbContext.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Given(@"I have these loans to save")]
|
||||||
|
public void GivenIHaveThisLoanToSave(Table table)
|
||||||
|
{
|
||||||
|
_loansToSave = table.CreateSet<Loan>().ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Given(@"a loan filter that looks like")]
|
||||||
|
public void GivenALoanFilterThatLooksLike(Table table)
|
||||||
|
{
|
||||||
|
_loanFilter = table.CreateInstance<LoanFilter>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the first loan from the loan service has ImportId (.*)")]
|
||||||
|
public void ThenTheFirstLoanFromTheLoanServiceHasImportId(int importId)
|
||||||
|
{
|
||||||
|
Assert.Equal(importId, _loansResult.First().ImportId);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Given(@"the Loan Repository throws an exception in ListAll")]
|
||||||
|
public void GivenTheLoanRepositoryThrowsAnExceptionInListAll()
|
||||||
|
{
|
||||||
|
_mockLoanRepo.Setup(a => a.GetAll()).Throws(new Exception());
|
||||||
|
_loanService = new LoanService(_mockLoanRepo.Object, new LoanTypeRepository(_appDbContext), new AuditHistoryService(_mockAuditHistRepo.Object), new Mock<ICoreApiServiceClient>().Object);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Given(@"the Loan Repository throws an exception in FindByIdAsync")]
|
||||||
|
public void GivenTheLoanRepositoryThrowsAnExceptionInFindByIdAsync()
|
||||||
|
{
|
||||||
|
_mockLoanRepo.Setup(a => a.FindByIdAsync(It.IsAny<int>())).Throws(new Exception());
|
||||||
|
_loanService = new LoanService(_mockLoanRepo.Object, new LoanTypeRepository(_appDbContext), new AuditHistoryService(_mockAuditHistRepo.Object), new Mock<ICoreApiServiceClient>().Object);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Given(@"the Loan Repository throws an exception in UpdateAsync")]
|
||||||
|
public void GivenTheLoanRepositoryThrowsAnExceptionInAdd()
|
||||||
|
{
|
||||||
|
_mockLoanRepo.Setup(a => a.UpdateAsync(It.IsAny<List<Loan>>())).Throws(new Exception());
|
||||||
|
_loanService = new LoanService(_mockLoanRepo.Object, new LoanTypeRepository(_appDbContext), new AuditHistoryService(_mockAuditHistRepo.Object), new Mock<ICoreApiServiceClient>().Object);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Given(@"loan types that look like")]
|
||||||
|
public void GivenLoanTypesThatLookLike(Table table)
|
||||||
|
{
|
||||||
|
var loanTypes = table.CreateSet<LoanType>().ToList();
|
||||||
|
_appDbContext.LoanTypes.AddRange(loanTypes);
|
||||||
|
_appDbContext.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Given(@"I have these loans to save with chargebacks")]
|
||||||
|
public void GivenIHaveTheseLoansToSaveWithChargebacks(Table table)
|
||||||
|
{
|
||||||
|
_closedLoans = table.CreateSet<Loan>().ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Given(@"the dealer table has these dealers")]
|
||||||
|
public void GivenTheDealerTableHasTheseDealers(Table table)
|
||||||
|
{
|
||||||
|
var dealers = table.CreateSet<Dealer>().ToList();
|
||||||
|
_appDbContext.Dealers.AddRange(dealers);
|
||||||
|
_appDbContext.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
[When(@"I save the loans with chargebacks")]
|
||||||
|
public async void WhenISaveTheLoansWithChargebacks()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = await _loanService.SaveWithChargebackAsync(_closedLoans.ToList());
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_exception = ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[When(@"I get the list of all loans with the loan service")]
|
||||||
|
public async void WhenIGetTheListOfAllLoansWithTheLoanService()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_loansResult = await _loanService.GetAllAsync();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_exception = ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[When(@"I get the list of all loans with the loan service with the mock loan repo")]
|
||||||
|
public async void WhenIGetTheListOfAllLoansWithTheLoanServiceWithTheMockLoanRepo()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_loansResult = await _loanService.GetAllAsync();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_exception = ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[When(@"I get the list of the filtered loans with the loan service")]
|
||||||
|
public async void WhenIGetTheListOfTheFilteredLoansWithTheLoanService()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_pagedListResponse = await _loanService.GetFilteredAsync(_loanFilter);
|
||||||
|
_loansResult = _pagedListResponse.LoanList;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_exception = ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[When(@"I get the list of paged loans")]
|
||||||
|
public async void WhenIGetTheListOfPagedLoans()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_pagedListResponse = await _loanService.GetFilteredAsync(_loanFilter);
|
||||||
|
_loansResult = _pagedListResponse.LoanList;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_exception = ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the result from the loan service should have (.*) pages")]
|
||||||
|
public void ThenTheResultFromTheLoanServiceShouldHavePages(int pageCount)
|
||||||
|
{
|
||||||
|
Assert.Equal(pageCount, _pagedListResponse.TotalPages);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the result from the loan service should have (.*) records")]
|
||||||
|
public void ThenTheResultFromTheLoanServiceShouldHaveRecords(int recordCount)
|
||||||
|
{
|
||||||
|
Assert.Equal(recordCount, _pagedListResponse.LoanList.Count());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the result from the loan service should have (.*) total items")]
|
||||||
|
public void ThenTheResultFromTheLoanServiceShouldHaveTotalItems(int recordCount)
|
||||||
|
{
|
||||||
|
Assert.Equal(recordCount, _pagedListResponse.TotalItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the first result from the loan service should have loanid (.*)")]
|
||||||
|
public void ThenTheFirstResultFromTheLoanServiceShouldHaveLoanId(int loanId)
|
||||||
|
{
|
||||||
|
Assert.Equal(loanId, _pagedListResponse.LoanList.First().LoanId);
|
||||||
|
}
|
||||||
|
|
||||||
|
//have to rethink this if we get rid of the other one
|
||||||
|
[When(@"I save the loan with the reserve")]
|
||||||
|
public async void WhenISaveTheLoan()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await _loanService.SaveLoansAsync(_loansToSave);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_exception = ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[When(@"I save the loan with the reserve with the mock loan repo")]
|
||||||
|
public async void WhenISaveTheLoanWithTheReserveWithTheMockLoanRepo()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await _loanService.SaveLoansAsync(_loansToSave);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_exception = ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the result from the loan service has previous page should be (.*)")]
|
||||||
|
public void ThenTheResultFromTheLoanServiceHasPreviousPageShouldBe(bool hasPreviousPage)
|
||||||
|
{
|
||||||
|
Assert.Equal(hasPreviousPage, _pagedListResponse.HasPreviousPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the result from the loan service has next page should be (.*)")]
|
||||||
|
public void ThenTheResultFromTheLoanServiceHasNextPageShouldBe(bool hasNextPage)
|
||||||
|
{
|
||||||
|
Assert.Equal(hasNextPage, _pagedListResponse.HasNextPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then (@"the result from the loan service first page should be (.*)")]
|
||||||
|
public void ThenTheResultFromTheLoanServiceFirstPageShouldBe(int firstPage)
|
||||||
|
{
|
||||||
|
Assert.Equal(firstPage, _pagedListResponse.FirstPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the result from the loan service last page should be (.*)")]
|
||||||
|
public void ThenTheResultFromTheLoanServiceLastPageShouldBe(int lastPage)
|
||||||
|
{
|
||||||
|
Assert.Equal(lastPage, _pagedListResponse.LastPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
[When(@"I get the loan with the loanId (.*) from the loan service")]
|
||||||
|
public async void WhenIGetTheLoanWithTheLoanIdFromTheLoanService(int loanId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_loanResult = await _loanService.GetByIdAsync(loanId);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_exception = ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[When(@"I get the loan with the loanId (.*) from the loan service using the Mock Loan Repo")]
|
||||||
|
public async void WhenIGetTheLoanWithTheLoanIdFromTheLoanServiceUsingTheMockLoanRepo(int loanId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_loanResult = await _loanService.GetByIdAsync(loanId);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_exception = ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[When(@"I get the list of members with search string ""(.*)""")]
|
||||||
|
public async void WhenIGetTheListOfMembersWithSearchString(string searchString)
|
||||||
|
{
|
||||||
|
_memberResult = await _loanService.SearchMembers(searchString);
|
||||||
|
}
|
||||||
|
|
||||||
|
[When(@"I get the list of loan numbers with search string ""(.*)""")]
|
||||||
|
public async void WhenIGetTheListOfLoanNumbersWithSearchString(string searchString)
|
||||||
|
{
|
||||||
|
_loanNumberResult = await _loanService.SearchLoanNumbers(searchString);
|
||||||
|
}
|
||||||
|
|
||||||
|
[When(@"I get the list of application ids with search string ""(.*)""")]
|
||||||
|
public async void WhenIGetTheListOfApplicationIdsWithSearchString(string searchString)
|
||||||
|
{
|
||||||
|
_applicationIdResult = await _loanService.SearchApplicationIds(searchString);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Then(@"the result from the loan service should have (.*) loans")]
|
||||||
|
public void ThenTheResultFromTheLoanServiceShouldHaveLoans(int loanCount)
|
||||||
|
{
|
||||||
|
Assert.Equal(loanCount, _loansResult.Count());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the list of members returned is in this order")]
|
||||||
|
public void ThenTheListOfMembersReturnedIsInThisOrder(Table table)
|
||||||
|
{
|
||||||
|
var expectedMemberNumbers = table.Rows.Select(x => x[0]).ToList();
|
||||||
|
_memberResult.Should().BeEquivalentTo(expectedMemberNumbers).And.ContainInOrder(expectedMemberNumbers);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the list of loan numbers looks like")]
|
||||||
|
public void ThenTheListOfLoanNumbersLooksLike(Table table)
|
||||||
|
{
|
||||||
|
var expectedLoanNumbers = table.Rows.Select(x => x[0]).ToList();
|
||||||
|
_loanNumberResult.Should().BeEquivalentTo(expectedLoanNumbers).And.ContainInOrder(expectedLoanNumbers);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the list of application ids looks like")]
|
||||||
|
public void ThenTheListOfApplicationIdsLooksLike(Table table)
|
||||||
|
{
|
||||||
|
var expectedApplicationIds = table.Rows.Select(x => x[0]).ToList();
|
||||||
|
_applicationIdResult.Should().BeEquivalentTo(expectedApplicationIds).And.ContainInOrder(expectedApplicationIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Then(@"the loans from the loan service look like")]
|
||||||
|
public async void ThenTheLoanFromTheLoanServiceLooksLike(Table table)
|
||||||
|
{
|
||||||
|
var actualLoans = (await _loanService.GetAllAsync()).ToList();
|
||||||
|
table.CompareToSet(actualLoans);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the first loan from the loan service has LoanId (.*)")]
|
||||||
|
public void ThenTheFirstLoanFromTheLoanServiceHasLoanId(int loanId)
|
||||||
|
{
|
||||||
|
Assert.Equal(loanId, _loansResult.First().LoanId);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the loan ids from the loan service look like")]
|
||||||
|
public void ThenTheLoanIdsFromTheLoanServiceLookLike(Table table)
|
||||||
|
{
|
||||||
|
var expectedLoanIds = table.CreateSet<int>().ToList();
|
||||||
|
_loansResult.Select(x => x.LoanId).Should().BeEquivalentTo(expectedLoanIds).And.ContainInOrder(expectedLoanIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the loan ids from the loan service look like ""(.*)""")]
|
||||||
|
public void ThenTheLoanIdsFromTheLoanServiceLookLike(string listOfIds)
|
||||||
|
{
|
||||||
|
var expected = listOfIds.Split(',').Select(x => int.Parse(x)).ToList();
|
||||||
|
_loansResult.Select(x => x.LoanId).Should().BeEquivalentTo(expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Then(@"the loan with LoanId (.*) has dealer name ""(.*)""")]
|
||||||
|
public void ThenTheLoanWithLoanIdHasDealerName(int loanId, string dealerName)
|
||||||
|
{
|
||||||
|
Assert.Equal(dealerName, _loansResult.First(x => x.LoanId == loanId).Dealer.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the Loan Service throws an exception with the message ""(.*)""")]
|
||||||
|
public void ThenTheLoanServiceThrowsAnExceptionWithTheMessage(string message)
|
||||||
|
{
|
||||||
|
Assert.NotNull(_exception);
|
||||||
|
Assert.Equal(message, _exception.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the loan from the loan service has LoanId (.*)")]
|
||||||
|
public void ThenTheLoanFromTheLoanServiceHasLoanId(int loanId)
|
||||||
|
{
|
||||||
|
Assert.Equal(loanId, _loanResult.LoanId);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the loan from the loan service has dealer name ""(.*)""")]
|
||||||
|
public void ThenTheLoanFromTheLoanServiceHasDealerName(string dealerName)
|
||||||
|
{
|
||||||
|
Assert.Equal(dealerName, _loanResult.Dealer.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the flat fee result for MemberNumber (.*) should be (.*)")]
|
||||||
|
public void ThenTheReserveAmountResultShouldBe(string member, bool feePaid)
|
||||||
|
{
|
||||||
|
Assert.Equal(feePaid, _loansResult.FirstOrDefault(x => x.MemberNumber == member).FlatFeePaid);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the loan from the loan service has LoanType.LoanComment ""(.*)""")]
|
||||||
|
public void ThenTheLoanFromTheLoanServiceHasLoanTypeDescription(string description)
|
||||||
|
{
|
||||||
|
Assert.Equal(description, _loanResult.LoanType?.LoanComment ?? string.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the loans in the system look like")]
|
||||||
|
public void ThenTheLoansInTheSystemLookLike(Table table)
|
||||||
|
{
|
||||||
|
table.CompareToSet(_loansInSystem);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the loans not in the system look like")]
|
||||||
|
public void ThenTheLoansNotInTheSystemLookLike(Table table)
|
||||||
|
{
|
||||||
|
table.CompareToSet(_loansNotInSystem);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Then(@"the loans in the loan table will look like")]
|
||||||
|
public void ThenTheLoansInTheLoanTableWillLookLike(Table table)
|
||||||
|
{
|
||||||
|
table.CompareToSet(_loansResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+230
@@ -0,0 +1,230 @@
|
|||||||
|
Feature: Reserve Calculation
|
||||||
|
Calculates reserve amount for a loan
|
||||||
|
|
||||||
|
Scenario: Calculate Reserve with Standard Markup
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Amount | Buy Rate | Contract Rate | Loan Type | Term |
|
||||||
|
| 5/28/2015 | 6/27/2015 | 5/27/2017 | 6200.20 | 1.48 | 3.89 | NC | 24 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the reserve is calculated
|
||||||
|
Then the reserve amount should be 118.73687752592344707611833965
|
||||||
|
And the reserve message should be Standard Reserve
|
||||||
|
And FlatFeePaid should be "false"
|
||||||
|
|
||||||
|
Scenario: Calculate Boat Reserve with Standard Markup
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Amount | Buy Rate | Contract Rate | Loan Type | Term | AccountType |
|
||||||
|
| 5/28/2015 | 6/27/2015 | 5/27/2017 | 6200.20 | 1.50 | 3.00 | NC | 24 | DL09 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the reserve is calculated
|
||||||
|
Then the reserve amount should be 310.01
|
||||||
|
And the reserve message should be Standard Reserve
|
||||||
|
And FlatFeePaid should be "false"
|
||||||
|
|
||||||
|
Scenario: Calculate Reserve with Standard Markup and Days to First Payment is less than 30
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Amount | Buy Rate | Contract Rate | Loan Type | Term |
|
||||||
|
| 2/27/2021 | 3/27/2021 | 2/27/2028 | 55799.16 | 4.59 | 6.34 | NC | 84 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the reserve is calculated
|
||||||
|
Then the reserve amount should be 2917.8694562514364202612072482
|
||||||
|
And the reserve message should be Standard Reserve
|
||||||
|
And FlatFeePaid should be "false"
|
||||||
|
|
||||||
|
Scenario: Calculate Reserve with Standard Markup - first pay date is less than 30 days from loan date (this calculation might be wrong)
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Amount | Buy Rate | Contract Rate | Loan Type | Term |
|
||||||
|
| 4/23/2021 | 5/21/2021 | 4/21/2026 | 6474.80 | 3.24 | 5.24 | NC | 60 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the reserve is calculated
|
||||||
|
Then the reserve amount should be 263.93215613213476391531161260
|
||||||
|
And the reserve message should be Standard Reserve
|
||||||
|
And FlatFeePaid should be "false"
|
||||||
|
|
||||||
|
Scenario: Calculate Reserve with Standard Markup - loan type id is missing, but will calculate the same as NC
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Amount | Buy Rate | Contract Rate | Loan Type Id | Term |
|
||||||
|
| 5/28/2015 | 6/27/2015 | 5/27/2017 | 6200.20 | 1.48 | 3.89 | | 24 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the reserve is calculated
|
||||||
|
Then the reserve amount should be 118.73687752592344707611833965
|
||||||
|
And the reserve message should be Standard Reserve
|
||||||
|
And FlatFeePaid should be "false"
|
||||||
|
|
||||||
|
Scenario: Calculate Reserve with Standard Markup - BB
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Amount | Buy Rate | Contract Rate | Loan Type Id | Term |
|
||||||
|
| 5/28/2015 | 6/27/2015 | 5/27/2017 | 6200.20 | 1.48 | 3.89 | BB | 24 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| BB | Standard | S | 0 | 0 | 0 | 1.00 | 0.25 |
|
||||||
|
When the reserve is calculated
|
||||||
|
Then the reserve amount should be 158.3158367012312627681577862
|
||||||
|
And the reserve message should be Standard Reserve
|
||||||
|
And FlatFeePaid should be "false"
|
||||||
|
|
||||||
|
Scenario: Calculate Reserve with Standard Markup - NR
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Amount | Buy Rate | Contract Rate | Loan Type Id | Term |
|
||||||
|
| 5/28/2015 | 6/27/2015 | 5/27/2017 | 6200.20 | 3.89 | 3.89 | NR | 24 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NR | No reserve to be paid | N | 0 | 0 | 0 | 0.00 | 0.25 |
|
||||||
|
When the reserve is calculated
|
||||||
|
Then the reserve amount should be 0
|
||||||
|
And the reserve message should be No Reserve
|
||||||
|
And FlatFeePaid should be "false"
|
||||||
|
|
||||||
|
Scenario: Calculate Reserve with Standard Markup Flat Fee Applied
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Amount | Buy Rate | Contract Rate | Loan Type | Term |
|
||||||
|
| 2/18/2021 | 4/4/2021 | 3/1/2024 | 12000.95 | 2.89 | 3.49 | NC | 36 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the reserve is calculated
|
||||||
|
Then the reserve amount should be 90.007125
|
||||||
|
And the reserve message should be Flat Fee Reserve
|
||||||
|
And FlatFeePaid should be "true"
|
||||||
|
|
||||||
|
Scenario: Calculate Reserve with No Markup Flat Fee Applied
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Amount | Buy Rate | Contract Rate | Loan Type | Term |
|
||||||
|
| 7/10/2019 | 8/24/2019 | 7/24/2024 | 20500 | 3.49 | 3.49 | NC | 60 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the reserve is calculated
|
||||||
|
Then the reserve amount should be 153.75
|
||||||
|
Then the reserve message should be Flat Fee Reserve
|
||||||
|
And FlatFeePaid should be "true"
|
||||||
|
|
||||||
|
Scenario: Calculate Boat Reserve with No Markup Standard Reserve Applied @ 1% Reserve
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Amount | Buy Rate | Contract Rate | Loan Type | Term | AccountType |
|
||||||
|
| 7/10/2019 | 8/24/2019 | 7/24/2024 | 20500 | 3.49 | 3.49 | NC | 60 | DL12 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the reserve is calculated
|
||||||
|
Then the reserve amount should be 205
|
||||||
|
Then the reserve message should be Standard Reserve
|
||||||
|
And FlatFeePaid should be "false"
|
||||||
|
|
||||||
|
Scenario: Calculate Boat Reserve with Non Standard Markup
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Amount | Buy Rate | Contract Rate | Loan Type | Term | AccountType |
|
||||||
|
| 1/2/2021 | 2/16/2021 | 1/26/2026 | 28423.05 | 1.83 | 11.73 | NC | 60 | DL10 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the reserve is calculated
|
||||||
|
Then the reserve amount should be 1705.383
|
||||||
|
Then the reserve message should be Standard Reserve - Exceeds Max Markup
|
||||||
|
And FlatFeePaid should be "false"
|
||||||
|
|
||||||
|
Scenario: Calculate Reserve with Non Standard Markup
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Amount | Buy Rate | Contract Rate | Loan Type | Term |
|
||||||
|
| 1/2/2021 | 2/16/2021 | 1/26/2026 | 28423.05 | 1.83 | 11.73 | NC | 60 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the reserve is calculated
|
||||||
|
Then the reserve amount should be 6104.6234279062733014747185835
|
||||||
|
Then the reserve message should be Standard Reserve - Exceeds Max Markup
|
||||||
|
And FlatFeePaid should be "false"
|
||||||
|
|
||||||
|
Scenario: Calculate Buydown Reserve
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Amount | Buy Rate | Contract Rate | Loan Type | Term |
|
||||||
|
| 4/19/2018 | 5/19/2018 | 4/19/2024 | 27042.25 | 4.6 | 1.9 | NC | 72 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the reserve is calculated
|
||||||
|
Then the reserve amount should be -2362.679817869475221821891298
|
||||||
|
Then the reserve message should be Buy Down Reserve
|
||||||
|
And FlatFeePaid should be "false"
|
||||||
|
|
||||||
|
Scenario: Calculate Boat Buydown Reserve
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Amount | Buy Rate | Contract Rate | Loan Type | Term | AccountType |
|
||||||
|
| 4/19/2018 | 5/19/2018 | 4/19/2024 | 27042.25 | 4.6 | 1.9 | NC | 72 | DL11 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the reserve is calculated
|
||||||
|
Then the reserve amount should be -2362.679817869475221821891298
|
||||||
|
Then the reserve message should be Buy Down Reserve
|
||||||
|
And FlatFeePaid should be "false"
|
||||||
|
|
||||||
|
Scenario: Calculate Buydown Reserve - 0.5 difference
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Amount | Buy Rate | Contract Rate | Loan Type | Term |
|
||||||
|
| 5/15/2019 | 7/1/2019 | 6/1/2022 | 6261 | 5.27 | 4.77 | NC | 36 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the reserve is calculated
|
||||||
|
Then the reserve amount should be -52.284980016715778985051587237
|
||||||
|
Then the reserve message should be Buy Down Reserve
|
||||||
|
And FlatFeePaid should be "false"
|
||||||
|
|
||||||
|
Scenario: Calculate Boat Buydown Reserve - 0.05 difference (reserve should be 0)
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Amount | Buy Rate | Contract Rate | Loan Type | Term | AccountType |
|
||||||
|
| 8/4/2017 | 9/3/2017 | 8/3/2022 | 15721.42 | 9.95 | 9.9 | NC | 60 | DL09 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the reserve is calculated
|
||||||
|
Then the reserve amount should be 0
|
||||||
|
Then the reserve message should be No Reserve
|
||||||
|
And FlatFeePaid should be "false"
|
||||||
|
|
||||||
|
Scenario: Calculate Buydown Reserve - 0.05 difference (reserve should be 0)
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Amount | Buy Rate | Contract Rate | Loan Type | Term |
|
||||||
|
| 8/4/2017 | 9/3/2017 | 8/3/2022 | 15721.42 | 9.95 | 9.9 | NC | 60 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the reserve is calculated
|
||||||
|
Then the reserve amount should be 0
|
||||||
|
Then the reserve message should be No Reserve
|
||||||
|
And FlatFeePaid should be "false"
|
||||||
|
|
||||||
|
Scenario: Calculate Buydown Reserve - 0.25 difference (reserve should be 0)
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | Loan Amount | Buy Rate | Contract Rate | Loan Type | Term |
|
||||||
|
| 8/4/2017 | 9/3/2017 | 8/3/2022 | 15721.42 | 8.25 | 8 | NC | 60 |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the reserve is calculated
|
||||||
|
Then the reserve amount should be 0
|
||||||
|
Then the reserve message should be No Reserve
|
||||||
|
And FlatFeePaid should be "false"
|
||||||
|
|
||||||
|
Scenario: Calculate Reserve when there are weird payment dates
|
||||||
|
Given a loan that looks like
|
||||||
|
| Loan Date | First Pmt Date | Final Pmt Date | PostedDate | Loan Amount | Buy Rate | Contract Rate | Loan Type |
|
||||||
|
| 6/14/2021 | 7/24/2021 | 6/30/2021 | 6/18/2021 | 20500 | 3.49 | 3.49 | NC |
|
||||||
|
And a loan type table that looks like
|
||||||
|
| LoanTypeId | LoanComment | ChargebackMethod | NoChargebackDays | NoChargebackPayments | ReserveDiscount | FlatFeePercent | NoReserveThreshold |
|
||||||
|
| NC | 75% Reserve | N | 90 | 3 | 25.00 | 1.00 | 0.25 |
|
||||||
|
When the reserve is calculated
|
||||||
|
Then the reserve amount should be 0
|
||||||
|
Then the reserve message should be Exception while calculating reserve
|
||||||
|
And FlatFeePaid should be "false"
|
||||||
+129
@@ -0,0 +1,129 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<SpecFlowObsoleteCodeBehindFiles Remove="Features\ImportReadService Closed - Copy.feature.cs" />
|
||||||
|
<SpecFlowObsoleteCodeBehindFiles Remove="Features\ImportReadService New - Copy.feature.cs" />
|
||||||
|
<SpecFlowObsoleteCodeBehindFiles Remove="Features\LoanService - Copy.feature.cs" />
|
||||||
|
<SpecFlowObsoleteCodeBehindFiles Remove="Features\LoanService - Filtering and Pagination - Copy.feature.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Blazored.FluentValidation" Version="1.4.1" />
|
||||||
|
<PackageReference Include="FluentAssertions" Version="6.1.0" />
|
||||||
|
<PackageReference Include="LCU.Library.Internal.ApiSecurity" Version="1.0.2" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="3.1.18" />
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
||||||
|
<PackageReference Include="Moq" Version="4.16.1" />
|
||||||
|
<PackageReference Include="SpecFlow" Version="3.9.22" />
|
||||||
|
<PackageReference Include="SpecFlow.xUnit" Version="3.9.22" />
|
||||||
|
<PackageReference Include="xunit" Version="2.4.1" />
|
||||||
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="coverlet.collector" Version="3.1.0">
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
</PackageReference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\ReserveManagementSystemApi\ReserveManagementSystemApi.csproj" />
|
||||||
|
<ProjectReference Include="..\ReserveManagementSystemLib\ReserveManagementSystemLib.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Update="Features\ImportReadService Closed from DNA.feature.cs">
|
||||||
|
<DependentUpon>ImportReadService Closed from DNA.feature</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Update="Features\ImportReadService Closed.feature.cs">
|
||||||
|
<DependentUpon>ImportReadService Closed.feature</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Update="Features\ImportReadService New from DNA.feature.cs">
|
||||||
|
<DependentUpon>ImportReadService New from DNA.feature</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Update="Features\ImportReadService New.feature.cs">
|
||||||
|
<DependentUpon>ImportReadService New.feature</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Update="Features\ImportService.feature.cs">
|
||||||
|
<DependentUpon>ImportService.feature</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Update="Features\LoanService - Saving.feature.cs">
|
||||||
|
<DependentUpon>LoanService - Saving.feature</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Update="Features\LoanService - Filtering and Pagination.feature.cs">
|
||||||
|
<DependentUpon>LoanService - Filtering and Pagination.feature</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Update="Features\LoanService - Get All and Get By Id.feature.cs">
|
||||||
|
<DependentUpon>LoanService - Get All and Get By Id.feature</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Update="Features\ImportReadServiceSteps.cs">
|
||||||
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Update="Features\ImportServiceSteps.cs">
|
||||||
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Update="Features\LoanServiceSteps.cs">
|
||||||
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Update="Features\LoanCalculationServiceSteps.cs">
|
||||||
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Update="Features\ChargebackCalculation.feature.cs">
|
||||||
|
<DependentUpon>ChargebackCalculation.feature</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Update="Features\ReserveCalculation.feature.cs">
|
||||||
|
<DependentUpon>ReserveCalculation.feature</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="xunit.runner.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<SpecFlowFeatureFiles Update="Features\ImportReadService Closed from DNA.feature">
|
||||||
|
<Visible>$(UsingMicrosoftNETSdk)</Visible>
|
||||||
|
<CodeBehindFile>%(RelativeDir)%(Filename).feature$(DefaultLanguageSourceExtension)</CodeBehindFile>
|
||||||
|
</SpecFlowFeatureFiles>
|
||||||
|
<SpecFlowFeatureFiles Update="Features\ImportReadService Closed.feature">
|
||||||
|
<Visible>$(UsingMicrosoftNETSdk)</Visible>
|
||||||
|
<CodeBehindFile>%(RelativeDir)%(Filename).feature$(DefaultLanguageSourceExtension)</CodeBehindFile>
|
||||||
|
</SpecFlowFeatureFiles>
|
||||||
|
<SpecFlowFeatureFiles Update="Features\ImportReadService New from DNA.feature">
|
||||||
|
<Visible>$(UsingMicrosoftNETSdk)</Visible>
|
||||||
|
<CodeBehindFile>%(RelativeDir)%(Filename).feature$(DefaultLanguageSourceExtension)</CodeBehindFile>
|
||||||
|
</SpecFlowFeatureFiles>
|
||||||
|
<SpecFlowFeatureFiles Update="Features\ImportReadService New.feature">
|
||||||
|
<Visible>$(UsingMicrosoftNETSdk)</Visible>
|
||||||
|
<CodeBehindFile>%(RelativeDir)%(Filename).feature$(DefaultLanguageSourceExtension)</CodeBehindFile>
|
||||||
|
</SpecFlowFeatureFiles>
|
||||||
|
<SpecFlowFeatureFiles Update="Features\ImportService.feature">
|
||||||
|
<Visible>$(UsingMicrosoftNETSdk)</Visible>
|
||||||
|
<CodeBehindFile>%(RelativeDir)%(Filename).feature$(DefaultLanguageSourceExtension)</CodeBehindFile>
|
||||||
|
</SpecFlowFeatureFiles>
|
||||||
|
<SpecFlowFeatureFiles Update="Features\ChargebackCalculation.feature">
|
||||||
|
<Visible>$(UsingMicrosoftNETSdk)</Visible>
|
||||||
|
<CodeBehindFile>%(RelativeDir)%(Filename).feature$(DefaultLanguageSourceExtension)</CodeBehindFile>
|
||||||
|
</SpecFlowFeatureFiles>
|
||||||
|
<SpecFlowFeatureFiles Update="Features\LoanService - Saving.feature">
|
||||||
|
<Visible>$(UsingMicrosoftNETSdk)</Visible>
|
||||||
|
<CodeBehindFile>%(RelativeDir)%(Filename).feature$(DefaultLanguageSourceExtension)</CodeBehindFile>
|
||||||
|
</SpecFlowFeatureFiles>
|
||||||
|
<SpecFlowFeatureFiles Update="Features\LoanService - Filtering and Pagination.feature">
|
||||||
|
<Visible>$(UsingMicrosoftNETSdk)</Visible>
|
||||||
|
<CodeBehindFile>%(RelativeDir)%(Filename).feature$(DefaultLanguageSourceExtension)</CodeBehindFile>
|
||||||
|
</SpecFlowFeatureFiles>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"parallelizeTestCollections": false
|
||||||
|
}
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
namespace ReserveManagementSystemApi.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; }
|
||||||
|
}
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
namespace ReserveManagementSystemApi.Configurations
|
||||||
|
{
|
||||||
|
public class FeatureFlags
|
||||||
|
{
|
||||||
|
public bool RunRmsActiveLoanConsumer { get; set; }
|
||||||
|
public bool EnableImportExportActive { get; set; }
|
||||||
|
public bool EnableImportExportClosed { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
using LCU.Library.Internal.LcuMassTransitModels;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi.Configurations
|
||||||
|
{
|
||||||
|
public class ReceiveEndpointConfigurations
|
||||||
|
{
|
||||||
|
public ReceiveEndpointConfiguration RmsActiveLoanReceiveEndpoint { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
namespace ReserveManagementSystemApi.Configurations
|
||||||
|
{
|
||||||
|
public class SqlConnectionConfiguration
|
||||||
|
{
|
||||||
|
public string ConnectionString { get; set; }
|
||||||
|
public int MaxRetryCount { get; set; }
|
||||||
|
public TimeSpan MaxRetryDelay { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
+40
@@ -0,0 +1,40 @@
|
|||||||
|
using MassTransit;
|
||||||
|
using LCU.Api.Internal.MaidBotLib.Models;
|
||||||
|
using ReserveManagementSystemLib.Models;
|
||||||
|
using ReserveManagementSystemApi.Services;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi.Consumers;
|
||||||
|
|
||||||
|
public class RmsActiveImportConsumer : IConsumer<RmsActiveImportRequest>
|
||||||
|
{
|
||||||
|
private readonly IServiceScopeFactory _scopeFactory;
|
||||||
|
|
||||||
|
public RmsActiveImportConsumer(IServiceScopeFactory scopeFactory)
|
||||||
|
{
|
||||||
|
_scopeFactory = scopeFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Consume(ConsumeContext<RmsActiveImportRequest> context)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Log.Debug("Starting RmsActiveImportConsumer.");
|
||||||
|
using var scope = _scopeFactory.CreateScope();
|
||||||
|
await Task.Run(async () => await scope.ServiceProvider.GetRequiredService<IRmsActiveLoanService>().HandleRmsActiveImportRequest(context.Message));
|
||||||
|
Log.Debug("Ending RmsActiveImportConsumer.");
|
||||||
|
}
|
||||||
|
catch (ServiceException)
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
Log.ForContext(Enum.GetName(typeof(PropertyEnum), PropertyEnum.Group),
|
||||||
|
Enum.GetName(typeof(GroupEnum), GroupEnum.ITDevelopment))
|
||||||
|
.Fatal(exception, $"Unexpected RmsActiveImportConsumer Failure. " +
|
||||||
|
$"The RmsActiveImportRequest is placed on ReserveManagementSystemApi.ActiveImport_error.");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+34
@@ -0,0 +1,34 @@
|
|||||||
|
using ReserveManagementSystemApi.Services;
|
||||||
|
using ReserveManagementSystemLib.Models;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi.Controllers
|
||||||
|
{
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[ApiController]
|
||||||
|
public class AuditHistoryController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly IAuditHistoryService _auditHistoryService;
|
||||||
|
|
||||||
|
public AuditHistoryController(IAuditHistoryService auditHistoryService)
|
||||||
|
{
|
||||||
|
_auditHistoryService = auditHistoryService;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet(Name = "GetAllHistory")]
|
||||||
|
[ProducesResponseType(typeof(IEnumerable<AuditHistory>), 200)]
|
||||||
|
[ProducesResponseType(500)]
|
||||||
|
public async Task<IActionResult> Get()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = await _auditHistoryService.GetAllAsync();
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error(e, "Failure returning Audit Histories");
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+51
@@ -0,0 +1,51 @@
|
|||||||
|
using ReserveManagementSystemApi.Services;
|
||||||
|
using ReserveManagementSystemLib.Models;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi.Controllers
|
||||||
|
{
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[ApiController]
|
||||||
|
public class DealerController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly IDealerService _dealerService;
|
||||||
|
|
||||||
|
public DealerController(IDealerService dealerService)
|
||||||
|
{
|
||||||
|
_dealerService = dealerService;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("Search/{dealerSearchText}", Name = "Search")]
|
||||||
|
[ProducesResponseType(typeof(IEnumerable<Dealer>), 200)]
|
||||||
|
[ProducesResponseType(500)]
|
||||||
|
public async Task<IActionResult> Search(string dealerSearchText)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = await _dealerService.Search(dealerSearchText);
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error(e, "Failure returning dealers");
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("GetByDealerCode/{dealerCode}", Name = "GetDealerByCode")]
|
||||||
|
[ProducesResponseType(typeof(Dealer), 200)]
|
||||||
|
[ProducesResponseType(500)]
|
||||||
|
public async Task<IActionResult> GetByDealerCode(string dealerCode)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = await _dealerService.GetDealerByCodeAsync(dealerCode);
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error(e, "Failure returning dealer");
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+183
@@ -0,0 +1,183 @@
|
|||||||
|
using ReserveManagementSystemApi.Models;
|
||||||
|
using ReserveManagementSystemApi.Services;
|
||||||
|
using ReserveManagementSystemApi.Services.QueueServices;
|
||||||
|
using ReserveManagementSystemLib.Models;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi.Controllers
|
||||||
|
{
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[ApiController]
|
||||||
|
public class ImportController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly IImportReadService _importReadService;
|
||||||
|
private readonly IImportService _importService;
|
||||||
|
private readonly IQueueRmsActiveLoanService _queueRmsActiveLoanService;
|
||||||
|
|
||||||
|
public ImportController(IImportReadService importReadService, IImportService importService, IQueueRmsActiveLoanService queueRmsActiveLoanService)
|
||||||
|
{
|
||||||
|
_importReadService = importReadService;
|
||||||
|
_importService = importService;
|
||||||
|
_queueRmsActiveLoanService = queueRmsActiveLoanService;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet(Name = "GetAllImports")]
|
||||||
|
[ProducesResponseType(typeof(IEnumerable<Import>), 200)]
|
||||||
|
[ProducesResponseType(500)]
|
||||||
|
public async Task<IActionResult> Get()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = await _importService.GetAllAsync();
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error(e, "Failure returning Imports");
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("GetRecentImports/{numberOfImports}", Name = "GetRecentImports")]
|
||||||
|
[ProducesResponseType(typeof(IEnumerable<Import>), 200)]
|
||||||
|
[ProducesResponseType(500)]
|
||||||
|
public async Task<IActionResult> GetRecent(int numberOfImports)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = await _importService.GetRecentAsync(numberOfImports);
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error(e, "Failure returning Imports");
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("GetById/{importId}", Name = "GetImportById")]
|
||||||
|
[ProducesResponseType(typeof(Loan), 200)]
|
||||||
|
[ProducesResponseType(500)]
|
||||||
|
public async Task<IActionResult> GetById(int importId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = await _importService.GetByIdAsync(importId);
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error(e, $"Failure returning loan with id {importId}");
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("ImportNewLoanFile", Name ="ImportNewLoanFile")]
|
||||||
|
[ProducesResponseType(typeof(Import), 200)]
|
||||||
|
[ProducesResponseType(500)]
|
||||||
|
public async Task<IActionResult> ImportNewLoanFile(IFormFile file)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var stream = new StreamReader(file.OpenReadStream());
|
||||||
|
var import = await _importReadService.ReadNewLoanImportFile(stream, file.FileName, DateTime.Now);
|
||||||
|
return Ok(import);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error("Failure to import new loan file, message: {0} {1}", e.Message, e.StackTrace);
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("ImportBoatLoanFile", Name = "ImportBoatLoanFile")]
|
||||||
|
[ProducesResponseType(typeof(List<ImportBoatLoan>), 200)]
|
||||||
|
[ProducesResponseType(500)]
|
||||||
|
public async Task<IActionResult> ImportBoatLoanFile(IFormFile file)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var stream = new StreamReader(file.OpenReadStream());
|
||||||
|
var import = await _importReadService.ReadBoatLoanImportFile(stream);
|
||||||
|
return Ok(import);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error("Failure to import boat loan file, message: {0} {1}", e.Message, e.StackTrace);
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("ImportClosedLoanFile", Name = "ImportClosedLoanFile")]
|
||||||
|
[ProducesResponseType(typeof(Import), 200)]
|
||||||
|
[ProducesResponseType(500)]
|
||||||
|
public async Task<IActionResult> ImportClosedLoanFile(IFormFile file)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var stream = new StreamReader(file.OpenReadStream());
|
||||||
|
var import = await _importReadService.ReadClosedLoanImportFile(stream, file.FileName, DateTime.Now);
|
||||||
|
return Ok(import);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error("Failure to import closed loan file, message: {0} {1}", e.Message, e.StackTrace);
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPut("ImportActiveLoans", Name = "ImportActiveLoans")]
|
||||||
|
[ProducesResponseType(typeof(Import), 200)]
|
||||||
|
[ProducesResponseType(500)]
|
||||||
|
public async Task<IActionResult> ImportActiveLoans(string? newerThanDateTime = "", bool skipExport = false)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var request = new RmsActiveImportRequest()
|
||||||
|
{
|
||||||
|
ImportDateTime = newerThanDateTime,
|
||||||
|
SkipExport = skipExport
|
||||||
|
};
|
||||||
|
await _queueRmsActiveLoanService.QueueRmsActiveLoanServiceRequest(request);
|
||||||
|
return Accepted();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, $"Failure importing Active Loans");
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPut("ImportClosedLoans", Name = "ImportClosedLoans")]
|
||||||
|
[ProducesResponseType(typeof(Import), 200)]
|
||||||
|
[ProducesResponseType(500)]
|
||||||
|
public async Task<IActionResult> ImportClosedLoans(string? newerThanDateTime)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var import = await _importReadService.ImportClosedLoansFromDNA(newerThanDateTime);
|
||||||
|
return Ok(import);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, $"Failure importing Closed Loans");
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPut("ImportClosedLoansWithUpdates", Name = "ImportClosedLoansWithUpdates")]
|
||||||
|
[ProducesResponseType(typeof(Import), 200)]
|
||||||
|
[ProducesResponseType(500)]
|
||||||
|
public async Task<IActionResult> ImportClosedLoansWithUpdates(string? newerThanDateTime, bool skipExport = false)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var import = await _importReadService.ImportClosedLoansWithUpdatesFromDNA(newerThanDateTime, skipExport);
|
||||||
|
return Ok(import);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+146
@@ -0,0 +1,146 @@
|
|||||||
|
using ReserveManagementSystemApi.Services;
|
||||||
|
using ReserveManagementSystemLib.Models;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi.Controllers
|
||||||
|
{
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[ApiController]
|
||||||
|
public class LoanController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly ILoanService _loanService;
|
||||||
|
public LoanController(ILoanService loanService)
|
||||||
|
{
|
||||||
|
_loanService = loanService;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet(Name = "GetAllLoans")]
|
||||||
|
[ProducesResponseType(typeof(IEnumerable<Loan>), 200)]
|
||||||
|
[ProducesResponseType(500)]
|
||||||
|
public async Task<IActionResult> Get()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = await _loanService.GetAllAsync();
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error(e, "Failure returning Loans");
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("SearchLoans", Name = "SearchLoans")]
|
||||||
|
[ProducesResponseType(typeof(PaginatedListResponse), 200)]
|
||||||
|
[ProducesResponseType(500)]
|
||||||
|
public async Task<IActionResult> Post([FromBody]LoanFilter filter)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = await _loanService.GetFilteredAsync(filter);
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error(e, "Failure returning Filtered Loans");
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("SearchMembers/{searchText}", Name = "SearchMembers")]
|
||||||
|
[ProducesResponseType(typeof(string), 200)]
|
||||||
|
[ProducesResponseType(500)]
|
||||||
|
public async Task<IActionResult> SearchMembers(string searchText)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = await _loanService.SearchMembers(searchText);
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error(e, $"Failure returning members");
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("SearchLoanNumbers/{searchText}", Name = "SearchLoanNumbers")]
|
||||||
|
[ProducesResponseType(typeof(string), 200)]
|
||||||
|
[ProducesResponseType(500)]
|
||||||
|
public async Task<IActionResult> SearchLoanNumbers(string searchText)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = await _loanService.SearchLoanNumbers(searchText);
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error(e, $"Failure returning loan numbers");
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("SearchApplicationIds/{searchText}", Name = "SearchApplicationIds")]
|
||||||
|
[ProducesResponseType(typeof(string), 200)]
|
||||||
|
[ProducesResponseType(500)]
|
||||||
|
public async Task<IActionResult> SearchApplicationIds(string searchText)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = await _loanService.SearchApplicationIds(searchText);
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error(e, $"Failure returning application ids");
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("GetById/{loanId}", Name = "GetLoanById")]
|
||||||
|
[ProducesResponseType(typeof(Loan), 200)]
|
||||||
|
[ProducesResponseType(500)]
|
||||||
|
public async Task<IActionResult> GetById(int loanId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = await _loanService.GetByIdAsync(loanId);
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error(e, $"Failure returning loan with id {loanId}");
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("CalculateReserve", Name = "CalculateReserve")]
|
||||||
|
public async Task<LoanReserve> Post([FromBody] LoanReserveInput input)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await _loanService.GetLoanReserveAsync(input);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error("Failure to Calculate Loan Reserve: {0} {1}", e.Message, e.StackTrace);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("CalculateChargeback", Name = "CalculateChargeback")]
|
||||||
|
public async Task<LoanChargeback> Post([FromBody] LoanChargebackInput input)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await _loanService.GetLoanChargebackAsync(input);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error("Failure to Calculate Loan Chargeback: {0} {1}", e.Message, e.StackTrace);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+33
@@ -0,0 +1,33 @@
|
|||||||
|
using ReserveManagementSystemApi.Services;
|
||||||
|
namespace ReserveManagementSystemApi.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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
namespace ReserveManagementSystemApi.Enums
|
||||||
|
{
|
||||||
|
public enum ActivityType
|
||||||
|
{
|
||||||
|
Warning,
|
||||||
|
Error,
|
||||||
|
LoanStatusChange,
|
||||||
|
NewLoanUpdate
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
namespace ReserveManagementSystemApi.Enums
|
||||||
|
{
|
||||||
|
public enum LoanStatus
|
||||||
|
{
|
||||||
|
New,
|
||||||
|
Updated,
|
||||||
|
Closed,
|
||||||
|
MissingActiveLoan
|
||||||
|
}
|
||||||
|
}
|
||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
namespace ReserveManagementSystemApi.Helpers
|
||||||
|
{
|
||||||
|
public static class BatchHelper
|
||||||
|
{
|
||||||
|
public static IEnumerable<IEnumerable<TSource>> CreateBatch <TSource>(
|
||||||
|
List<TSource> source, int batchSize)
|
||||||
|
{
|
||||||
|
var items = new TSource[batchSize];
|
||||||
|
var count = 0;
|
||||||
|
foreach (var item in source)
|
||||||
|
{
|
||||||
|
items[count++] = item;
|
||||||
|
if (count == batchSize)
|
||||||
|
{
|
||||||
|
yield return items;
|
||||||
|
items = new TSource[batchSize];
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count > 0)
|
||||||
|
{
|
||||||
|
yield return items.Take(count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+56
@@ -0,0 +1,56 @@
|
|||||||
|
using ReserveManagementSystemLib.Models;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi.Helpers
|
||||||
|
{
|
||||||
|
public class BoatLoanCalculationHelper
|
||||||
|
{
|
||||||
|
private LoanReserve loanReserve = new LoanReserve();
|
||||||
|
|
||||||
|
public BoatLoanCalculationHelper()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public LoanReserve CalculateStandardMarkup(CalculationConfig cc)
|
||||||
|
{
|
||||||
|
var markup = cc.LoanData().ContractRate - cc.LoanData().BuyRate;
|
||||||
|
loanReserve.ReserveTypeMessage = "Standard Reserve";
|
||||||
|
switch (markup)
|
||||||
|
{
|
||||||
|
case decimal d when (d >= (decimal)0.00 && d <= (decimal)0.49):
|
||||||
|
loanReserve.ReserveAmount = cc.LoanData().LoanAmount * (decimal).01;
|
||||||
|
break;
|
||||||
|
case decimal d when (d >= (decimal)0.50 && d <= (decimal)0.74):
|
||||||
|
loanReserve.ReserveAmount = cc.LoanData().LoanAmount * (decimal).02;
|
||||||
|
break;
|
||||||
|
case decimal d when (d >= (decimal)0.75 && d <= (decimal)0.99):
|
||||||
|
loanReserve.ReserveAmount = cc.LoanData().LoanAmount * (decimal).03;
|
||||||
|
break;
|
||||||
|
case decimal d when (d >= (decimal)1.00 && d <= (decimal)1.49):
|
||||||
|
loanReserve.ReserveAmount = cc.LoanData().LoanAmount * (decimal).04;
|
||||||
|
break;
|
||||||
|
case decimal d when (d >= (decimal)1.50 && d <= (decimal)1.99):
|
||||||
|
loanReserve.ReserveAmount = cc.LoanData().LoanAmount * (decimal).05;
|
||||||
|
break;
|
||||||
|
case decimal d when (d == (decimal)2.00):
|
||||||
|
loanReserve.ReserveAmount = cc.LoanData().LoanAmount * (decimal).06;
|
||||||
|
break;
|
||||||
|
case decimal d when (d > (decimal)2.00):
|
||||||
|
loanReserve.ReserveAmount = cc.LoanData().LoanAmount * (decimal).06;
|
||||||
|
loanReserve.ReserveTypeMessage = "Standard Reserve - Exceeds Max Markup";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
loanReserve.ReserveAmount = 0;
|
||||||
|
loanReserve.ReserveTypeMessage = "No Reserve";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return loanReserve;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
internal DateTime GetLastChargebackDate (DateTime firstPmtDate, int numOfChargebackPayments)
|
||||||
|
{
|
||||||
|
return firstPmtDate.AddMonths(numOfChargebackPayments - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+210
@@ -0,0 +1,210 @@
|
|||||||
|
using LCU.Library.Internal.CoreApiWrapperModel.CoreModels.IndirectLoan;
|
||||||
|
using ReserveManagementSystemApi.Models;
|
||||||
|
using ReserveManagementSystemLib.Models;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi.Helpers
|
||||||
|
{
|
||||||
|
public class ImportHelper
|
||||||
|
{
|
||||||
|
private string _firstName;
|
||||||
|
private string _middleInitial;
|
||||||
|
private const double MonthInDays = 30.4375;
|
||||||
|
|
||||||
|
public ImportHelper()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Loan> TransformNewLoan(List<Models.ImportNewLoan> iImportLoans, int iImportId)
|
||||||
|
{
|
||||||
|
var result = new List<Loan>();
|
||||||
|
|
||||||
|
foreach (var iLoan in iImportLoans)
|
||||||
|
{
|
||||||
|
Loan loan = new Loan();
|
||||||
|
loan.ImportId = iImportId;
|
||||||
|
loan.MemberNumber = iLoan.MemberNumber;
|
||||||
|
loan.LoanNumber = iLoan.LoanNumber;
|
||||||
|
SplitFirstMiddleName(iLoan.FirstAndMiddleName);
|
||||||
|
loan.MemberFirstName = _firstName?.ToUpper();
|
||||||
|
loan.MemberInitial = _middleInitial?.ToUpper();
|
||||||
|
|
||||||
|
loan.MemberLastName = iLoan.LastName?.ToUpper();
|
||||||
|
loan.DealerOrganizationNumber = iLoan.DealerOrganizationNumber;
|
||||||
|
loan.LoanDate = iLoan.LoanDate;
|
||||||
|
loan.PostedDate = iLoan.PostedDate;
|
||||||
|
loan.FirstPmtDate = iLoan.FirstPmtDate;
|
||||||
|
loan.FinalPmtDate = iLoan.FinalPmtDate;
|
||||||
|
loan.LoanAmount = iLoan.LoanAmount;
|
||||||
|
loan.BuyRate = Math.Round(iLoan.BuyRate, 3, MidpointRounding.AwayFromZero);
|
||||||
|
loan.ContractRate = Math.Round(iLoan.ContractRate, 3, MidpointRounding.AwayFromZero);
|
||||||
|
loan.MonthlyPmt = iLoan.MonthlyPmt;
|
||||||
|
loan.LoanTypeId = iLoan.LoanType;
|
||||||
|
loan.ChargeBack = null;
|
||||||
|
loan.PaidLoanDate = null;
|
||||||
|
loan.ApplicationId = iLoan.ApplicationId;
|
||||||
|
loan.AccountType = iLoan.AccountType;
|
||||||
|
loan.Gap = !string.IsNullOrEmpty(iLoan.Gap) && Convert.ToBoolean(iLoan.Gap);
|
||||||
|
loan.Warranty = !string.IsNullOrEmpty(iLoan.Warranty) && Convert.ToBoolean(iLoan.Warranty);
|
||||||
|
loan.CreditLife = !string.IsNullOrEmpty(iLoan.CreditLife) && Convert.ToBoolean(iLoan.CreditLife);
|
||||||
|
loan.CreditDisability = !string.IsNullOrEmpty(iLoan.CreditDisability) && Convert.ToBoolean(iLoan.CreditDisability);
|
||||||
|
loan.Mbp = !string.IsNullOrEmpty(iLoan.Mbp) && Convert.ToBoolean(iLoan.Mbp);
|
||||||
|
loan.Term = (int)Math.Round(Convert.ToDecimal(iLoan.OriginalTermInDays) / (decimal)MonthInDays, 0);
|
||||||
|
|
||||||
|
Vehicle vehicle = new Vehicle();
|
||||||
|
vehicle.VINNumber = !string.IsNullOrEmpty(iLoan.VINNumber) ? iLoan.VINNumber : null;
|
||||||
|
vehicle.Make = iLoan.Make;
|
||||||
|
vehicle.Model = iLoan.Model;
|
||||||
|
vehicle.Year = iLoan.Year;
|
||||||
|
vehicle.Mileage = ValidateMileage(iLoan.Mileage);
|
||||||
|
vehicle.Color = iLoan.Color;
|
||||||
|
loan.Vehicle = vehicle;
|
||||||
|
result.Add(loan);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Loan> TransformLoanFromDNA(List<IndirectLoanDetail> importLoans, int iImportId)
|
||||||
|
{
|
||||||
|
var result = new List<Loan>();
|
||||||
|
if (!importLoans.Any())
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var iLoan in importLoans)
|
||||||
|
{
|
||||||
|
Loan loan = new Loan
|
||||||
|
{
|
||||||
|
ImportId = iImportId,
|
||||||
|
MemberNumber = iLoan.MemberNumber,
|
||||||
|
LoanNumber = iLoan.LoanNumber,
|
||||||
|
MemberFirstName = iLoan.MemberFirstName?.ToUpper(),
|
||||||
|
MemberInitial = iLoan.MemberInitial?.ToUpper(),
|
||||||
|
MemberLastName = iLoan.MemberLastName?.ToUpper(),
|
||||||
|
DealerOrganizationNumber = (!String.IsNullOrWhiteSpace(iLoan.DealerOrganizationNumber)) ? iLoan.DealerOrganizationNumber : string.Empty,
|
||||||
|
LoanDate = iLoan.LoanDate,
|
||||||
|
FirstPmtDate = iLoan.FirstPmtDate,
|
||||||
|
FinalPmtDate = iLoan.FinalPmtDate,
|
||||||
|
LoanAmount = iLoan.LoanAmount,
|
||||||
|
BuyRate = (iLoan.BuyRate != 0) ? Math.Round(iLoan.BuyRate, 3, MidpointRounding.AwayFromZero) : 0,
|
||||||
|
ContractRate = Math.Round(iLoan.ContractRate, 3, MidpointRounding.AwayFromZero),
|
||||||
|
MonthlyPmt = iLoan.MonthlyPmt,
|
||||||
|
LoanTypeId = iLoan.LoanType,
|
||||||
|
ApplicationId = iLoan.ApplicationId,
|
||||||
|
Gap = iLoan.GAP,
|
||||||
|
Warranty = iLoan.Warranty,
|
||||||
|
CreditLife = iLoan.CreditLife,
|
||||||
|
CreditDisability = iLoan.CreditDisability,
|
||||||
|
Mbp = iLoan.Mbp,
|
||||||
|
AccountType = iLoan.AccountType,
|
||||||
|
PaidLoanDate = iLoan.PaidLoanDate,
|
||||||
|
Term = (int)Math.Round(Convert.ToDecimal(iLoan.OriginalTermInDays) / (decimal)MonthInDays, 0)
|
||||||
|
};
|
||||||
|
|
||||||
|
if (iLoan.PostedDate == DateTime.MinValue)
|
||||||
|
{
|
||||||
|
loan.PostedDate = iLoan.LoanDate;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
loan.PostedDate = iLoan.PostedDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
loan.Vehicle = new Vehicle
|
||||||
|
{
|
||||||
|
VINNumber = !string.IsNullOrEmpty(iLoan.Vin) ? iLoan.Vin : null,
|
||||||
|
Make = iLoan.Make,
|
||||||
|
Model = iLoan.Model,
|
||||||
|
Year = iLoan.Year.ToString(),
|
||||||
|
Mileage = ValidateMileage(iLoan.Mileage.ToString()),
|
||||||
|
Color = iLoan.Color
|
||||||
|
};
|
||||||
|
|
||||||
|
loan.Dealer = new Dealer
|
||||||
|
{
|
||||||
|
DealerCode = (!String.IsNullOrWhiteSpace(iLoan.DealerCode)) && (iLoan.DealerCode.Length <= 4) ? iLoan.DealerCode : string.Empty,
|
||||||
|
Name = (!String.IsNullOrWhiteSpace(iLoan.DealerName)) ? iLoan.DealerName : string.Empty,
|
||||||
|
DealerAccountNumber = (!String.IsNullOrWhiteSpace(iLoan.DealerAccountNumber)) ? iLoan.DealerAccountNumber : string.Empty,
|
||||||
|
DealerOrganizationNumber = (!String.IsNullOrWhiteSpace(iLoan.DealerOrganizationNumber)) ? iLoan.DealerOrganizationNumber : string.Empty
|
||||||
|
};
|
||||||
|
|
||||||
|
result.Add(loan);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Loan> TransformBoatLoan(List<ImportBoatLoan> importLoans)
|
||||||
|
{
|
||||||
|
var result = new List<Loan>();
|
||||||
|
if (!importLoans.Any())
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var iLoan in importLoans)
|
||||||
|
{
|
||||||
|
Loan loan = new Loan
|
||||||
|
{
|
||||||
|
LoanNumber = iLoan.LoanNumber,
|
||||||
|
ReserveAmount = (!String.IsNullOrWhiteSpace(iLoan.IsChargeback) && iLoan.IsChargeback.ToUpper() == "FALSE") ? iLoan.Amount : 0,
|
||||||
|
ChargeBack = (!String.IsNullOrWhiteSpace(iLoan.IsChargeback) && iLoan.IsChargeback.ToUpper() == "TRUE") ? iLoan.Amount : 0,
|
||||||
|
Adjustment = (!String.IsNullOrWhiteSpace(iLoan.IsAdjustment) && iLoan.IsAdjustment.ToUpper() == "TRUE") ? iLoan.Amount : 0,
|
||||||
|
AccountType = iLoan.AccountType
|
||||||
|
};
|
||||||
|
|
||||||
|
loan.Dealer = new Dealer
|
||||||
|
{
|
||||||
|
DealerAccountNumber = iLoan.DealerAccountNumber
|
||||||
|
};
|
||||||
|
|
||||||
|
result.Add(loan);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double ValidateMileage(string mileage)
|
||||||
|
{
|
||||||
|
double convertedMileage;
|
||||||
|
if (double.TryParse(mileage, out convertedMileage))
|
||||||
|
{
|
||||||
|
return convertedMileage;
|
||||||
|
}
|
||||||
|
return convertedMileage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<Loan> TransformClosedLoans(List<ClosedIndirectLoan> importLoans, int importId)
|
||||||
|
{
|
||||||
|
return importLoans.Select(x => new Loan
|
||||||
|
{
|
||||||
|
ImportId = importId,
|
||||||
|
LoanNumber = x.LoanNumber,
|
||||||
|
PaidLoanDate = x.PaidLoanDate
|
||||||
|
//will update LoanStatus when saving
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SplitFirstMiddleName(string name)
|
||||||
|
{
|
||||||
|
//initial first name last name rules with first name character max length set in DB as 20, and middle initial max as 1
|
||||||
|
|
||||||
|
_middleInitial = String.Empty;
|
||||||
|
_firstName = name;
|
||||||
|
|
||||||
|
string[] names = name.Trim().Split(" ");
|
||||||
|
if (names != null && names.Length > 1) //when true there is a middle initial
|
||||||
|
{
|
||||||
|
_firstName = _firstName.Substring(0, name.Length - names.Last().Length).Trim();
|
||||||
|
_middleInitial = names.Last().Substring(0, 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_firstName = name; //no middle initial
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+120
@@ -0,0 +1,120 @@
|
|||||||
|
using ReserveManagementSystemLib.Models;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi.Helpers
|
||||||
|
{
|
||||||
|
public class LoanCalculationHelper
|
||||||
|
{
|
||||||
|
private decimal _daysInterest;
|
||||||
|
private LoanReserve loanReserve = new LoanReserve();
|
||||||
|
|
||||||
|
public LoanCalculationHelper()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
public LoanReserve CalculateBuyDown(CalculationConfig cc)
|
||||||
|
{
|
||||||
|
// Case - Buy down Below Threshold where difference in rates is less than or equal to 0.25 percent
|
||||||
|
if (cc.BuydownRateDifference() <= cc.NoReserveThreshold()) //we already know it's positive
|
||||||
|
{
|
||||||
|
loanReserve.ReserveAmount = 0;
|
||||||
|
loanReserve.ReserveTypeMessage = "No Reserve";
|
||||||
|
loanReserve.FlatFeePaid = false;
|
||||||
|
return loanReserve;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case - This is a regular Buy Down
|
||||||
|
_daysInterest = cc.BuydownRateDifference() / 100 * cc.DaysToFirstPmt() * cc.LoanData().LoanAmount /
|
||||||
|
365 * (decimal)Math.Pow(1 + (double)cc.LoanData().ContractRate / 100, (double)cc.LoanData().Term / 12);
|
||||||
|
|
||||||
|
loanReserve.ReserveAmount = -(cc.BuyFinanceCharge - cc.ContractFinanceCharge + _daysInterest);
|
||||||
|
loanReserve.ReserveTypeMessage = "Buy Down Reserve";
|
||||||
|
loanReserve.FlatFeePaid = false;
|
||||||
|
return loanReserve;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LoanReserve CalculateNoMarkup(CalculationConfig cc)
|
||||||
|
{
|
||||||
|
// Case - Contract rate is equal to the Buy rate
|
||||||
|
_daysInterest = cc.StdRate() * cc.DaysToFirstPmt() * cc.LoanData().LoanAmount /
|
||||||
|
365 * (decimal)Math.Pow(1 + (double)cc.LoanData().ContractRate / 100, (double)cc.LoanData().Term / 12);
|
||||||
|
|
||||||
|
loanReserve.ReserveAmount = (cc.ContractFinanceCharge - cc.BuyFinanceCharge + _daysInterest);
|
||||||
|
loanReserve.ReserveTypeMessage = "No Reserve";
|
||||||
|
loanReserve.FlatFeePaid = false;
|
||||||
|
return loanReserve;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LoanReserve CalculateStandardMarkup(CalculationConfig cc)
|
||||||
|
{
|
||||||
|
// Case - Contract rate is greater than Buy rate
|
||||||
|
_daysInterest = (1 - cc.ReserveDiscount()/100) * cc.StdRate() / 100 * cc.DaysToFirstPmt() * cc.LoanData().LoanAmount /
|
||||||
|
365 * (decimal)Math.Pow(1 + (double)cc.LoanData().ContractRate / 100, (double)cc.LoanData().Term / 12);
|
||||||
|
|
||||||
|
loanReserve.ReserveAmount = ((1 - cc.ReserveDiscount() / 100) * (cc.ContractFinanceCharge - cc.BuyFinanceCharge) + _daysInterest);
|
||||||
|
|
||||||
|
if ((double)cc.StdRate() <= 2.5)
|
||||||
|
{
|
||||||
|
loanReserve.ReserveTypeMessage = "Standard Reserve";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
loanReserve.ReserveTypeMessage = "Standard Reserve - Exceeds Max Markup";
|
||||||
|
}
|
||||||
|
return loanReserve;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LoanReserve AssignFlatFee(LoanReserve loanReserve, CalculationConfig cc)
|
||||||
|
{
|
||||||
|
loanReserve.FlatFeePaid = false;
|
||||||
|
if (loanReserve.ReserveAmount < (cc.FlatFeePercent() / 100 * cc._loanData.LoanAmount * (1 - cc.ReserveDiscount() / 100)))
|
||||||
|
{
|
||||||
|
loanReserve.ReserveAmount = (cc.FlatFeePercent() / 100 * cc._loanData.LoanAmount * (1 - cc.ReserveDiscount() / 100));
|
||||||
|
loanReserve.ReserveTypeMessage = "Flat Fee Reserve";
|
||||||
|
loanReserve.FlatFeePaid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return loanReserve;
|
||||||
|
}
|
||||||
|
|
||||||
|
public decimal FinanceCharge(int term, decimal loanAmount, decimal rate)
|
||||||
|
{
|
||||||
|
if (rate == 0) { return 0; }
|
||||||
|
double paymentRate = (double)rate / (double)1200;
|
||||||
|
decimal rateFactor = (decimal)Math.Pow((1 + paymentRate), (double)term);
|
||||||
|
return (loanAmount * term * rate / 1200 * rateFactor) / (rateFactor - 1) - loanAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal DateTime GetLastChargebackDate(DateTime loanDate, DateTime firstPmtDate, int numOfChargebackPayments, Int16? numOfChargebackDays)
|
||||||
|
{
|
||||||
|
// in rare cases that date from loan date is most recent, check table values and compare between loan date vs. first payment date
|
||||||
|
int result = DateTime.Compare(loanDate.AddDays((Double)numOfChargebackDays), firstPmtDate.AddMonths(numOfChargebackPayments - 1));
|
||||||
|
if (result > 0)
|
||||||
|
{
|
||||||
|
return loanDate.AddDays((Double)numOfChargebackDays); //Loan Date is most recent
|
||||||
|
}
|
||||||
|
return firstPmtDate.AddMonths(numOfChargebackPayments - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal decimal CalculateChargeback(decimal reserve, int term, int remainingMonths)
|
||||||
|
{
|
||||||
|
return reserve * MonthFactor(remainingMonths) / MonthFactor(term);
|
||||||
|
}
|
||||||
|
|
||||||
|
private decimal MonthFactor(int numberOfMonths)
|
||||||
|
{
|
||||||
|
return numberOfMonths * (numberOfMonths + 1) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetRemainingMonths(Loan loanData)
|
||||||
|
{
|
||||||
|
if (loanData.PaidLoanDate >= loanData.FinalPmtDate)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
var monthsOccurred = (loanData.PaidLoanDate.Value - loanData.FirstPmtDate).TotalDays / (365) * 12 + 1;
|
||||||
|
|
||||||
|
var remainingMonths = (int)(loanData.Term - Math.Round((decimal)monthsOccurred, 0));
|
||||||
|
return remainingMonths;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
+72
@@ -0,0 +1,72 @@
|
|||||||
|
using NCrontab;
|
||||||
|
using ReserveManagementSystemApi.Services;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi.HostedService
|
||||||
|
{
|
||||||
|
public class HostedImportExportActive : BackgroundService
|
||||||
|
{
|
||||||
|
private readonly IConfiguration _config;
|
||||||
|
private readonly IServiceScopeFactory _scopeFactory;
|
||||||
|
private readonly CrontabSchedule _schedule;
|
||||||
|
private DateTime _nextRun;
|
||||||
|
public const string DefaultCronPattern = "0 19 * * 0-6";
|
||||||
|
|
||||||
|
private CancellationToken _cancellationToken;
|
||||||
|
|
||||||
|
public HostedImportExportActive(IConfiguration config, IServiceScopeFactory scopeFactory)
|
||||||
|
{
|
||||||
|
_config = config;
|
||||||
|
_scopeFactory = scopeFactory;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_schedule = CrontabSchedule.Parse(_config.GetSection("HostedServices").GetSection("ImportExportActiveCronSchedule").Value);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, "Failure parsing crontab in appsettings.");
|
||||||
|
_schedule = CrontabSchedule.Parse(DefaultCronPattern);
|
||||||
|
}
|
||||||
|
_nextRun = _schedule.GetNextOccurrence(DateTime.Now);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task ExecuteAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
Log.Information("Hosted ImportExportActive is starting.");
|
||||||
|
Log.Information($"The import export active job will run at {_nextRun:M/d/yyyy HH:mm:ss tt}");
|
||||||
|
|
||||||
|
_cancellationToken = cancellationToken;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await ImportExportScheduler(cancellationToken);
|
||||||
|
}
|
||||||
|
catch (TaskCanceledException ex) when (_cancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
Log.Information(ex, "Hosted ImportExportActive shut down normally.");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, "Error trying to startup main thread for Hosted ImportExportActive");
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.Information("Hosted ImportExportActive is stopping.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ImportExportScheduler(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (DateTime.Now > _nextRun)
|
||||||
|
{
|
||||||
|
using (var scope = _scopeFactory.CreateScope())
|
||||||
|
{
|
||||||
|
await scope.ServiceProvider.GetRequiredService<IScheduleService>().RunImportExportActive(_cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
_nextRun = _schedule.GetNextOccurrence(DateTime.Now);
|
||||||
|
}
|
||||||
|
|
||||||
|
await Task.Delay(5000, cancellationToken); //5 seconds delay
|
||||||
|
} while (!cancellationToken.IsCancellationRequested);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+72
@@ -0,0 +1,72 @@
|
|||||||
|
using NCrontab;
|
||||||
|
using ReserveManagementSystemApi.Services;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi.HostedService
|
||||||
|
{
|
||||||
|
public class HostedImportExportClosed : BackgroundService
|
||||||
|
{
|
||||||
|
private readonly IConfiguration _config;
|
||||||
|
private readonly IServiceScopeFactory _scopeFactory;
|
||||||
|
private readonly CrontabSchedule _schedule;
|
||||||
|
private DateTime _nextRun;
|
||||||
|
public const string DefaultCronPattern = "15 19 * * 0-6";
|
||||||
|
|
||||||
|
private CancellationToken _cancellationToken;
|
||||||
|
|
||||||
|
public HostedImportExportClosed(IConfiguration config, IServiceScopeFactory scopeFactory)
|
||||||
|
{
|
||||||
|
_config = config;
|
||||||
|
_scopeFactory = scopeFactory;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_schedule = CrontabSchedule.Parse(_config.GetSection("HostedServices").GetSection("ImportExportClosedCronSchedule").Value);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, "Failure parsing crontab in appsettings.");
|
||||||
|
_schedule = CrontabSchedule.Parse(DefaultCronPattern);
|
||||||
|
}
|
||||||
|
_nextRun = _schedule.GetNextOccurrence(DateTime.Now);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task ExecuteAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
Log.Information("Hosted ImportExportClosed is starting.");
|
||||||
|
Log.Information($"The import export closed job will run at {_nextRun:M/d/yyyy HH:mm:ss tt}");
|
||||||
|
|
||||||
|
_cancellationToken = cancellationToken;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await ImportExportScheduler(cancellationToken);
|
||||||
|
}
|
||||||
|
catch (TaskCanceledException ex) when (_cancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
Log.Information(ex, "Hosted ImportExportClosed shut down normally.");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, "Error trying to startup main thread for Hosted ImportExportClosed");
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.Information("Hosted ImportExportClosed is stopping.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ImportExportScheduler(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (DateTime.Now > _nextRun)
|
||||||
|
{
|
||||||
|
using (var scope = _scopeFactory.CreateScope())
|
||||||
|
{
|
||||||
|
await scope.ServiceProvider.GetRequiredService<IScheduleService>().RunImportExportClosed(_cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
_nextRun = _schedule.GetNextOccurrence(DateTime.Now);
|
||||||
|
}
|
||||||
|
|
||||||
|
await Task.Delay(5000, cancellationToken); //5 seconds delay
|
||||||
|
} while (!cancellationToken.IsCancellationRequested);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+180
@@ -0,0 +1,180 @@
|
|||||||
|
using LCU.Library.Internal.CoreApiWrapperModel.CoreModels.Transaction;
|
||||||
|
using LCU.Library.Internal.CoreApiWrapperModel.CoreModels.CoreRequests;
|
||||||
|
using ReserveManagementSystemLib.Models;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi.Mappers
|
||||||
|
{
|
||||||
|
public static class ExportMapper
|
||||||
|
{
|
||||||
|
//used for Chargeback transactions
|
||||||
|
private const string GeneralLedgerReceipt = "GLR";
|
||||||
|
private const string DealerInterestRebate = "DRIR";
|
||||||
|
private const string ChargeBkDesc = "ChrgBk";
|
||||||
|
private const string ChargeBkAdjDesc = "ChrgBk Adj";
|
||||||
|
private const string GeneralLedgerCategory = "NOTE";
|
||||||
|
private const string GeneralLedgerType = "BAL";
|
||||||
|
|
||||||
|
//used for Reserve transactions
|
||||||
|
private const string DealerExpense = "DLRE";
|
||||||
|
private const string DealerIncome = "DLRI";
|
||||||
|
private const string ReserveAdjDesc = "Adjustment";
|
||||||
|
|
||||||
|
//used for all transaction types
|
||||||
|
private const string UpfrontCategory = "UPFR";
|
||||||
|
private const string DealerType = "DLR";
|
||||||
|
private const string ElectronicFundType = "EL";
|
||||||
|
private const string NoHoldClearCategory = "IMED";
|
||||||
|
private const string FundTypeDetail = "INTR";
|
||||||
|
|
||||||
|
public static GroupedMonetaryTransactionRequest MapLoanToIndirectLoanForReserve(Loan loan)
|
||||||
|
{
|
||||||
|
return new GroupedMonetaryTransactionRequest
|
||||||
|
{
|
||||||
|
MonetaryTransactionRequests = BuildReserveTransactions(loan),
|
||||||
|
ParentRequestNumber = loan.LoanNumber
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<MonetaryTransactionRequest> BuildReserveTransactions(Loan loan)
|
||||||
|
{
|
||||||
|
var listTransaction = new List<MonetaryTransactionRequest>();
|
||||||
|
var isAdjustment = loan.Adjustment != null && loan.Adjustment != 0;
|
||||||
|
|
||||||
|
var reserveRounded = Math.Round(loan.ReserveAmount, 4, MidpointRounding.AwayFromZero); //this represents the amount saved to DB
|
||||||
|
var amount = isAdjustment ? Math.Round((decimal)loan.Adjustment, 2, MidpointRounding.AwayFromZero) : Math.Round(reserveRounded, 2, MidpointRounding.AwayFromZero);
|
||||||
|
var transactionDescription = isAdjustment ? ReserveAdjDesc : null;
|
||||||
|
|
||||||
|
var loanAmount = (double)amount * -1;
|
||||||
|
listTransaction.Add(BuildParentTransaction(loanAmount, loan.LoanNumber, DealerExpense, transactionDescription));
|
||||||
|
|
||||||
|
var dealerAmount = (double)amount;
|
||||||
|
listTransaction.Add(BuildDealerTransaction(dealerAmount, loan.Dealer.DealerAccountNumber, DealerIncome, transactionDescription));
|
||||||
|
|
||||||
|
return listTransaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GroupedMonetaryTransactionRequest MapLoanToIndirectLoanForChargeback(Loan loan, MinorAccountType accountType)
|
||||||
|
{
|
||||||
|
var request = new GroupedMonetaryTransactionRequest();
|
||||||
|
if (accountType != null) {
|
||||||
|
request.MonetaryTransactionRequests = BuildChargebackTransactions(loan, accountType.GeneralLedgerAccountNumber);
|
||||||
|
request.ParentRequestNumber = loan.LoanNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<MonetaryTransactionRequest> BuildChargebackTransactions(Loan loan, string accountNumber)
|
||||||
|
{
|
||||||
|
var listTransaction = new List<MonetaryTransactionRequest>();
|
||||||
|
_balanceTypeList = new List<BalanceType1>();
|
||||||
|
_fundList = new List<Fund>();
|
||||||
|
_fundBalanceTypeList = new List<FundBalanceType>();
|
||||||
|
|
||||||
|
var isAdjustment = loan.Adjustment != null && loan.Adjustment != 0;
|
||||||
|
|
||||||
|
var chargeBackRounded = Math.Round((decimal)loan.ChargeBack, 4, MidpointRounding.AwayFromZero); //this represents the amount saved to DB
|
||||||
|
var amount = isAdjustment ? Math.Round((decimal)loan.Adjustment, 2, MidpointRounding.AwayFromZero) : Math.Round(chargeBackRounded, 2, MidpointRounding.AwayFromZero);
|
||||||
|
var transactionDescription = isAdjustment ? $"{ChargeBkAdjDesc}-{loan.LoanNumber}" : $"{ChargeBkDesc}-{loan.LoanNumber}";
|
||||||
|
|
||||||
|
var loanAmount = (double)amount;
|
||||||
|
listTransaction.Add(BuildParentTransaction(loanAmount, accountNumber, GeneralLedgerReceipt, transactionDescription));
|
||||||
|
|
||||||
|
var dealerAmount = (double)amount * -1;
|
||||||
|
listTransaction.Add(BuildDealerTransaction(dealerAmount, loan.Dealer.DealerAccountNumber, DealerInterestRebate, transactionDescription));
|
||||||
|
|
||||||
|
return listTransaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MonetaryTransactionRequest BuildParentTransaction(double amount, string accountNumber, string transactionType, string transactionDescription)
|
||||||
|
{
|
||||||
|
//if a reserve the parent transaction contains the loan number, if chargeback the account is the ledger account for minor account type
|
||||||
|
_balanceTypeList = new List<BalanceType1>();
|
||||||
|
_fundList = new List<Fund>();
|
||||||
|
_fundBalanceTypeList = new List<FundBalanceType>();
|
||||||
|
|
||||||
|
_balanceTypeList.Add(BuildBalanceType(amount, transactionType));
|
||||||
|
_fundList.Add(BuildFund(amount));
|
||||||
|
_fundBalanceTypeList.Add(BuildFundBalanceType(amount));
|
||||||
|
|
||||||
|
var transaction = new MonetaryTransactionRequest()
|
||||||
|
{
|
||||||
|
AccountNumber = (long)System.Convert.ToUInt64(accountNumber),
|
||||||
|
TransactionAmount = (transactionType != GeneralLedgerReceipt) ? amount : (double?)null,
|
||||||
|
RequestNumber = "1",
|
||||||
|
ParentRequestNumber = null,
|
||||||
|
TransactionTypeCode = transactionType,
|
||||||
|
Description = transactionDescription,
|
||||||
|
BalanceTypes = _balanceTypeList,
|
||||||
|
Funds = _fundList,
|
||||||
|
FundBalanceTypes = (transactionType == GeneralLedgerReceipt) ? _fundBalanceTypeList : null,
|
||||||
|
};
|
||||||
|
|
||||||
|
return transaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MonetaryTransactionRequest BuildDealerTransaction(double amount, string dealerAccount, string transactionType, string transactionDescription)
|
||||||
|
{
|
||||||
|
//for second request take the offset amount value of parent request amount
|
||||||
|
_balanceTypeList = new List<BalanceType1>();
|
||||||
|
_fundList = new List<Fund>();
|
||||||
|
_fundBalanceTypeList = new List<FundBalanceType>();
|
||||||
|
|
||||||
|
_balanceTypeList.Add(BuildBalanceType(amount, transactionType));
|
||||||
|
_fundList.Add(BuildFund(amount));
|
||||||
|
_fundBalanceTypeList.Add(BuildFundBalanceType(amount));
|
||||||
|
|
||||||
|
var transaction = new MonetaryTransactionRequest()
|
||||||
|
{
|
||||||
|
AccountNumber = (string.IsNullOrEmpty(dealerAccount) == true) ? 0 : (long)System.Convert.ToUInt64(dealerAccount),
|
||||||
|
TransactionAmount = amount,
|
||||||
|
RequestNumber = "2",
|
||||||
|
ParentRequestNumber = "1",
|
||||||
|
TransactionTypeCode = transactionType,
|
||||||
|
Description = transactionDescription,
|
||||||
|
BalanceTypes = _balanceTypeList,
|
||||||
|
Funds = _fundList,
|
||||||
|
};
|
||||||
|
|
||||||
|
return transaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<FundBalanceType> _fundBalanceTypeList;
|
||||||
|
private static FundBalanceType BuildFundBalanceType(double amount)
|
||||||
|
{
|
||||||
|
return new FundBalanceType
|
||||||
|
{
|
||||||
|
FundBalanceAmount = amount,
|
||||||
|
FundTypeCode = ElectronicFundType,
|
||||||
|
FundTypeDetailCode = NoHoldClearCategory
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<BalanceType1> _balanceTypeList;
|
||||||
|
private static BalanceType1 BuildBalanceType(double amount, string transactionType)
|
||||||
|
{
|
||||||
|
return new BalanceType1
|
||||||
|
{
|
||||||
|
BalanceTypeAmount = amount,
|
||||||
|
BalanceCategoryCode = (transactionType == GeneralLedgerReceipt) ? GeneralLedgerCategory : UpfrontCategory,
|
||||||
|
BalanceTypeCode = (transactionType == GeneralLedgerReceipt) ? GeneralLedgerType : DealerType,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Fund> _fundList;
|
||||||
|
private static Fund BuildFund(double amount)
|
||||||
|
{
|
||||||
|
return new Fund
|
||||||
|
{
|
||||||
|
ClearingCategoryCode = NoHoldClearCategory,
|
||||||
|
FundAmount = amount,
|
||||||
|
FundTypeCode = ElectronicFundType,
|
||||||
|
FundTypeDetailCode = FundTypeDetail,
|
||||||
|
NumberOfItems = 1,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
+43
@@ -0,0 +1,43 @@
|
|||||||
|
using CsvHelper.Configuration.Attributes;
|
||||||
|
using System;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi.Models
|
||||||
|
{
|
||||||
|
public class ImportBoatLoan
|
||||||
|
{
|
||||||
|
|
||||||
|
[Index(0)]
|
||||||
|
public string LoanNumber { get; set; }
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
[Index(1)]
|
||||||
|
public string DealerAccountNumber { get; set; }
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
[Index(2)]
|
||||||
|
public decimal Amount { get; set; }
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
[Index(3)]
|
||||||
|
public string IsChargeback { get; set; }
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
[Index(4)]
|
||||||
|
public string IsAdjustment { get; set; }
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
[Index(5)]
|
||||||
|
[Optional]
|
||||||
|
public string AccountType { get; set; }
|
||||||
|
|
||||||
|
[Index(6)]
|
||||||
|
[Optional]
|
||||||
|
public string ErrorMessage { get; set; }
|
||||||
|
|
||||||
|
[Index(7)]
|
||||||
|
[Optional]
|
||||||
|
public bool? WasSuccessful { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
+113
@@ -0,0 +1,113 @@
|
|||||||
|
using CsvHelper.Configuration.Attributes;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi.Models
|
||||||
|
{
|
||||||
|
public class ImportNewLoan
|
||||||
|
{
|
||||||
|
[Index(0)]
|
||||||
|
public string DealerOrganizationNumber { get; set; }
|
||||||
|
|
||||||
|
[Index(1)]
|
||||||
|
public string MemberNumber { get; set; }
|
||||||
|
|
||||||
|
[Index(2)]
|
||||||
|
public string LoanNumber { get; set; }
|
||||||
|
|
||||||
|
[Index(3)]
|
||||||
|
public string LastName { get; set; }
|
||||||
|
|
||||||
|
[Index(4)]
|
||||||
|
public string FirstAndMiddleName { get; set; }
|
||||||
|
|
||||||
|
[Index(5)]
|
||||||
|
public DateTime LoanDate { get; set; }
|
||||||
|
|
||||||
|
[Index(6)]
|
||||||
|
public DateTime PostedDate { get; set; }
|
||||||
|
|
||||||
|
[Index(7)]
|
||||||
|
public DateTime FirstPmtDate { get; set; }
|
||||||
|
|
||||||
|
[Index(8)]
|
||||||
|
public DateTime FinalPmtDate { get; set; }
|
||||||
|
|
||||||
|
[Index(9)]
|
||||||
|
public decimal LoanAmount { get; set; }
|
||||||
|
|
||||||
|
[Index(10)]
|
||||||
|
public decimal BuyRate { get; set; }
|
||||||
|
|
||||||
|
[Index(11)]
|
||||||
|
public decimal ContractRate { get; set; }
|
||||||
|
|
||||||
|
[Index(12)]
|
||||||
|
public decimal MonthlyPmt { get; set; }
|
||||||
|
|
||||||
|
[Index(13)]
|
||||||
|
public string LoanType { get; set; }
|
||||||
|
|
||||||
|
[Index(14)]
|
||||||
|
public string InsuranceIndicator { get; set; }
|
||||||
|
|
||||||
|
[Index(15)]
|
||||||
|
public string NewMember { get; set; }
|
||||||
|
|
||||||
|
[Index(16)]
|
||||||
|
[Optional]
|
||||||
|
public string OriginalTermInDays { get; set; }
|
||||||
|
|
||||||
|
[Index(17)]
|
||||||
|
[Optional]
|
||||||
|
public string VINNumber { get; set; }
|
||||||
|
|
||||||
|
[Index(18)]
|
||||||
|
[Optional]
|
||||||
|
public string Make { get; set; }
|
||||||
|
|
||||||
|
[Index(19)]
|
||||||
|
[Optional]
|
||||||
|
public string Model { get; set; }
|
||||||
|
|
||||||
|
[Index(20)]
|
||||||
|
[Optional]
|
||||||
|
public string Year { get; set; }
|
||||||
|
|
||||||
|
[Index(21)]
|
||||||
|
[Optional]
|
||||||
|
public string Mileage { get; set; }
|
||||||
|
|
||||||
|
[Index(22)]
|
||||||
|
[Optional]
|
||||||
|
public string Color { get; set; }
|
||||||
|
|
||||||
|
[Index(23)]
|
||||||
|
[Optional]
|
||||||
|
public string ApplicationId { get; set; }
|
||||||
|
|
||||||
|
[Index(24)]
|
||||||
|
[Optional]
|
||||||
|
public string Warranty { get; set; }
|
||||||
|
|
||||||
|
[Index(25)]
|
||||||
|
[Optional]
|
||||||
|
public string Gap { get; set; }
|
||||||
|
|
||||||
|
[Index(26)]
|
||||||
|
[Optional]
|
||||||
|
public string CreditLife { get; set; }
|
||||||
|
|
||||||
|
[Index(27)]
|
||||||
|
[Optional]
|
||||||
|
public string CreditDisability { get; set; }
|
||||||
|
|
||||||
|
[Index(28)]
|
||||||
|
[Optional]
|
||||||
|
public string Mbp { get; set; }
|
||||||
|
|
||||||
|
[Index(29)]
|
||||||
|
[Optional]
|
||||||
|
public string AccountType { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
+249
@@ -0,0 +1,249 @@
|
|||||||
|
using ReserveManagementSystemApi.Services;
|
||||||
|
using ReserveManagementSystemApi.HostedService;
|
||||||
|
using ReserveManagementSystemApi.ServiceClients;
|
||||||
|
using ReserveManagementSystemApi.Configurations;
|
||||||
|
using ReserveManagementSystemLib.Configuration;
|
||||||
|
using ReserveManagementSystemLib.Persistence;
|
||||||
|
using ReserveManagementSystemLib.Repositories;
|
||||||
|
using MassTransit;
|
||||||
|
using Microsoft.OpenApi.Models;
|
||||||
|
using Microsoft.Extensions.FileProviders;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using LCU.Library.Internal.LcuHttpClient;
|
||||||
|
using LCU.Library.Internal.ApiSecurity;
|
||||||
|
using LCU.Library.Internal.Logging.Models;
|
||||||
|
using LCU.Library.Internal.Logging;
|
||||||
|
using LCU.Library.Internal.Logging.Middleware;
|
||||||
|
using LCU.Library.Internal.Configuration;
|
||||||
|
using LCU.Library.Internal.LcuMassTransit;
|
||||||
|
using LCU.Library.Internal.LcuMassTransitModels;
|
||||||
|
using ReserveManagementSystemApi.Consumers;
|
||||||
|
using ReserveManagementSystemApi.Services.QueueServices;
|
||||||
|
using LCU.Library.Internal.Status;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi
|
||||||
|
{
|
||||||
|
public class Program
|
||||||
|
{
|
||||||
|
public static string MyAllowSpecificOrigins { get; private set; }
|
||||||
|
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
|
||||||
|
WebApplicationBuilder builder = BuildBuilder(args);
|
||||||
|
BuildServicesAndConfigurations(builder);
|
||||||
|
BuildAppAndRun(builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static WebApplicationBuilder BuildBuilder(string[] args)
|
||||||
|
{
|
||||||
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
builder.Configuration.AddJsonFile("/app/config/environment-appsettings/appsettings.json", true, true);
|
||||||
|
builder.Configuration.AddJsonFile("/app/config/workload-appsettings/appsettings.json", true, true);
|
||||||
|
builder.Configuration.AddJsonFile("/vault/secrets/reserve-management-system-seq-api-key.json", true, true);
|
||||||
|
builder.Configuration.AddJsonFile("/vault/secrets/reserve-management-system-rms-database-connection.json", true, true);
|
||||||
|
builder.Configuration.AddJsonFile("/vault/secrets/reserve-management-system-connection-configuration-queue-username.json", true, true);
|
||||||
|
builder.Configuration.AddJsonFile("/vault/secrets/reserve-management-system-connection-configuration-queue-password.json", true, true);
|
||||||
|
builder.Configuration.AddJsonFile("/vault/secrets/reserve-management-system-api-security-configuration-internal-api-key-set.json", true, true);
|
||||||
|
builder.Host.UseSerilog();
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void BuildServicesAndConfigurations(WebApplicationBuilder builder)
|
||||||
|
{
|
||||||
|
var services = builder.Services;
|
||||||
|
var configuration = builder.Configuration;
|
||||||
|
|
||||||
|
services.AddControllers();
|
||||||
|
services.AddEndpointsApiExplorer();
|
||||||
|
services.AddLCUHttpServices();
|
||||||
|
|
||||||
|
var apiConfiguration = configuration.Bind<ApiConfiguration>(services, "Primary");
|
||||||
|
|
||||||
|
services.AddCors(options =>
|
||||||
|
{
|
||||||
|
options.AddPolicy(MyAllowSpecificOrigins,
|
||||||
|
builder =>
|
||||||
|
{
|
||||||
|
builder.WithOrigins(apiConfiguration.CorsAllowedOrigins).AllowAnyHeader()
|
||||||
|
.AllowAnyMethod();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
services.AddDbContext<AppDbContext>(options =>
|
||||||
|
{
|
||||||
|
options.UseSqlServer(configuration.GetSection("SqlConnectionConfiguration").GetSection("ConnectionString").Value);
|
||||||
|
});
|
||||||
|
|
||||||
|
var connectionConfiguration = MassTransitConfigurationSetUp.AddConnectionConfiguration(ref services, configuration);
|
||||||
|
Log.Debug(JsonConvert.SerializeObject(connectionConfiguration));
|
||||||
|
|
||||||
|
var receiveEndpointConfigurations = new ReceiveEndpointConfigurations()
|
||||||
|
{
|
||||||
|
RmsActiveLoanReceiveEndpoint = MassTransitConfigurationSetUp.GetReceiveEndpointConfiguration(configuration, "RmsActiveLoanReceiveEndpoint")
|
||||||
|
};
|
||||||
|
|
||||||
|
services.AddSingleton(receiveEndpointConfigurations);
|
||||||
|
Log.Debug(JsonConvert.SerializeObject(receiveEndpointConfigurations));
|
||||||
|
|
||||||
|
AddMassTransitServices(ref services, connectionConfiguration, receiveEndpointConfigurations, apiConfiguration);
|
||||||
|
AddQueueServices(services);
|
||||||
|
|
||||||
|
var loggerConfiguration = new LoggingConfiguration(apiConfiguration.AppName,
|
||||||
|
apiConfiguration.SeqApiKey,
|
||||||
|
apiConfiguration.SeqUrl);
|
||||||
|
var lcuLogging = new LcuLogging(loggerConfiguration);
|
||||||
|
lcuLogging.UseLcuLogging();
|
||||||
|
|
||||||
|
var rmsApiConfiguration = configuration.Bind<RmsApiConfiguration>(services, "RmsApiConfiguration");
|
||||||
|
var coreApiConfiguration = configuration.Bind<CoreApiConfiguration>(services, "CoreApiConfiguration");
|
||||||
|
|
||||||
|
services.AddApiKeySecurity(configuration);
|
||||||
|
services.AddLCUStatusServices();
|
||||||
|
|
||||||
|
//Services
|
||||||
|
services.AddScoped<IStatusService, StatusService>();
|
||||||
|
services.AddScoped<ILoanCalculationService, LoanCalculationService>();
|
||||||
|
services.AddScoped<ILoanService, LoanService>();
|
||||||
|
services.AddScoped<IImportService, ImportService>();
|
||||||
|
services.AddScoped<IImportReadService, ImportReadService>();
|
||||||
|
services.AddScoped<IAuditHistoryService, AuditHistoryService>();
|
||||||
|
services.AddScoped<IDealerService, DealerService>();
|
||||||
|
services.AddScoped<IExportService, ExportService>();
|
||||||
|
services.AddScoped<IVehicleService, VehicleService>();
|
||||||
|
services.AddScoped<IScheduleService, ScheduleService>();
|
||||||
|
services.AddScoped<IRmsActiveLoanService, RmsActiveLoanService>();
|
||||||
|
|
||||||
|
//Service Clients
|
||||||
|
services.AddScoped<ICoreApiServiceClient, CoreApiServiceClient>();
|
||||||
|
|
||||||
|
//Repositories
|
||||||
|
services.AddScoped<ILoanRepository, LoanRepository>();
|
||||||
|
services.AddScoped<ILoanTypeRepository, LoanTypeRepository>();
|
||||||
|
services.AddScoped<IImportRepository, ImportRepository>();
|
||||||
|
services.AddScoped<IAuditHistoryRepository, AuditHistoryRepository>();
|
||||||
|
services.AddScoped<IDealerRepository, DealerRepository>();
|
||||||
|
services.AddScoped<IVehicleRepository, VehicleRepository>();
|
||||||
|
services.AddScoped<IMinorAccountTypeRepository, MinorAccountTypeRepository>();
|
||||||
|
|
||||||
|
//HostedServices
|
||||||
|
if (apiConfiguration.FeatureFlags.EnableImportExportActive)
|
||||||
|
{
|
||||||
|
services.AddHostedService<HostedImportExportActive>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (apiConfiguration.FeatureFlags.EnableImportExportClosed)
|
||||||
|
{
|
||||||
|
services.AddHostedService<HostedImportExportClosed>();
|
||||||
|
}
|
||||||
|
|
||||||
|
services.AddSwaggerGen(c =>
|
||||||
|
{
|
||||||
|
c.SwaggerDoc("v1", new OpenApiInfo
|
||||||
|
{
|
||||||
|
Title = $"{apiConfiguration.AppName}",
|
||||||
|
Version = "v1",
|
||||||
|
Contact = new OpenApiContact { Name = "SpecFlow Tests", Url = new Uri("/Specs/index.html", UriKind.Relative) }
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void BuildAppAndRun(WebApplicationBuilder builder)
|
||||||
|
{
|
||||||
|
var app = builder.Build();
|
||||||
|
|
||||||
|
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];
|
||||||
|
swaggerDoc.Servers = new List<OpenApiServer>()
|
||||||
|
{
|
||||||
|
new() { Description = serverUrl, Url = serverUrl }
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
app.UseSwaggerUI(c =>
|
||||||
|
{
|
||||||
|
c.RoutePrefix = "swagger";
|
||||||
|
c.SwaggerEndpoint("v1/swagger.json", "ReserveManagementSystemApi v1");
|
||||||
|
});
|
||||||
|
|
||||||
|
if (app.Environment.IsDevelopment())
|
||||||
|
{
|
||||||
|
app.UseDeveloperExceptionPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
var specsFolder = Path.Combine(Directory.GetCurrentDirectory(), "Specs");
|
||||||
|
|
||||||
|
if (Directory.Exists(specsFolder))
|
||||||
|
{
|
||||||
|
app.UseFileServer(new FileServerOptions()
|
||||||
|
{
|
||||||
|
FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), "Specs")),
|
||||||
|
RequestPath = new PathString("/Specs"),
|
||||||
|
EnableDefaultFiles = true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
app.UseMiddleware<RequestResponseLoggingMiddleware>();
|
||||||
|
app.UseSerilogRequestLogging(options =>
|
||||||
|
{
|
||||||
|
options.EnrichDiagnosticContext = RequestResponseLoggingMiddleware.RequestDataParser.EnrichFromRequest;
|
||||||
|
});
|
||||||
|
|
||||||
|
app.UseAuthentication();
|
||||||
|
app.UseHttpsRedirection();
|
||||||
|
app.UseRouting();
|
||||||
|
app.UseAuthorization();
|
||||||
|
|
||||||
|
app.UseEndpoints(endpoints =>
|
||||||
|
{
|
||||||
|
endpoints.MapControllers();
|
||||||
|
});
|
||||||
|
|
||||||
|
app.Run();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void AddMassTransitServices(ref IServiceCollection services,
|
||||||
|
ConnectionConfiguration connectionConfiguration,
|
||||||
|
ReceiveEndpointConfigurations receiveEndpointConfigurations,
|
||||||
|
ApiConfiguration apiConfiguration)
|
||||||
|
{
|
||||||
|
services.AddMassTransit(x =>
|
||||||
|
{
|
||||||
|
x.AddConsumer<RmsActiveImportConsumer>();
|
||||||
|
|
||||||
|
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.RunRmsActiveLoanConsumer)
|
||||||
|
{
|
||||||
|
cfg.ReceiveEndpoint(receiveEndpointConfigurations.RmsActiveLoanReceiveEndpoint.ReceiveEndpoint, e =>
|
||||||
|
{
|
||||||
|
e.ConfigureConsumer<RmsActiveImportConsumer>(context);
|
||||||
|
e.SetQuorumQueue();
|
||||||
|
e.PrefetchCount = receiveEndpointConfigurations.RmsActiveLoanReceiveEndpoint.PrefetchLimit;
|
||||||
|
e.UseTimeout(t => t.Timeout = TimeSpan.FromSeconds(420));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
services.AddMassTransitHostedService();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void AddQueueServices(IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddScoped<IQueueRmsActiveLoanService, QueueRmsActiveLoanService>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+45
@@ -0,0 +1,45 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<Version>1.1.1</Version>
|
||||||
|
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||||
|
<Description></Description>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="CsvHelper" Version="30.0.1" />
|
||||||
|
<PackageReference Include="LCU.Api.Internal.MaidBotLib" Version="1.0.2" />
|
||||||
|
<PackageReference Include="LCU.Library.Internal.ApiSecurity" Version="1.0.2" />
|
||||||
|
<PackageReference Include="LCU.Library.Internal.Configuration" Version="1.0.0" />
|
||||||
|
<PackageReference Include="LCU.Library.Internal.CoreApiWrapperModel" Version="2.3.0" />
|
||||||
|
<PackageReference Include="LCU.Library.Internal.Exceptions" Version="1.0.0" />
|
||||||
|
<PackageReference Include="LCU.Library.Internal.LcuHttpClient" Version="1.9.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.0.1" />
|
||||||
|
<PackageReference Include="LCU.Library.Internal.StatusModels" Version="1.0.0" />
|
||||||
|
<PackageReference Include="LCU.Shared.Common.NotificationApiLib" Version="2.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="2.2.7" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.18" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.NETCore.App" Version="2.2.8" />
|
||||||
|
<PackageReference Include="NCrontab.Signed" Version="3.3.2" />
|
||||||
|
<PackageReference Include="Pickles.CommandLine" Version="2.21.1" />
|
||||||
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
||||||
|
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.2.12" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\ReserveManagementSystemLib\ReserveManagementSystemLib.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="Specs\**">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
+51
@@ -0,0 +1,51 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 16
|
||||||
|
VisualStudioVersion = 16.0.31025.194
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReserveManagementSystemApi", "ReserveManagementSystemApi.csproj", "{954C8B67-1471-4FB2-81BD-713BEE5E679E}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReserveManagementSystemLib", "..\ReserveManagementSystemLib\ReserveManagementSystemLib.csproj", "{BA77A7A0-7D17-4BD8-80A4-B9FFB3908C82}"
|
||||||
|
EndProject
|
||||||
|
Project("{00D1A9C2-B5F0-4AF3-8072-F6C62B433612}") = "ReserveManagementSystemApi.Sql", "..\ReserveManagementSystemApi.Sql\ReserveManagementSystemApi.Sql.sqlproj", "{5A41C8DC-6F4D-4FD2-B03D-D0B2D8B363DF}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReserveManagementSystemApi.Tests", "..\ReserveManagementSystemApi.Tests\ReserveManagementSystemApi.Tests.csproj", "{CFE504B7-58D7-444B-A4B8-8A219400BA42}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReserveManagementSystemApi.Test", "..\ReserveManagementSystemApi.Test\ReserveManagementSystemApi.Test.csproj", "{5BC5FBBC-2B72-4055-95E0-41192F581784}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{954C8B67-1471-4FB2-81BD-713BEE5E679E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{954C8B67-1471-4FB2-81BD-713BEE5E679E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{954C8B67-1471-4FB2-81BD-713BEE5E679E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{954C8B67-1471-4FB2-81BD-713BEE5E679E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{BA77A7A0-7D17-4BD8-80A4-B9FFB3908C82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{BA77A7A0-7D17-4BD8-80A4-B9FFB3908C82}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{BA77A7A0-7D17-4BD8-80A4-B9FFB3908C82}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{BA77A7A0-7D17-4BD8-80A4-B9FFB3908C82}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{5A41C8DC-6F4D-4FD2-B03D-D0B2D8B363DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{5A41C8DC-6F4D-4FD2-B03D-D0B2D8B363DF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{5A41C8DC-6F4D-4FD2-B03D-D0B2D8B363DF}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
|
||||||
|
{5A41C8DC-6F4D-4FD2-B03D-D0B2D8B363DF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{5A41C8DC-6F4D-4FD2-B03D-D0B2D8B363DF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{5A41C8DC-6F4D-4FD2-B03D-D0B2D8B363DF}.Release|Any CPU.Deploy.0 = Release|Any CPU
|
||||||
|
{CFE504B7-58D7-444B-A4B8-8A219400BA42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{CFE504B7-58D7-444B-A4B8-8A219400BA42}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{CFE504B7-58D7-444B-A4B8-8A219400BA42}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{CFE504B7-58D7-444B-A4B8-8A219400BA42}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{5BC5FBBC-2B72-4055-95E0-41192F581784}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{5BC5FBBC-2B72-4055-95E0-41192F581784}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{5BC5FBBC-2B72-4055-95E0-41192F581784}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{5BC5FBBC-2B72-4055-95E0-41192F581784}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {27D5180A-D1E5-4786-9F4D-99C4652488F4}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
+120
@@ -0,0 +1,120 @@
|
|||||||
|
using ReserveManagementSystemLib.Configuration;
|
||||||
|
using LCU.Library.Internal.ApiSecurity.Models;
|
||||||
|
using LCU.Library.Internal.CoreApiWrapperModel.CoreModels.IndirectLoan;
|
||||||
|
using LCU.Library.Internal.CoreApiWrapperModel.CoreModels.CoreRequests;
|
||||||
|
using LCU.Library.Internal.CoreApiWrapperModel.CoreModels.Transaction;
|
||||||
|
using LCU.Library.Internal.LcuHttpClient.HttpRequest;
|
||||||
|
using LCU.Library.Internal.ApiSecurity.Enums;
|
||||||
|
using LCU.Library.Internal.LcuHttpClient.Utilities;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi.ServiceClients
|
||||||
|
{
|
||||||
|
public class CoreApiServiceClient : ICoreApiServiceClient
|
||||||
|
{
|
||||||
|
private readonly ApiSecurityConfiguration _apiSecurityConfiguration;
|
||||||
|
private readonly CoreApiConfiguration _coreApiWrapperConfiguration;
|
||||||
|
private readonly IPostRequest _postRequest;
|
||||||
|
private readonly IGetRequest _getRequest;
|
||||||
|
private readonly IPutRequest _putRequest;
|
||||||
|
|
||||||
|
private const string ClientKeyValue = "ReserveManagementSystem";
|
||||||
|
|
||||||
|
public CoreApiServiceClient(
|
||||||
|
ApiSecurityConfiguration apiSecurityConfiguration,
|
||||||
|
CoreApiConfiguration coreApiWrapperConfiguration,
|
||||||
|
IGetRequest getRequest,
|
||||||
|
IPostRequest postRequest,
|
||||||
|
IPutRequest putRequest
|
||||||
|
)
|
||||||
|
{
|
||||||
|
_apiSecurityConfiguration = apiSecurityConfiguration;
|
||||||
|
_coreApiWrapperConfiguration = coreApiWrapperConfiguration;
|
||||||
|
_getRequest = getRequest;
|
||||||
|
_postRequest = postRequest;
|
||||||
|
_putRequest = putRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<MonetaryTransactionResponse>> PostMonetaryTransactions(List<GroupedMonetaryTransactionRequest> loanReserves)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var path = $"{_coreApiWrapperConfiguration.BaseUrl}{_coreApiWrapperConfiguration.PostMonetaryTransactions}";
|
||||||
|
var uri = new Uri(path);
|
||||||
|
var response = await _postRequest.Async<List<GroupedMonetaryTransactionRequest>, List<MonetaryTransactionResponse>>(uri, loanReserves,
|
||||||
|
HttpUtilities.GetApiKeyHeaders(ClientKeyValue, _apiSecurityConfiguration.ExtractApiKey(ClientKeyValue, ApiKeySetName.InternalKeySet)),
|
||||||
|
0, Convert.ToInt16(_coreApiWrapperConfiguration.ApiTimeOutInSeconds));
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, "Error in posting MonetaryTransactions.");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<UpdateDealerOriginalBalanceResponse>> PutDealerOriginalBalance(string accountNumber)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var path = $"{_coreApiWrapperConfiguration.BaseUrl}{_coreApiWrapperConfiguration.PutDealerOriginalBalance}";
|
||||||
|
var uri = new Uri(path);
|
||||||
|
var response = await _putRequest.Async<string, List<UpdateDealerOriginalBalanceResponse>>(uri, accountNumber,
|
||||||
|
HttpUtilities.GetApiKeyHeaders(ClientKeyValue, _apiSecurityConfiguration.ExtractApiKey(ClientKeyValue, ApiKeySetName.InternalKeySet)),
|
||||||
|
0, Convert.ToUInt16(_coreApiWrapperConfiguration.ApiTimeOutInSeconds));
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, "Error updating Dealer Original Balance");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<IndirectLoanDetail>> GetIndirectLoansByPostedDate(string afterPostDate)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var path = $"{_coreApiWrapperConfiguration.BaseUrl}{_coreApiWrapperConfiguration.GetIndirectLoansByPostedDate}{afterPostDate}";
|
||||||
|
var response = await _getRequest.AsyncWithNewton<List<IndirectLoanDetail>>(path, null, 0, Convert.ToUInt16(_coreApiWrapperConfiguration.ApiTimeOutInSeconds));
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, "Error getting Indirect Loans By Posted Date");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<ClosedIndirectLoan>> GetClosedLoansByPostedDate(string afterPostDate)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var path = $"{_coreApiWrapperConfiguration.BaseUrl}{_coreApiWrapperConfiguration.GetClosedLoansByPostedDate}{afterPostDate}";
|
||||||
|
var response = await _getRequest.AsyncWithNewton<List<ClosedIndirectLoan>>(path);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, "Error getting Closed Loans By Posted Date");
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<IndirectLoanDetail>> GetClosedLoansWithDetailByClosedDate(string afterClosedDate)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var path = $"{_coreApiWrapperConfiguration.BaseUrl}{_coreApiWrapperConfiguration.GetClosedIndirectLoansWithDetailByPostedDate}{afterClosedDate}";
|
||||||
|
var response = await _getRequest.AsyncWithNewton<List<IndirectLoanDetail>>(path);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, "Error getting Closed Loans With Detail");
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
using LCU.Library.Internal.CoreApiWrapperModel.CoreModels.IndirectLoan;
|
||||||
|
using LCU.Library.Internal.CoreApiWrapperModel.CoreModels.Transaction;
|
||||||
|
using LCU.Library.Internal.CoreApiWrapperModel.CoreModels.CoreRequests;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi.ServiceClients
|
||||||
|
{
|
||||||
|
public interface ICoreApiServiceClient
|
||||||
|
{
|
||||||
|
Task<List<MonetaryTransactionResponse>> PostMonetaryTransactions(List<GroupedMonetaryTransactionRequest> loans);
|
||||||
|
|
||||||
|
Task<List<IndirectLoanDetail>> GetIndirectLoansByPostedDate(string afterPostDate);
|
||||||
|
|
||||||
|
Task<List<ClosedIndirectLoan>> GetClosedLoansByPostedDate(string afterPostDate);
|
||||||
|
|
||||||
|
Task<List<IndirectLoanDetail>> GetClosedLoansWithDetailByClosedDate(string afterClosedDate);
|
||||||
|
|
||||||
|
Task<List<UpdateDealerOriginalBalanceResponse>> PutDealerOriginalBalance(string accountNumber);
|
||||||
|
}
|
||||||
|
}
|
||||||
+146
@@ -0,0 +1,146 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
using ReserveManagementSystemApi.Enums;
|
||||||
|
using ReserveManagementSystemLib.Models;
|
||||||
|
using ReserveManagementSystemLib.Repositories;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi.Services
|
||||||
|
{
|
||||||
|
public class AuditHistoryService : IAuditHistoryService
|
||||||
|
{
|
||||||
|
private readonly IAuditHistoryRepository _auditHistoryRepository;
|
||||||
|
const string SYSTEM_MODIFIED_BY = "RMS";
|
||||||
|
|
||||||
|
public AuditHistoryService(IAuditHistoryRepository auditHistoryRepository)
|
||||||
|
{
|
||||||
|
_auditHistoryRepository = auditHistoryRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<AuditHistory>> GetAllAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await _auditHistoryRepository.GetAll().OrderByDescending(o => o.ModifiedDate).ToListAsync();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, "Failure retrieving audit histories.");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<AuditHistory> FindByIdAsync(int id)
|
||||||
|
{
|
||||||
|
AuditHistory history;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
history = await _auditHistoryRepository.FindByIdAsync(id);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, $"Failure retrieving history with id {id}.");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (history == null)
|
||||||
|
{
|
||||||
|
throw new Exception($"Audit history with id {id} not found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return history;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<AuditHistory> AddHistoryAsync(AuditHistory history)
|
||||||
|
{
|
||||||
|
return await _auditHistoryRepository.AddHistoryAsync(history);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> AddAuditHistoriesForNonexistingLoansAsync(List<Loan> loans)
|
||||||
|
{
|
||||||
|
var currentDate = DateTime.Now;
|
||||||
|
var histories = loans.Select(loan => new AuditHistory
|
||||||
|
{
|
||||||
|
LoanId = null,
|
||||||
|
MemberNumber = loan.MemberNumber,
|
||||||
|
LoanNumber = loan.LoanNumber,
|
||||||
|
ModifiedBy = SYSTEM_MODIFIED_BY,
|
||||||
|
ModifiedDate = currentDate,
|
||||||
|
ActivityType = ActivityType.Error.ToString(),
|
||||||
|
AuditDescription = "Loan in closed file not found",
|
||||||
|
OldValue = null,
|
||||||
|
NewValue = null
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
return await _auditHistoryRepository.AddHistoriesAsync(histories);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuditHistory GetAuditHistoryForNonexistingClosedLoan(Loan loan)
|
||||||
|
{
|
||||||
|
var currentDate = DateTime.Now;
|
||||||
|
return new AuditHistory
|
||||||
|
{
|
||||||
|
LoanId = null,
|
||||||
|
MemberNumber = loan.MemberNumber,
|
||||||
|
LoanNumber = loan.LoanNumber,
|
||||||
|
ModifiedBy = SYSTEM_MODIFIED_BY,
|
||||||
|
ModifiedDate = currentDate,
|
||||||
|
ActivityType = ActivityType.Error.ToString(),
|
||||||
|
AuditDescription = "Loan in closed import not found",
|
||||||
|
OldValue = null,
|
||||||
|
NewValue = null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuditHistory GetExistingLoanUpdateHistoryAsync(Loan loan, Loan originalLoan)
|
||||||
|
{
|
||||||
|
var currentDate = DateTime.Now;
|
||||||
|
return new AuditHistory
|
||||||
|
{
|
||||||
|
LoanId = loan.LoanId,
|
||||||
|
MemberNumber = loan.MemberNumber,
|
||||||
|
LoanNumber = loan.LoanNumber,
|
||||||
|
ModifiedBy = SYSTEM_MODIFIED_BY,
|
||||||
|
ModifiedDate = currentDate,
|
||||||
|
ActivityType = ActivityType.NewLoanUpdate.ToString(),
|
||||||
|
AuditDescription = "Loan found in table, record updated",
|
||||||
|
OldValue = JsonConvert.SerializeObject(originalLoan),
|
||||||
|
NewValue = JsonConvert.SerializeObject(loan)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuditHistory GetLoanStatusChangeHistory(Loan loan, string oldStatus, string description)
|
||||||
|
{
|
||||||
|
return new AuditHistory
|
||||||
|
{
|
||||||
|
LoanId = loan.LoanId,
|
||||||
|
MemberNumber = loan.MemberNumber,
|
||||||
|
LoanNumber = loan.LoanNumber,
|
||||||
|
ModifiedBy = SYSTEM_MODIFIED_BY,
|
||||||
|
ModifiedDate = DateTime.Now,
|
||||||
|
ActivityType = ActivityType.LoanStatusChange.ToString(),
|
||||||
|
OldValue = oldStatus,
|
||||||
|
NewValue = loan.LoanStatus,
|
||||||
|
AuditDescription = description
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> AddHistoriesAsync(List<AuditHistory> histories)
|
||||||
|
{
|
||||||
|
return await _auditHistoryRepository.AddHistoriesAsync(histories);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task AddErrorHistoryAsync(string memberNumber, string loanNumber, string description)
|
||||||
|
{
|
||||||
|
var auditHist = new AuditHistory
|
||||||
|
{
|
||||||
|
MemberNumber = memberNumber,
|
||||||
|
LoanNumber = loanNumber,
|
||||||
|
ActivityType = ActivityType.Error.ToString(),
|
||||||
|
ModifiedDate = DateTime.Now,
|
||||||
|
AuditDescription = description,
|
||||||
|
ModifiedBy = SYSTEM_MODIFIED_BY
|
||||||
|
};
|
||||||
|
|
||||||
|
await _auditHistoryRepository.AddHistoryAsync(auditHist);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+100
@@ -0,0 +1,100 @@
|
|||||||
|
using ReserveManagementSystemLib.Models;
|
||||||
|
using ReserveManagementSystemLib.Repositories;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi.Services
|
||||||
|
{
|
||||||
|
public class DealerService: IDealerService
|
||||||
|
{
|
||||||
|
private readonly IDealerRepository _dealerRepository;
|
||||||
|
|
||||||
|
public DealerService(IDealerRepository dealerRepository)
|
||||||
|
{
|
||||||
|
_dealerRepository = dealerRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<Dealer>> Search(string dealerSearchText)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await _dealerRepository.GetAll().Where(d => d.DealerCode.Contains(dealerSearchText) || d.Name.Contains(dealerSearchText)).OrderBy(x => x.DealerCode).ToListAsync();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, "Failure retrieving dealers.");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Dealer> GetDealerByCodeAsync(string dealerCode)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await _dealerRepository.FindByCodeAsync(dealerCode);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, "Failure retrieving dealer by code.");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<Dealer>> GetAllDealersAsync()
|
||||||
|
{
|
||||||
|
return await _dealerRepository.GetAll().ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UpdateDealersAsync(List<Dealer> dealers)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var allDealers = await GetAllDealersAsync();
|
||||||
|
var dealersToAdd = new List<Dealer>();
|
||||||
|
var dealersToUpdate = new List<Dealer>();
|
||||||
|
dealers.ForEach(d =>
|
||||||
|
{
|
||||||
|
var currentDealer = allDealers.FirstOrDefault(a => a.DealerOrganizationNumber == d.DealerOrganizationNumber);
|
||||||
|
if (currentDealer != null && !currentDealer.Equals(d))
|
||||||
|
{
|
||||||
|
currentDealer.Name = d.Name ?? currentDealer.Name;
|
||||||
|
currentDealer.DealerCode = d.DealerCode?.ToUpper() ?? currentDealer.DealerCode;
|
||||||
|
currentDealer.DealerAccountNumber = d.DealerAccountNumber ?? currentDealer.DealerAccountNumber;
|
||||||
|
currentDealer.DealerOrganizationNumber = d.DealerOrganizationNumber ?? currentDealer.DealerOrganizationNumber;
|
||||||
|
dealersToUpdate.Add(currentDealer);
|
||||||
|
}
|
||||||
|
else if (currentDealer == null)
|
||||||
|
{
|
||||||
|
//write the new dealer record to set Action required to true if invalid
|
||||||
|
dealersToAdd.Add(d);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (dealersToUpdate.Any())
|
||||||
|
{
|
||||||
|
await _dealerRepository.UpdateDealersAsync(dealersToUpdate);
|
||||||
|
}
|
||||||
|
if (dealersToAdd.Any())
|
||||||
|
{
|
||||||
|
await _dealerRepository.AddDealersAsync(dealersToAdd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, "Failure updating dealers.");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UpdateDealersAsync(List<Loan> loans)
|
||||||
|
{
|
||||||
|
var dealers = loans.Select(l => new Dealer
|
||||||
|
{
|
||||||
|
DealerCode = l.Dealer.DealerCode,
|
||||||
|
Name = l.Dealer.Name,
|
||||||
|
DealerOrganizationNumber = l.DealerOrganizationNumber,
|
||||||
|
DealerAccountNumber = l.Dealer.DealerAccountNumber
|
||||||
|
})
|
||||||
|
.GroupBy(d => d.DealerOrganizationNumber).Select(g => g.First()).ToList();
|
||||||
|
|
||||||
|
await UpdateDealersAsync(dealers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+275
@@ -0,0 +1,275 @@
|
|||||||
|
using LCU.Library.Internal.CoreApiWrapperModel.CoreModels.CoreRequests;
|
||||||
|
using LCU.Library.Internal.CoreApiWrapperModel.CoreModels.Transaction;
|
||||||
|
using ReserveManagementSystemApi.Mappers;
|
||||||
|
using ReserveManagementSystemApi.Helpers;
|
||||||
|
using ReserveManagementSystemApi.Models;
|
||||||
|
using ReserveManagementSystemApi.ServiceClients;
|
||||||
|
using ReserveManagementSystemLib.Models;
|
||||||
|
using ReserveManagementSystemLib.Repositories;
|
||||||
|
using ReserveManagementSystemLib.Configuration;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi.Services
|
||||||
|
{
|
||||||
|
public class ExportService: IExportService
|
||||||
|
{
|
||||||
|
private readonly ILoanRepository _loanRepository;
|
||||||
|
private readonly ICoreApiServiceClient _coreApiServiceClient;
|
||||||
|
private readonly IMinorAccountTypeRepository _minorAccountTypeRepository;
|
||||||
|
private readonly RmsApiConfiguration _rmsApiConfig;
|
||||||
|
|
||||||
|
public ExportService(ILoanRepository loanRepository, ICoreApiServiceClient coreApiServiceClient, IMinorAccountTypeRepository minorAccountTypeRepository, RmsApiConfiguration rmsApiConfig)
|
||||||
|
{
|
||||||
|
_loanRepository = loanRepository;
|
||||||
|
_coreApiServiceClient = coreApiServiceClient;
|
||||||
|
_minorAccountTypeRepository = minorAccountTypeRepository;
|
||||||
|
_rmsApiConfig = rmsApiConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> ExportReservesAsync(DateTime currentDate)
|
||||||
|
{
|
||||||
|
var numberOfLoansUpdated = 0;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var loansToUpdate = await _loanRepository.GetAll().Where(l => l.ExportedReserveDate == null).ToListAsync();
|
||||||
|
var groupedLoanRequests = loansToUpdate.Select(ExportMapper.MapLoanToIndirectLoanForReserve).ToList();
|
||||||
|
var exportResult = await SendBatchListMonetaryTransactionRequests(groupedLoanRequests);
|
||||||
|
|
||||||
|
if (exportResult != null || exportResult.Any())
|
||||||
|
{
|
||||||
|
var loansExported = new List<Loan>();
|
||||||
|
|
||||||
|
loansToUpdate.ForEach(loan =>
|
||||||
|
{
|
||||||
|
var validLoan = exportResult.Where(e => e.AccountNumber.ToString() == loan.LoanNumber).FirstOrDefault();
|
||||||
|
if (validLoan != null && validLoan.WasSuccessful)
|
||||||
|
{
|
||||||
|
loan.ExportedReserveDate = currentDate;
|
||||||
|
numberOfLoansUpdated += 1;
|
||||||
|
loan.Adjustment = 0;
|
||||||
|
loansExported.Add(loan); //update successful loan export with exported date
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.Error($"Failure to export loan reserve account number: {loan.LoanNumber}");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await _loanRepository.UpdateAsync(loansExported);
|
||||||
|
Log.Information($"Exported {numberOfLoansUpdated} reserves");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, "Failure exporting loan reserves.");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
return numberOfLoansUpdated;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> ExportChargebacksAsync(DateTime currentDate)
|
||||||
|
{
|
||||||
|
var numberOfLoansUpdated = 0;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var loansToUpdate = await _loanRepository.GetAll().Where(l => l.ExportedChargebackDate == null && l.PaidLoanDate != null).ToListAsync();
|
||||||
|
var groupedLoanRequests = new List<GroupedMonetaryTransactionRequest>();
|
||||||
|
loansToUpdate.ForEach(loan =>
|
||||||
|
{
|
||||||
|
var accountType = GetMinorAccountType(loan.AccountType);
|
||||||
|
groupedLoanRequests.Add(ExportMapper.MapLoanToIndirectLoanForChargeback(loan, accountType));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
var exportResult = await SendBatchListMonetaryTransactionRequests(groupedLoanRequests);
|
||||||
|
|
||||||
|
if (exportResult != null || exportResult.Any())
|
||||||
|
{
|
||||||
|
var loansExported = new List<Loan>();
|
||||||
|
loansToUpdate.ForEach(loan =>
|
||||||
|
{
|
||||||
|
var accountType = GetMinorAccountType(loan.AccountType);
|
||||||
|
var validLoan = exportResult.Where(e => e.AccountNumber.ToString() == accountType.GeneralLedgerAccountNumber).FirstOrDefault();
|
||||||
|
if (validLoan != null && validLoan.WasSuccessful)
|
||||||
|
{
|
||||||
|
loan.ExportedChargebackDate = currentDate;
|
||||||
|
numberOfLoansUpdated += 1;
|
||||||
|
loan.Adjustment = 0;
|
||||||
|
loansExported.Add(loan); //update successful loan export with exported date
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.Error($"Failure to export loan reserve account number: {loan.LoanNumber}");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await _loanRepository.UpdateAsync(loansExported);
|
||||||
|
Log.Information($"Exported {numberOfLoansUpdated} chargebacks");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.Error("Failure exporting loan chargebacks.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, "Failure exporting loan chargebacks.");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
return numberOfLoansUpdated;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<ImportBoatLoan>> ExportBoatLoansAsync(List<Loan> loans)
|
||||||
|
{
|
||||||
|
var loansExported = new List<ImportBoatLoan>();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var reserveLoans = loans.Where(l => l.ReserveAmount != 0);
|
||||||
|
if (reserveLoans != null || reserveLoans.Any())
|
||||||
|
{
|
||||||
|
var groupedReserveRequests = reserveLoans.Select(ExportMapper.MapLoanToIndirectLoanForReserve).ToList();
|
||||||
|
var exportReserveResult = await SendBatchListMonetaryTransactionRequests(groupedReserveRequests);
|
||||||
|
loansExported.AddRange(MapBoatExportResults(exportReserveResult, reserveLoans.ToList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
var chargebackLoans = loans.Where(l => l.ChargeBack != 0).ToList();
|
||||||
|
if (chargebackLoans != null || chargebackLoans.Any())
|
||||||
|
{
|
||||||
|
var groupedLoanRequests = new List<GroupedMonetaryTransactionRequest>();
|
||||||
|
chargebackLoans.ForEach(loan =>
|
||||||
|
{
|
||||||
|
var accountType = GetMinorAccountType(loan.AccountType);
|
||||||
|
groupedLoanRequests.Add(ExportMapper.MapLoanToIndirectLoanForChargeback(loan, accountType));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
var exportResult = await _coreApiServiceClient.PostMonetaryTransactions(groupedLoanRequests);
|
||||||
|
loansExported.AddRange(MapBoatExportResults(exportResult, chargebackLoans.ToList()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, "Failure exporting boat loans.");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
return loansExported;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> MarkReservesAsExportedAsync(List<Loan> loans, DateTime currentDate)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
loans.ForEach(l =>
|
||||||
|
{
|
||||||
|
l.ExportedReserveDate = currentDate;
|
||||||
|
});
|
||||||
|
|
||||||
|
await _loanRepository.UpdateAsync(loans);
|
||||||
|
Log.Information($"Marked {loans.Count} loan reserves as exported (without exporting)");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, "Failure marking loan reserves as exported.");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
return loans.Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> MarkReservesAndChargebacksAsExportedAsync(List<Loan> loans, DateTime currentDate)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
loans.ForEach(l =>
|
||||||
|
{
|
||||||
|
l.ExportedReserveDate = currentDate;
|
||||||
|
l.ExportedChargebackDate = currentDate;
|
||||||
|
});
|
||||||
|
|
||||||
|
await _loanRepository.UpdateAsync(loans);
|
||||||
|
Log.Information($"Marked {loans.Count} loan reserves and chargebacks as exported (without exporting)");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, "Failure marking loan reserves and chargebacks as exported.");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
return loans.Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ImportBoatLoan> MapBoatExportResults(List<MonetaryTransactionResponse> exportResult, List<Loan> loansToUpdate)
|
||||||
|
{
|
||||||
|
var numberOfLoansUpdated = 0;
|
||||||
|
var loansExported = new List<ImportBoatLoan>();
|
||||||
|
|
||||||
|
if (exportResult != null || exportResult.Any())
|
||||||
|
{
|
||||||
|
loansToUpdate.ForEach(loan =>
|
||||||
|
{
|
||||||
|
var boatLoan = new ImportBoatLoan();
|
||||||
|
string acccountNumber;
|
||||||
|
if (loan.ReserveAmount != 0)
|
||||||
|
{
|
||||||
|
acccountNumber = loan.LoanNumber;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var accountType = GetMinorAccountType(loan.AccountType);
|
||||||
|
acccountNumber = accountType.GeneralLedgerAccountNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
var validLoan = exportResult.Where(e => e.AccountNumber.ToString() == acccountNumber).Any();
|
||||||
|
var validDealer = exportResult.Where(e => e.AccountNumber.ToString() == loan.Dealer.DealerAccountNumber).Any();
|
||||||
|
|
||||||
|
if (validLoan && validDealer)
|
||||||
|
{
|
||||||
|
numberOfLoansUpdated += 1;
|
||||||
|
boatLoan.LoanNumber = loan.LoanNumber;
|
||||||
|
boatLoan.WasSuccessful = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var error = $"Failure to export boat loan account number: {loan.LoanNumber}";
|
||||||
|
boatLoan.LoanNumber = loan.LoanNumber;
|
||||||
|
boatLoan.WasSuccessful = false;
|
||||||
|
boatLoan.ErrorMessage = error;
|
||||||
|
Log.Error(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
loansExported.Add(boatLoan);
|
||||||
|
});
|
||||||
|
|
||||||
|
Log.Information($"Exported {numberOfLoansUpdated} boat loans");
|
||||||
|
}
|
||||||
|
|
||||||
|
return loansExported;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MinorAccountType GetMinorAccountType(string loanAccountType)
|
||||||
|
{
|
||||||
|
var result = _minorAccountTypeRepository.GetMinorAccountType(loanAccountType);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<MonetaryTransactionResponse>> SendBatchListMonetaryTransactionRequests(List<GroupedMonetaryTransactionRequest> groupedLoanRequests)
|
||||||
|
{
|
||||||
|
var result = new List<MonetaryTransactionResponse>();
|
||||||
|
var batchSize = _rmsApiConfig.DefaultBatchSize;
|
||||||
|
|
||||||
|
foreach (var batch in BatchHelper.CreateBatch<GroupedMonetaryTransactionRequest>(groupedLoanRequests, batchSize))
|
||||||
|
{
|
||||||
|
var response = await _coreApiServiceClient.PostMonetaryTransactions(batch.ToList());
|
||||||
|
result.AddRange(response);
|
||||||
|
};
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
+25
@@ -0,0 +1,25 @@
|
|||||||
|
using ReserveManagementSystemLib.Models;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi.Services
|
||||||
|
{
|
||||||
|
public interface IAuditHistoryService
|
||||||
|
{
|
||||||
|
Task<IEnumerable<AuditHistory>> GetAllAsync();
|
||||||
|
|
||||||
|
Task<AuditHistory> FindByIdAsync(int id);
|
||||||
|
|
||||||
|
Task<AuditHistory> AddHistoryAsync(AuditHistory history);
|
||||||
|
|
||||||
|
Task<int> AddAuditHistoriesForNonexistingLoansAsync(List<Loan> loans);
|
||||||
|
|
||||||
|
AuditHistory GetExistingLoanUpdateHistoryAsync(Loan loan, Loan originalLoan);
|
||||||
|
|
||||||
|
AuditHistory GetAuditHistoryForNonexistingClosedLoan(Loan loan);
|
||||||
|
|
||||||
|
AuditHistory GetLoanStatusChangeHistory(Loan loan, string oldStatus, string description);
|
||||||
|
|
||||||
|
Task<int> AddHistoriesAsync(List<AuditHistory> histories);
|
||||||
|
|
||||||
|
Task AddErrorHistoryAsync(string memberNumber, string loanNumber, string description);
|
||||||
|
}
|
||||||
|
}
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
using ReserveManagementSystemLib.Models;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi.Services
|
||||||
|
{
|
||||||
|
public interface IDealerService
|
||||||
|
{
|
||||||
|
Task<IEnumerable<Dealer>> Search(string dealerSearch);
|
||||||
|
|
||||||
|
Task<Dealer> GetDealerByCodeAsync(string dealerCode);
|
||||||
|
|
||||||
|
Task UpdateDealersAsync(List<Dealer> dealers);
|
||||||
|
|
||||||
|
Task UpdateDealersAsync(List<Loan> loans);
|
||||||
|
|
||||||
|
Task<IEnumerable<Dealer>> GetAllDealersAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
using ReserveManagementSystemApi.Models;
|
||||||
|
using ReserveManagementSystemLib.Models;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi.Services
|
||||||
|
{
|
||||||
|
public interface IExportService
|
||||||
|
{
|
||||||
|
Task<int> ExportReservesAsync(DateTime currentDate);
|
||||||
|
|
||||||
|
Task<int> ExportChargebacksAsync(DateTime currentDate);
|
||||||
|
|
||||||
|
Task<List<ImportBoatLoan>> ExportBoatLoansAsync(List<Loan> loans);
|
||||||
|
|
||||||
|
Task<int> MarkReservesAsExportedAsync(List<Loan> loans, DateTime currentDate);
|
||||||
|
|
||||||
|
Task<int> MarkReservesAndChargebacksAsExportedAsync(List<Loan> loans, DateTime currentDate);
|
||||||
|
}
|
||||||
|
}
|
||||||
+28
@@ -0,0 +1,28 @@
|
|||||||
|
using LCU.Library.Internal.CoreApiWrapperModel.CoreModels.IndirectLoan;
|
||||||
|
using ReserveManagementSystemApi.Models;
|
||||||
|
using ReserveManagementSystemLib.Models;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi.Services
|
||||||
|
{
|
||||||
|
public interface IImportReadService
|
||||||
|
{
|
||||||
|
Task<Import> ImportActiveLoansFromDNA(string newerThanDateTime, bool skipExport = false);
|
||||||
|
|
||||||
|
Task<Import> ImportClosedLoansFromDNA(string newerThanDateTime);
|
||||||
|
|
||||||
|
Task<Import> ImportClosedLoansWithUpdatesFromDNA(string newerThanDateTime, bool skipExport);
|
||||||
|
|
||||||
|
Task<Import> ProcessActiveLoanImport(List<IndirectLoanDetail> loanDetails, DateTime currentTime, bool skipExport);
|
||||||
|
|
||||||
|
Task<Import> ProcessClosedLoanImport(List<ClosedIndirectLoan> closedLoans, DateTime currentTime, string newerThanDateTime);
|
||||||
|
|
||||||
|
Task<Import> ProcessClosedLoansWithUpdates(List<IndirectLoanDetail> dnaLoans, DateTime currentTime, bool skipExport);
|
||||||
|
|
||||||
|
Task<Import> ReadNewLoanImportFile(StreamReader importFile, string fileName, DateTime currentTime);
|
||||||
|
|
||||||
|
Task<List<ImportBoatLoan>> ReadBoatLoanImportFile(StreamReader importFile);
|
||||||
|
|
||||||
|
Task<Import> ReadClosedLoanImportFile(StreamReader importFile, string fileName, DateTime currentTime);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
using ReserveManagementSystemLib.Enums;
|
||||||
|
using ReserveManagementSystemLib.Models;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi.Services
|
||||||
|
{
|
||||||
|
public interface IImportService
|
||||||
|
{
|
||||||
|
Task<IEnumerable<Import>> GetAllAsync();
|
||||||
|
|
||||||
|
Task<IEnumerable<Import>> GetRecentAsync(int numberOfImports);
|
||||||
|
|
||||||
|
Task<Import> GetByIdAsync(int id);
|
||||||
|
|
||||||
|
Task<Import> AddImportAsync(Import import);
|
||||||
|
|
||||||
|
Task<Import> UpdateImportAsync(Import import);
|
||||||
|
|
||||||
|
Task<Import> GetLastLoanImportByType(ImportType importType);
|
||||||
|
}
|
||||||
|
}
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
using ReserveManagementSystemLib.Models;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi.Services
|
||||||
|
{
|
||||||
|
public interface ILoanCalculationService
|
||||||
|
{
|
||||||
|
LoanReserve CalculateSingleReserve(Loan loan);
|
||||||
|
|
||||||
|
LoanChargeback CalculateSingleChargeback(Loan loan);
|
||||||
|
|
||||||
|
Loan CalculateLoanReserve(Loan loan, decimal? originalReserve = null, DateTime? originalExportedReserveDate = null);
|
||||||
|
}
|
||||||
|
}
|
||||||
+31
@@ -0,0 +1,31 @@
|
|||||||
|
using ReserveManagementSystemLib.Models;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi.Services
|
||||||
|
{
|
||||||
|
public interface ILoanService
|
||||||
|
{
|
||||||
|
Task<IEnumerable<Loan>> GetAllAsync();
|
||||||
|
|
||||||
|
Task<PaginatedListResponse> GetFilteredAsync(LoanFilter filter);
|
||||||
|
|
||||||
|
Task<Loan> GetByIdAsync(int id);
|
||||||
|
|
||||||
|
Task<LoanReserve> GetLoanReserveAsync(LoanReserveInput input);
|
||||||
|
|
||||||
|
Task<LoanChargeback> GetLoanChargebackAsync(LoanChargebackInput input);
|
||||||
|
|
||||||
|
Task<List<Loan>> SaveLoansAsync(List<Loan> loans);
|
||||||
|
|
||||||
|
Task<List<Loan>> SaveWithChargebackAsync(List<Loan> loans);
|
||||||
|
|
||||||
|
Task<List<Loan>> SaveWithReserveAndChargebackAsync(List<Loan> loans);
|
||||||
|
|
||||||
|
Task<List<string>> SearchMembers(string searchText);
|
||||||
|
|
||||||
|
Task<List<string>> SearchLoanNumbers(string searchText);
|
||||||
|
|
||||||
|
Task<List<string>> SearchApplicationIds(string searchText);
|
||||||
|
|
||||||
|
Task UpdateDealerOriginalBalanceAsync(List<string> accountNumbers);
|
||||||
|
}
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
using ReserveManagementSystemLib.Models;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi.Services
|
||||||
|
{
|
||||||
|
public interface IRmsActiveLoanService
|
||||||
|
{
|
||||||
|
Task HandleRmsActiveImportRequest(RmsActiveImportRequest request);
|
||||||
|
}
|
||||||
|
}
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
namespace ReserveManagementSystemApi.Services
|
||||||
|
{
|
||||||
|
interface IScheduleService
|
||||||
|
{
|
||||||
|
Task RunImportExportActive(CancellationToken cancellationToken);
|
||||||
|
Task RunImportExportClosed(CancellationToken cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
using LCU.Library.Internal.StatusModels.Models;
|
||||||
|
namespace ReserveManagementSystemApi.Services;
|
||||||
|
|
||||||
|
public interface IStatusService
|
||||||
|
{
|
||||||
|
EnvironmentView GetEnviromentView();
|
||||||
|
}
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
using ReserveManagementSystemLib.Models;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi.Services
|
||||||
|
{
|
||||||
|
public interface IVehicleService
|
||||||
|
{
|
||||||
|
|
||||||
|
Task<Vehicle> GetVehicleByLoanIdAsync(int? loanId);
|
||||||
|
}
|
||||||
|
}
|
||||||
+402
@@ -0,0 +1,402 @@
|
|||||||
|
using CsvHelper;
|
||||||
|
using CsvHelper.Configuration;
|
||||||
|
using System.Globalization;
|
||||||
|
using ReserveManagementSystemApi.Helpers;
|
||||||
|
using ReserveManagementSystemApi.Models;
|
||||||
|
using ReserveManagementSystemApi.ServiceClients;
|
||||||
|
using ReserveManagementSystemLib.Enums;
|
||||||
|
using ReserveManagementSystemLib.Helpers;
|
||||||
|
using ReserveManagementSystemLib.Models;
|
||||||
|
using ReserveManagementSystemLib.Configuration;
|
||||||
|
using ReserveManagementSystemApi.Enums;
|
||||||
|
using LCU.Api.Internal.MaidBotLib.Models;
|
||||||
|
using LCU.Library.Internal.CoreApiWrapperModel.CoreModels.IndirectLoan;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi.Services
|
||||||
|
{
|
||||||
|
public class ImportReadService : IImportReadService
|
||||||
|
{
|
||||||
|
private readonly ILoanService _loanService;
|
||||||
|
private readonly IImportService _importService;
|
||||||
|
private readonly IDealerService _dealerService;
|
||||||
|
private readonly IExportService _exportService;
|
||||||
|
private readonly ICoreApiServiceClient _coreApiServiceClient;
|
||||||
|
private readonly RmsApiConfiguration _rmsApiConfig;
|
||||||
|
private ImportHelper _importHelper = new ImportHelper();
|
||||||
|
|
||||||
|
public ImportReadService(ILoanService loanService,
|
||||||
|
IImportService importService,
|
||||||
|
IDealerService dealerService,
|
||||||
|
IExportService exportService,
|
||||||
|
ICoreApiServiceClient coreApiServiceClient,
|
||||||
|
RmsApiConfiguration rmsApiConfig)
|
||||||
|
{
|
||||||
|
_loanService = loanService;
|
||||||
|
_importService = importService;
|
||||||
|
_dealerService = dealerService;
|
||||||
|
_exportService = exportService;
|
||||||
|
_coreApiServiceClient = coreApiServiceClient;
|
||||||
|
_rmsApiConfig = rmsApiConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Import> ImportActiveLoansFromDNA(string newerThanDateTime, bool skipExport = false)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(newerThanDateTime))
|
||||||
|
{
|
||||||
|
Import lastImport = await _importService.GetLastLoanImportByType(ImportType.Active);
|
||||||
|
newerThanDateTime = GetStartDateForNextImport(lastImport);
|
||||||
|
}
|
||||||
|
Log.Information("Get Active Loans By Posted Date is starting.");
|
||||||
|
var dnaLoans = await _coreApiServiceClient.GetIndirectLoansByPostedDate(newerThanDateTime);
|
||||||
|
Log.Information($"Get Active Loans By Posted Date has ended. Found {dnaLoans.Count()} active loan records.");
|
||||||
|
|
||||||
|
Log.Information("Starting ProcessActiveLoanImport");
|
||||||
|
var import = await ProcessActiveLoanImport(dnaLoans, DateTime.Now, skipExport);
|
||||||
|
Log.Information("ProcessActiveLoanImport has ended");
|
||||||
|
|
||||||
|
return import;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Import> ImportClosedLoansFromDNA(string newerThanDateTime = "")
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(newerThanDateTime))
|
||||||
|
{
|
||||||
|
var lastImport = await _importService.GetLastLoanImportByType(ImportType.Closed);
|
||||||
|
newerThanDateTime = GetStartDateForNextImport(lastImport);
|
||||||
|
}
|
||||||
|
var dnaLoans = await _coreApiServiceClient.GetClosedLoansByPostedDate(newerThanDateTime);
|
||||||
|
var import = await ProcessClosedLoanImport(dnaLoans, DateTime.Now, newerThanDateTime);
|
||||||
|
|
||||||
|
return import;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Import> ImportClosedLoansWithUpdatesFromDNA(string newerThanDateTime, bool skipExport)
|
||||||
|
{
|
||||||
|
var dnaLoans = await _coreApiServiceClient.GetClosedLoansWithDetailByClosedDate(newerThanDateTime);
|
||||||
|
var newImport = new Import();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
newImport = await ProcessClosedLoansWithUpdates(dnaLoans, DateTime.Now, skipExport);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, "Failure to import closed loans from DNA.");
|
||||||
|
Log.ForContext(Enum.GetName(typeof(PropertyEnum), PropertyEnum.Group),
|
||||||
|
Enum.GetName(typeof(GroupEnum), GroupEnum.IndirectLending))
|
||||||
|
.Error(ex, $"Reserve Management System Failure. " +
|
||||||
|
$"Error while importing Closed Loans from DNA.");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
return newImport;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Import> ProcessActiveLoanImport(List<IndirectLoanDetail> loanDetails, DateTime currentTime, bool skipExport = false)
|
||||||
|
{
|
||||||
|
var newImport = new Import
|
||||||
|
{
|
||||||
|
ImportType = ImportType.Active.ToString(),
|
||||||
|
StartDate = currentTime
|
||||||
|
};
|
||||||
|
|
||||||
|
newImport = await _importService.AddImportAsync(newImport);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var loans = _importHelper.TransformLoanFromDNA(loanDetails, newImport.ImportId); //Transform import to loan object
|
||||||
|
|
||||||
|
await _dealerService.UpdateDealersAsync(loans);
|
||||||
|
|
||||||
|
var allDealers = await _dealerService.GetAllDealersAsync();
|
||||||
|
loans.ForEach(loan =>
|
||||||
|
{
|
||||||
|
var currentDealer = allDealers.FirstOrDefault(a => a.DealerOrganizationNumber == loan.DealerOrganizationNumber);
|
||||||
|
loan.Dealer = currentDealer; // assign the loan the updated dealer then check validation in save method
|
||||||
|
});
|
||||||
|
|
||||||
|
await SaveLoansExportAndImportAsync(newImport, loans, currentTime, skipExport);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, "Failure to import active loans from DNA.");
|
||||||
|
Log.ForContext(Enum.GetName(typeof(PropertyEnum), PropertyEnum.Group),
|
||||||
|
Enum.GetName(typeof(GroupEnum), GroupEnum.IndirectLending))
|
||||||
|
.Error(ex, $"Reserve Management System Failure. " +
|
||||||
|
$"Error while importing Active Loans from DNA.");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
return newImport;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Import> ProcessClosedLoansWithUpdates(List<IndirectLoanDetail> dnaLoans, DateTime currentTime, bool skipExport)
|
||||||
|
{
|
||||||
|
var closedImport = new Import
|
||||||
|
{
|
||||||
|
ImportType = ImportType.Closed.ToString(),
|
||||||
|
StartDate = currentTime
|
||||||
|
};
|
||||||
|
|
||||||
|
closedImport = await _importService.AddImportAsync(closedImport);
|
||||||
|
var loans = _importHelper.TransformLoanFromDNA(dnaLoans, closedImport.ImportId);
|
||||||
|
|
||||||
|
await _dealerService.UpdateDealersAsync(loans);
|
||||||
|
|
||||||
|
var loansClosed = await _loanService.SaveWithReserveAndChargebackAsync(loans);
|
||||||
|
|
||||||
|
if (!skipExport)
|
||||||
|
{
|
||||||
|
//prevent converted loans from exporting
|
||||||
|
DateTime defaultConvertedPostDate = Convert.ToDateTime(_rmsApiConfig.DefaultConvertedLoanPostDate);
|
||||||
|
var convertedLoansMarkExported = loansClosed.Where(loan => loan.PostedDate < defaultConvertedPostDate && loan.LoanStatus == "Closed").ToList();
|
||||||
|
await _exportService.MarkReservesAsExportedAsync(convertedLoansMarkExported, currentTime);
|
||||||
|
|
||||||
|
//update dealer original balance with only non-converted loans
|
||||||
|
await _exportService.ExportReservesAsync(DateTime.Now);
|
||||||
|
var nonConvertedLoans = loansClosed.Where(loan => loan.PostedDate > defaultConvertedPostDate).ToList();
|
||||||
|
var listAccountNumbers = nonConvertedLoans.Select(loan => loan.LoanNumber).ToList();
|
||||||
|
await _loanService.UpdateDealerOriginalBalanceAsync(listAccountNumbers);
|
||||||
|
|
||||||
|
await _exportService.ExportChargebacksAsync(DateTime.Now);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await _exportService.MarkReservesAndChargebacksAsExportedAsync(loansClosed, DateTime.Now);
|
||||||
|
}
|
||||||
|
|
||||||
|
closedImport.EndDate = DateTime.Now;
|
||||||
|
closedImport.RecordCount = loansClosed.Count;
|
||||||
|
closedImport.RecordsSaved = loansClosed.Count;
|
||||||
|
closedImport.Success = true;
|
||||||
|
|
||||||
|
await _importService.UpdateImportAsync(closedImport);
|
||||||
|
|
||||||
|
return closedImport;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Import> ProcessClosedLoanImport(List<ClosedIndirectLoan> closedLoans, DateTime currentTime, string newerThanDateTime)
|
||||||
|
{
|
||||||
|
List<Loan> loansUpdated;
|
||||||
|
var closedImport = new Import
|
||||||
|
{
|
||||||
|
ImportType = ImportType.Closed.ToString(),
|
||||||
|
StartDate = currentTime
|
||||||
|
};
|
||||||
|
|
||||||
|
closedImport = await _importService.AddImportAsync(closedImport);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
loansUpdated = await CloseLoans(closedLoans, closedImport);
|
||||||
|
var needDetails = loansUpdated.Where(l => l.LoanStatus == LoanStatus.MissingActiveLoan.ToString()).ToList();
|
||||||
|
if (needDetails.Count > 0)
|
||||||
|
{
|
||||||
|
await ImportClosedLoansWithUpdatesFromDNA(newerThanDateTime, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, "Failure to import closed loans from DNA.");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
return closedImport;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Import> ReadNewLoanImportFile(StreamReader importFile, string fileName, DateTime currentTime)
|
||||||
|
{
|
||||||
|
var loansFromImport = new List<ImportNewLoan>();
|
||||||
|
var newImport = new Import
|
||||||
|
{
|
||||||
|
FileName = fileName.Truncate(50),
|
||||||
|
StartDate = currentTime,
|
||||||
|
ImportType = ImportType.Active.ToString()
|
||||||
|
};
|
||||||
|
|
||||||
|
newImport = await _importService.AddImportAsync(newImport);
|
||||||
|
|
||||||
|
var config = new CsvConfiguration(CultureInfo.InvariantCulture)
|
||||||
|
{
|
||||||
|
HasHeaderRecord = false,
|
||||||
|
TrimOptions = TrimOptions.Trim,
|
||||||
|
HeaderValidated = null,
|
||||||
|
MissingFieldFound = null
|
||||||
|
};
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var csv = new CsvReader(importFile, config))
|
||||||
|
{
|
||||||
|
loansFromImport = csv.GetRecords<ImportNewLoan>().ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
var dealers = loansFromImport.Select(l => new Dealer
|
||||||
|
{
|
||||||
|
DealerOrganizationNumber = l.DealerOrganizationNumber
|
||||||
|
})
|
||||||
|
.GroupBy(d => d.DealerOrganizationNumber).First().ToList();
|
||||||
|
|
||||||
|
await _dealerService.UpdateDealersAsync(dealers);
|
||||||
|
|
||||||
|
var loans = _importHelper.TransformNewLoan(loansFromImport, newImport.ImportId); //Transform import to loan object
|
||||||
|
|
||||||
|
await SaveLoansExportAndImportAsync(newImport, loans, currentTime);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error("Failure to read new loan file, message: {0} {1}", ex.Message, ex.StackTrace);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
return newImport;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<ImportBoatLoan>> ReadBoatLoanImportFile(StreamReader importFile)
|
||||||
|
{
|
||||||
|
var loansFromImport = new List<ImportBoatLoan>();
|
||||||
|
var config = new CsvConfiguration(CultureInfo.InvariantCulture)
|
||||||
|
{
|
||||||
|
HasHeaderRecord = false,
|
||||||
|
TrimOptions = TrimOptions.Trim,
|
||||||
|
HeaderValidated = null,
|
||||||
|
MissingFieldFound = null,
|
||||||
|
BadDataFound = null
|
||||||
|
};
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var csv = new CsvReader(importFile, config))
|
||||||
|
{
|
||||||
|
loansFromImport = csv.GetRecords<ImportBoatLoan>().ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
var loans = _importHelper.TransformBoatLoan(loansFromImport);
|
||||||
|
loansFromImport = await ExportBoatLoansAsync(loans);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, "Failure to read boat loan file");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
return loansFromImport;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Import> ReadClosedLoanImportFile(StreamReader importFile, string fileName, DateTime currentTime)
|
||||||
|
{
|
||||||
|
var loansFromImport = new List<ClosedIndirectLoan>();
|
||||||
|
List<Loan> loansUpdated;
|
||||||
|
|
||||||
|
var closedImport = new Import
|
||||||
|
{
|
||||||
|
FileName = fileName.Truncate(50),
|
||||||
|
StartDate = currentTime,
|
||||||
|
ImportType = ImportType.Closed.ToString()
|
||||||
|
};
|
||||||
|
|
||||||
|
closedImport = await _importService.AddImportAsync(closedImport);
|
||||||
|
|
||||||
|
var config = new CsvConfiguration(CultureInfo.InvariantCulture)
|
||||||
|
{
|
||||||
|
HasHeaderRecord = true,
|
||||||
|
TrimOptions = TrimOptions.Trim,
|
||||||
|
PrepareHeaderForMatch = args => args.Header.ToLower()
|
||||||
|
};
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var csv = new CsvReader(importFile, config))
|
||||||
|
{
|
||||||
|
loansFromImport = csv.GetRecords<ClosedIndirectLoan>().ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
loansUpdated = await CloseLoans(loansFromImport, closedImport);
|
||||||
|
Log.Information($"Closed {loansUpdated.Count} loans");
|
||||||
|
await _exportService.ExportChargebacksAsync(DateTime.Now);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error("Failure to read closed loan file, message: {0} {1}", ex.Message, ex.StackTrace);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
return closedImport;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<List<Loan>> CloseLoans(List<ClosedIndirectLoan> loansFromImport, Import closedImport)
|
||||||
|
{
|
||||||
|
var loans = _importHelper.TransformClosedLoans(loansFromImport, closedImport.ImportId).ToList();
|
||||||
|
var loansUpdated = await _loanService.SaveWithChargebackAsync(loans);
|
||||||
|
|
||||||
|
var missingActiveLoans = loansUpdated.Where(l => l.LoanStatus == LoanStatus.MissingActiveLoan.ToString()).ToList();
|
||||||
|
|
||||||
|
await _exportService.ExportChargebacksAsync(DateTime.Now);
|
||||||
|
|
||||||
|
closedImport.EndDate = DateTime.Now;
|
||||||
|
closedImport.RecordCount = loansFromImport.Count;
|
||||||
|
closedImport.RecordsSaved = loansUpdated.Count - missingActiveLoans.Count;
|
||||||
|
closedImport.Success = true;
|
||||||
|
|
||||||
|
await _importService.UpdateImportAsync(closedImport);
|
||||||
|
Log.Information($"Closed {loansUpdated.Count} loans");
|
||||||
|
|
||||||
|
return loansUpdated;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<List<ImportBoatLoan>> ExportBoatLoansAsync(List<Loan> loans, bool skipExport = false)
|
||||||
|
{
|
||||||
|
var boatResults = new List<ImportBoatLoan>();
|
||||||
|
if (!skipExport)
|
||||||
|
{
|
||||||
|
boatResults = await _exportService.ExportBoatLoansAsync(loans);
|
||||||
|
var reserveLoans = loans.Where(l => l.ReserveAmount != 0);
|
||||||
|
var listAccounts = reserveLoans.Select(loan => loan.LoanNumber).ToList();
|
||||||
|
await _loanService.UpdateDealerOriginalBalanceAsync(listAccounts);
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.Information($"Imported {loans.Count} boat loans");
|
||||||
|
return boatResults;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetStartDateForNextImport(Import lastImport)
|
||||||
|
{
|
||||||
|
if (lastImport?.StartDate != null)
|
||||||
|
{
|
||||||
|
return lastImport.StartDate.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture);
|
||||||
|
}
|
||||||
|
return _rmsApiConfig.DefaultImportStartDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SaveLoansExportAndImportAsync(Import import, List<Loan> loans, DateTime currentTime, bool skipExport = false)
|
||||||
|
{
|
||||||
|
var loansImported = await _loanService.SaveLoansAsync(loans);
|
||||||
|
if (!skipExport)
|
||||||
|
{
|
||||||
|
//prevent converted loans from exporting
|
||||||
|
DateTime defaultConvertedPostDate = Convert.ToDateTime(_rmsApiConfig.DefaultConvertedLoanPostDate);
|
||||||
|
var convertedLoansMarkExported = loansImported.Where(loan => loan.PostedDate < defaultConvertedPostDate && loan.LoanStatus == "New").ToList();
|
||||||
|
await _exportService.MarkReservesAsExportedAsync(convertedLoansMarkExported, currentTime);
|
||||||
|
|
||||||
|
//update dealer original balance with only non-converted loans
|
||||||
|
await _exportService.ExportReservesAsync(currentTime);
|
||||||
|
var nonConvertedLoans = loansImported.Where(loan => loan.PostedDate > defaultConvertedPostDate).ToList();
|
||||||
|
var listAccountNumbers = nonConvertedLoans.Select(loan => loan.LoanNumber).ToList();
|
||||||
|
await _loanService.UpdateDealerOriginalBalanceAsync(listAccountNumbers);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await _exportService.MarkReservesAsExportedAsync(loansImported, currentTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.Information($"Imported {loansImported.Count} active loans");
|
||||||
|
import.EndDate = DateTime.Now;
|
||||||
|
import.RecordCount = loansImported.Count;
|
||||||
|
import.RecordsSaved = loansImported.Count;
|
||||||
|
import.Success = true;
|
||||||
|
|
||||||
|
await _importService.UpdateImportAsync(import);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+89
@@ -0,0 +1,89 @@
|
|||||||
|
using ReserveManagementSystemLib.Enums;
|
||||||
|
using ReserveManagementSystemLib.Models;
|
||||||
|
using ReserveManagementSystemLib.Repositories;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi.Services
|
||||||
|
{
|
||||||
|
public class ImportService: IImportService
|
||||||
|
{
|
||||||
|
private readonly IImportRepository _importRepository;
|
||||||
|
|
||||||
|
public ImportService(IImportRepository importRepository)
|
||||||
|
{
|
||||||
|
_importRepository = importRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<Import>> GetAllAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await _importRepository.GetAll().OrderByDescending(imp => imp.StartDate).ToListAsync();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, "Failure retrieving imports.");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Import> GetLastLoanImportByType(ImportType importType)
|
||||||
|
{
|
||||||
|
Import import;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
import = await _importRepository.GetLastLoanDnaImportByType(importType).FirstOrDefaultAsync();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, $"Failure retrieving last import.");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
return import;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<Import>> GetRecentAsync(int numberOfImports)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await _importRepository.GetAll().OrderByDescending(imp => imp.StartDate).Take(numberOfImports).ToListAsync();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, "Failure retrieving imports.");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Import> GetByIdAsync(int id)
|
||||||
|
{
|
||||||
|
Import import;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
import = await _importRepository.FindByIdAsync(id);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, $"Failure retrieving import with id {id}.");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (import == null)
|
||||||
|
{
|
||||||
|
throw new Exception($"Import with id {id} not found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return import;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Import> AddImportAsync(Import newImport)
|
||||||
|
{
|
||||||
|
return await _importRepository.AddImportAsync(newImport);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Import> UpdateImportAsync(Import import)
|
||||||
|
{
|
||||||
|
return await _importRepository.UpdateImportAsync(import);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+314
@@ -0,0 +1,314 @@
|
|||||||
|
using ReserveManagementSystemApi.Helpers;
|
||||||
|
using ReserveManagementSystemLib.Models;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi.Services
|
||||||
|
{
|
||||||
|
public class LoanCalculationService : ILoanCalculationService
|
||||||
|
{
|
||||||
|
private readonly LoanCalculationHelper _loanCalculationHelper;
|
||||||
|
private readonly BoatLoanCalculationHelper _boatLoanCalculationHelper;
|
||||||
|
private CalculationConfig _calculationConfig;
|
||||||
|
|
||||||
|
public LoanCalculationService()
|
||||||
|
{
|
||||||
|
_loanCalculationHelper = new LoanCalculationHelper();
|
||||||
|
_boatLoanCalculationHelper = new BoatLoanCalculationHelper();
|
||||||
|
}
|
||||||
|
|
||||||
|
public LoanReserve CalculateSingleReserve(Loan loan)
|
||||||
|
{
|
||||||
|
var result = new LoanReserve();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_calculationConfig = new CalculationConfig(loan);
|
||||||
|
if (!loan.IsBoatLoan(loan))
|
||||||
|
{
|
||||||
|
result = ReserveCalculation(loan);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = BoatReserveCalculation(loan);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error("Failure to Calculate Loan: {0} {1}", e.Message, e.StackTrace);
|
||||||
|
result.ReserveTypeMessage = "Exception while calculating reserve";
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LoanChargeback CalculateSingleChargeback(Loan loan)
|
||||||
|
{
|
||||||
|
var result = new LoanChargeback();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_calculationConfig = new CalculationConfig(loan);
|
||||||
|
if (!loan.IsBoatLoan(loan))
|
||||||
|
{
|
||||||
|
result = ChargebackCalculation(loan);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = BoatChargebackCalculation(loan);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error("Failure to Calculate Chargeback: {0} {1}", e.Message, e.StackTrace);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Loan CalculateLoanReserve(Loan loan, decimal? originalReserve = null, DateTime? originalExportReserveDate = null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_calculationConfig = new CalculationConfig(loan);
|
||||||
|
var loanReserve = new LoanReserve();
|
||||||
|
if (!loan.IsBoatLoan(loan))
|
||||||
|
{
|
||||||
|
loanReserve = ReserveCalculation(loan);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
loanReserve = BoatReserveCalculation(loan);
|
||||||
|
}
|
||||||
|
|
||||||
|
loan = AssignReserveValues(loan, loanReserve);
|
||||||
|
if (originalReserve.HasValue)
|
||||||
|
{
|
||||||
|
CalculateReserveAdjustment(loan, originalReserve, originalExportReserveDate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error("Failure to Calculate Reserve: {0} {1}", e.Message, e.StackTrace);
|
||||||
|
loan.ReserveMessage = "Exception while calculating reserve";
|
||||||
|
}
|
||||||
|
|
||||||
|
return loan;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CalculateReserveAdjustment(Loan loan, decimal? originalReserve, DateTime? originalExportReserveDate)
|
||||||
|
{
|
||||||
|
var updatedReserveSaved = Math.Round(loan.ReserveAmount, 4, MidpointRounding.AwayFromZero); //this represents the amount saved to DB
|
||||||
|
var updatedReserveRounded = Math.Round(updatedReserveSaved, 2, MidpointRounding.AwayFromZero);
|
||||||
|
var originalReserveRounded = Math.Round(originalReserve.Value, 2, MidpointRounding.AwayFromZero);
|
||||||
|
|
||||||
|
if (updatedReserveRounded != originalReserveRounded)
|
||||||
|
{
|
||||||
|
loan.Adjustment = (updatedReserveRounded - originalReserveRounded);
|
||||||
|
loan.ExportedReserveDate = null; //we only want to remove last export date if reserve amount changed
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
loan.ExportedReserveDate = originalExportReserveDate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private LoanReserve ReserveCalculation(Loan loanData)
|
||||||
|
{
|
||||||
|
var loanReserve = new LoanReserve();
|
||||||
|
_calculationConfig.BuyFinanceCharge = _loanCalculationHelper.FinanceCharge(_calculationConfig.LoanData().Term, loanData.LoanAmount, loanData.BuyRate); // Finance charge using BuyRate%
|
||||||
|
_calculationConfig.ContractFinanceCharge = _loanCalculationHelper.FinanceCharge(_calculationConfig.LoanData().Term, loanData.LoanAmount, loanData.ContractRate); // Finance charge using ContractRate%
|
||||||
|
|
||||||
|
if (loanData.ContractRate < loanData.BuyRate)
|
||||||
|
{
|
||||||
|
//Calculate Buy Down.
|
||||||
|
return _loanCalculationHelper.CalculateBuyDown(_calculationConfig);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Calculate Reserve Amount for all other loans.
|
||||||
|
if ((double)loanData.ContractRate == (double)loanData.BuyRate)
|
||||||
|
{
|
||||||
|
loanReserve = _loanCalculationHelper.CalculateNoMarkup(_calculationConfig);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
loanReserve = _loanCalculationHelper.CalculateStandardMarkup(_calculationConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Assign any Flat Fees if applicable
|
||||||
|
return _loanCalculationHelper.AssignFlatFee(loanReserve, _calculationConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private LoanReserve BoatReserveCalculation(Loan loanData)
|
||||||
|
{
|
||||||
|
if (loanData.ContractRate < loanData.BuyRate)
|
||||||
|
{
|
||||||
|
_calculationConfig.BuyFinanceCharge = _loanCalculationHelper.FinanceCharge(_calculationConfig.LoanData().Term, loanData.LoanAmount, loanData.BuyRate); // Finance charge using BuyRate%
|
||||||
|
_calculationConfig.ContractFinanceCharge = _loanCalculationHelper.FinanceCharge(_calculationConfig.LoanData().Term, loanData.LoanAmount, loanData.ContractRate); // Finance charge using ContractRate%
|
||||||
|
|
||||||
|
return _loanCalculationHelper.CalculateBuyDown(_calculationConfig);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Calculate Reserve Amount for all other loans.
|
||||||
|
return _boatLoanCalculationHelper.CalculateStandardMarkup(_calculationConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Loan AssignReserveValues(Loan loan, LoanReserve loanReserve)
|
||||||
|
{
|
||||||
|
loan.ReserveAmount = loanReserve.ReserveAmount;
|
||||||
|
loan.ReserveMessage = loanReserve.ReserveTypeMessage;
|
||||||
|
loan.Term = _calculationConfig.LoanData().Term;
|
||||||
|
loan.FlatFeePaid = loanReserve.FlatFeePaid;
|
||||||
|
|
||||||
|
return loan;
|
||||||
|
}
|
||||||
|
|
||||||
|
private LoanChargeback ChargebackCalculation(Loan loanData)
|
||||||
|
{
|
||||||
|
if (loanData.ReserveAmount < 0 || loanData.ReserveMessage != null && loanData.ReserveMessage.ToUpper().Contains("BUYDOWN"))
|
||||||
|
{
|
||||||
|
return SetBuyDownChargeback(loanData);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loanData.LoanType?.ChargebackMethod == "S")
|
||||||
|
{
|
||||||
|
return CalculateBBLoans(loanData);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return CalculateLoanWithChargebackDate(loanData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private LoanChargeback BoatChargebackCalculation(Loan loanData)
|
||||||
|
{
|
||||||
|
if (loanData.ReserveAmount < 0 || loanData.ReserveMessage != null && loanData.ReserveMessage.ToUpper().Contains("BUYDOWN"))
|
||||||
|
{
|
||||||
|
return SetBuyDownChargeback(loanData);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return CalculateBoatLoanWithChargebackDate(loanData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private LoanChargeback CalculateBoatLoanWithChargebackDate(Loan loanData)
|
||||||
|
{
|
||||||
|
var numOfChargebackPayments = loanData.Term <= 63 ? 6 : 12; //term is 63 or less chargeback date is 6 monthly payments, otherwise 12
|
||||||
|
var lastChargebackDate = _boatLoanCalculationHelper.GetLastChargebackDate(loanData.FirstPmtDate, numOfChargebackPayments);
|
||||||
|
|
||||||
|
if (loanData.PaidLoanDate > lastChargebackDate)
|
||||||
|
{
|
||||||
|
return new LoanChargeback
|
||||||
|
{
|
||||||
|
ChargebackAmount = 0M,
|
||||||
|
ChargebackTypeMessage = loanData.ReserveAmount == 0 ? "No Reserve - No Chargeback" : "Paid After Chargeback Date",
|
||||||
|
RemainingMonthsAtClose = (byte)_loanCalculationHelper.GetRemainingMonths(loanData)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return ChargebackWithRemainingMonths(loanData);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private LoanChargeback CalculateLoanWithChargebackDate(Loan loanData)
|
||||||
|
{
|
||||||
|
var numOfChargebackPayments = loanData.LoanType?.NoChargebackPayments ?? 3;
|
||||||
|
var numOfChargebackDays = loanData.LoanType?.NoChargebackDays ?? 90;
|
||||||
|
var lastChargebackDate = _loanCalculationHelper.GetLastChargebackDate(loanData.LoanDate, loanData.FirstPmtDate, numOfChargebackPayments, numOfChargebackDays);
|
||||||
|
|
||||||
|
if (loanData.PaidLoanDate > lastChargebackDate)
|
||||||
|
{
|
||||||
|
return new LoanChargeback
|
||||||
|
{
|
||||||
|
ChargebackAmount = 0M,
|
||||||
|
ChargebackTypeMessage = loanData.ReserveAmount == 0 ? "No Reserve - No Chargeback" : "Paid After Chargeback Date",
|
||||||
|
RemainingMonthsAtClose = (byte)_loanCalculationHelper.GetRemainingMonths(loanData)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return ChargebackWithRemainingMonths(loanData);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private LoanChargeback ChargebackWithRemainingMonths(Loan loanData)
|
||||||
|
{
|
||||||
|
int remainingMonths = 0;
|
||||||
|
string message = "Paid On or Before Chargeback Date";
|
||||||
|
|
||||||
|
remainingMonths = _loanCalculationHelper.GetRemainingMonths(loanData);
|
||||||
|
|
||||||
|
return new LoanChargeback
|
||||||
|
{
|
||||||
|
//this needs to be the original term formula
|
||||||
|
ChargebackAmount = _loanCalculationHelper.CalculateChargeback(loanData.ReserveAmount, loanData.Term, remainingMonths),
|
||||||
|
ChargebackTypeMessage = loanData.ReserveAmount == 0 ? "No Reserve - No Chargeback" : message,
|
||||||
|
RemainingMonthsAtClose = (byte)remainingMonths
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private LoanChargeback ChargebackWithRemainingMonthsBB(Loan loanData)
|
||||||
|
{
|
||||||
|
int remainingMonths = 0;
|
||||||
|
string message = "Paid After Chargeback Date";
|
||||||
|
|
||||||
|
//add chargeback date for BB Loans
|
||||||
|
var chargeBackDate = loanData.FirstPmtDate.AddMonths(loanData.Term - 1);
|
||||||
|
|
||||||
|
if (loanData.PaidLoanDate <= chargeBackDate)
|
||||||
|
{
|
||||||
|
remainingMonths = _loanCalculationHelper.GetRemainingMonths(loanData);
|
||||||
|
if (remainingMonths <= 0)
|
||||||
|
{
|
||||||
|
return new LoanChargeback
|
||||||
|
{
|
||||||
|
ChargebackAmount = 0M,
|
||||||
|
ChargebackTypeMessage = message,
|
||||||
|
RemainingMonthsAtClose = 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
message = "Paid On or Before Chargeback Date";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new LoanChargeback
|
||||||
|
{
|
||||||
|
ChargebackAmount = _loanCalculationHelper.CalculateChargeback(loanData.ReserveAmount, loanData.Term, remainingMonths),
|
||||||
|
ChargebackTypeMessage = message,
|
||||||
|
RemainingMonthsAtClose = (byte)remainingMonths
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private LoanChargeback CalculateBBLoans(Loan loanData)
|
||||||
|
{
|
||||||
|
if (loanData.ReserveAmount != 0)
|
||||||
|
{
|
||||||
|
return ChargebackWithRemainingMonthsBB(loanData);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new LoanChargeback
|
||||||
|
{
|
||||||
|
ChargebackAmount = 0M,
|
||||||
|
ChargebackTypeMessage = "No Reserve - No Chargeback",
|
||||||
|
RemainingMonthsAtClose = (byte)_loanCalculationHelper.GetRemainingMonths(loanData)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private LoanChargeback SetBuyDownChargeback(Loan loanData)
|
||||||
|
{
|
||||||
|
//Buydown scenarios will not calculate a chargeback and return a message indicating this.
|
||||||
|
return new LoanChargeback
|
||||||
|
{
|
||||||
|
ChargebackAmount = 0M,
|
||||||
|
ChargebackTypeMessage = "Buy Down Reserve - No Chargeback",
|
||||||
|
RemainingMonthsAtClose = (byte)_loanCalculationHelper.GetRemainingMonths(loanData)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+448
@@ -0,0 +1,448 @@
|
|||||||
|
using System.Linq.Dynamic.Core;
|
||||||
|
using ReserveManagementSystemApi.Enums;
|
||||||
|
using ReserveManagementSystemApi.ServiceClients;
|
||||||
|
using ReserveManagementSystemLib.Helpers;
|
||||||
|
using ReserveManagementSystemLib.Models;
|
||||||
|
using ReserveManagementSystemLib.Repositories;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi.Services
|
||||||
|
{
|
||||||
|
public class LoanService : ILoanService
|
||||||
|
{
|
||||||
|
private readonly ILoanRepository _loanRepository;
|
||||||
|
private readonly ILoanTypeRepository _loanTypeRepository;
|
||||||
|
private readonly IAuditHistoryService _auditHistoryService;
|
||||||
|
private ILoanCalculationService _loanCalculationService;
|
||||||
|
private const double MonthInDays = 30.4375;
|
||||||
|
|
||||||
|
private readonly ICoreApiServiceClient _coreApiServiceClient;
|
||||||
|
|
||||||
|
public LoanService(ILoanRepository loanRepository, ILoanTypeRepository loanTypeRepository, IAuditHistoryService auditHistoryService, ICoreApiServiceClient coreApiServiceClient)
|
||||||
|
{
|
||||||
|
_loanRepository = loanRepository;
|
||||||
|
_loanTypeRepository = loanTypeRepository;
|
||||||
|
_auditHistoryService = auditHistoryService;
|
||||||
|
_coreApiServiceClient = coreApiServiceClient;
|
||||||
|
_loanCalculationService = new LoanCalculationService();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<Loan>> GetAllAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await _loanRepository.GetAll().OrderByDescending(x => x.ImportId).ThenBy(y => y.MemberNumber).ThenBy(z => z.LoanNumber).ToListAsync();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, "Failure retrieving loans.");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Loan> GetByIdAsync(int id)
|
||||||
|
{
|
||||||
|
Loan loan;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
loan = await _loanRepository.FindByIdAsync(id);
|
||||||
|
if (loan != null)
|
||||||
|
{
|
||||||
|
loan.ValidationErrors = ValidationHelper.SetValidationErrors(loan);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, $"Failure retrieving loan with id {id}.");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loan == null)
|
||||||
|
{
|
||||||
|
throw new Exception($"Loan with id {id} not found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return loan;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<PaginatedListResponse> GetFilteredAsync(LoanFilter filter)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
IQueryable<Loan> loans;
|
||||||
|
PaginatedListResponse pagedListResponse = new PaginatedListResponse();
|
||||||
|
var query = _loanRepository.GetAll();
|
||||||
|
var filteredQuery = filter.ApplyFilter(query);
|
||||||
|
|
||||||
|
List<string> listOfFieldNames = typeof(Loan).GetProperties().Select(f => f.Name).ToList();
|
||||||
|
listOfFieldNames.AddRange(typeof(Dealer).GetProperties().Select(f => $"Dealer.{f.Name}").ToList());
|
||||||
|
listOfFieldNames.AddRange(typeof(Vehicle).GetProperties().Select(f => $"Vehicle.{f.Name}").ToList());
|
||||||
|
|
||||||
|
var result = listOfFieldNames.Where(n => n == filter.SortField).FirstOrDefault();
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(filter.SortField) && result != null)
|
||||||
|
{
|
||||||
|
loans = filteredQuery.OrderBy($"{filter.SortField} {filter.SortDirection}, ImportId desc, MemberNumber, LoanNumber");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
loans = filteredQuery.OrderBy($"ImportId desc, MemberNumber, LoanNumber");
|
||||||
|
}
|
||||||
|
pagedListResponse = await PaginatedListResponse.CreateListAsync(loans, filter.PageIndex, filter.MaxRecordsPerPage, filter.MaxPagesPerRange);
|
||||||
|
return pagedListResponse;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, "Failure retrieving loans with filter.");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<LoanReserve> GetLoanReserveAsync(LoanReserveInput input)
|
||||||
|
{
|
||||||
|
var result = new LoanReserve();
|
||||||
|
var loan = new Loan
|
||||||
|
{
|
||||||
|
LoanDate = input.LoanDate,
|
||||||
|
FirstPmtDate = input.FirstPmtDate,
|
||||||
|
LoanAmount = input.LoanAmount,
|
||||||
|
LoanTypeId = input.LoanType,
|
||||||
|
BuyRate = input.BuyRate,
|
||||||
|
ContractRate = input.ContractRate,
|
||||||
|
Term = (int)Math.Round(Convert.ToDecimal(input.OriginalTermInDays) / (decimal)MonthInDays, 0),
|
||||||
|
AccountType = input.AccountType
|
||||||
|
};
|
||||||
|
|
||||||
|
loan.LoanType = await _loanTypeRepository.GetLoanTypeAsync(loan.LoanTypeId);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_loanCalculationService = new LoanCalculationService();
|
||||||
|
result = _loanCalculationService.CalculateSingleReserve(loan);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error("Failure to Calculate Loan Reserve: {0} {1}", e.Message, e.StackTrace);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<LoanChargeback> GetLoanChargebackAsync(LoanChargebackInput input)
|
||||||
|
{
|
||||||
|
var result = new LoanChargeback();
|
||||||
|
var loan = new Loan
|
||||||
|
{
|
||||||
|
LoanDate = input.LoanDate,
|
||||||
|
FirstPmtDate = input.FirstPmtDate,
|
||||||
|
FinalPmtDate = input.FinalPmtDate,
|
||||||
|
LoanTypeId = input.LoanType,
|
||||||
|
ReserveAmount = input.ReserveAmount,
|
||||||
|
PaidLoanDate = input.PaidLoanDate,
|
||||||
|
Term = input.Term,
|
||||||
|
AccountType = input.AccountType
|
||||||
|
};
|
||||||
|
|
||||||
|
loan.LoanType = await _loanTypeRepository.GetLoanTypeAsync(loan.LoanTypeId);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result = _loanCalculationService.CalculateSingleChargeback(loan);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error("Failure to Calculate Loan Chargeback: {0} {1}", e.Message, e.StackTrace);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<Loan>> SaveLoansAsync(List<Loan> loans)
|
||||||
|
{
|
||||||
|
var loansToAddOrUpdate = new List<Loan>();
|
||||||
|
var historyRecords = new List<AuditHistory>();
|
||||||
|
var loanTypes = await _loanTypeRepository.GetLoanTypesAsync();
|
||||||
|
var numberOfLoansToUpdateReserve = 0;
|
||||||
|
var numberOfLoansToAdd = 0;
|
||||||
|
var numberOfLoansToUpdate = 0;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Log.Information($"Have {loans.Count} loans to add or update");
|
||||||
|
loans.ForEach(loan =>
|
||||||
|
{
|
||||||
|
var validationErrors = ValidationHelper.SetValidationErrors(loan);
|
||||||
|
loan.ActionRequired = validationErrors.Count > 0;
|
||||||
|
loan.LoanType = loanTypes.FirstOrDefault(x => x.LoanTypeId == loan.LoanTypeId);
|
||||||
|
var originalLoan = _loanRepository.GetAll().FirstOrDefault(l => l.LoanNumber == loan.LoanNumber);
|
||||||
|
|
||||||
|
if (originalLoan != null) //have an updated loan
|
||||||
|
{
|
||||||
|
if (!loan.Equals(originalLoan) || (loan.Vehicle != null && !loan.Vehicle.Equals(originalLoan.Vehicle)))
|
||||||
|
{
|
||||||
|
numberOfLoansToUpdate++;
|
||||||
|
loan.LoanId = originalLoan.LoanId;
|
||||||
|
var needToUpdateReserve = !loan.HasSameReserve(originalLoan);
|
||||||
|
if (needToUpdateReserve)
|
||||||
|
{
|
||||||
|
numberOfLoansToUpdateReserve++;
|
||||||
|
loan = _loanCalculationService.CalculateLoanReserve(loan, originalLoan.ReserveAmount, originalLoan.ExportedReserveDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
historyRecords.Add(_auditHistoryService.GetExistingLoanUpdateHistoryAsync(loan, originalLoan));
|
||||||
|
CopyFromDnaLoanToOriginalLoan(loan, originalLoan, needToUpdateReserve);
|
||||||
|
|
||||||
|
originalLoan.LoanStatus = LoanStatus.Updated.ToString();
|
||||||
|
|
||||||
|
loansToAddOrUpdate.Add(originalLoan);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else //have a new loan
|
||||||
|
{
|
||||||
|
numberOfLoansToAdd++;
|
||||||
|
loan = _loanCalculationService.CalculateLoanReserve(loan);
|
||||||
|
|
||||||
|
loan.Dealer = null;
|
||||||
|
loan.LoanStatus = LoanStatus.New.ToString();
|
||||||
|
loansToAddOrUpdate.Add(loan);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Log.Information($"{numberOfLoansToUpdate} loans were updated");
|
||||||
|
Log.Information($"{numberOfLoansToUpdateReserve} loans had reserve recalculated");
|
||||||
|
Log.Information($"{numberOfLoansToAdd} loans were added");
|
||||||
|
|
||||||
|
if (loansToAddOrUpdate.Any())
|
||||||
|
{
|
||||||
|
await _loanRepository.UpdateAsync(loansToAddOrUpdate);
|
||||||
|
}
|
||||||
|
if (historyRecords.Any())
|
||||||
|
{
|
||||||
|
await _auditHistoryService.AddHistoriesAsync(historyRecords);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error("Failure to Save Loans: {0} {1}", e.Message, e.StackTrace);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
return loansToAddOrUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<Loan>> SaveWithChargebackAsync(List<Loan> loans)
|
||||||
|
{
|
||||||
|
var historiesForClosedLoans = new List<AuditHistory>();
|
||||||
|
var historiesForLoansNotFound = new List<AuditHistory>();
|
||||||
|
var loansToClose = new List<Loan>();
|
||||||
|
var description = "Importing closed loan changed loan status";
|
||||||
|
loans.ForEach(loan =>
|
||||||
|
{
|
||||||
|
var originalLoan = _loanRepository.GetAllWithoutDealer().FirstOrDefault(l => l.LoanNumber == loan.LoanNumber);
|
||||||
|
|
||||||
|
if (originalLoan != null) //have an updated loan
|
||||||
|
{
|
||||||
|
if (!originalLoan.PaidLoanDate.HasValue || originalLoan.PaidLoanDate != loan.PaidLoanDate)
|
||||||
|
{
|
||||||
|
var oldStatus = originalLoan.LoanStatus;
|
||||||
|
originalLoan.PaidLoanDate = loan.PaidLoanDate;
|
||||||
|
originalLoan.ImportId = loan.ImportId;
|
||||||
|
var chargebackResult = _loanCalculationService.CalculateSingleChargeback(originalLoan);
|
||||||
|
|
||||||
|
AssignChargebackResult(originalLoan, chargebackResult);
|
||||||
|
|
||||||
|
historiesForClosedLoans.Add(_auditHistoryService.GetLoanStatusChangeHistory(originalLoan, oldStatus, description));
|
||||||
|
|
||||||
|
loansToClose.Add(originalLoan);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else //active loan not found to close
|
||||||
|
{
|
||||||
|
//set this temporary status to flag selecting original loan with details in order to calculate both reserve and chargeback
|
||||||
|
loan.LoanStatus = LoanStatus.MissingActiveLoan.ToString();
|
||||||
|
loansToClose.Add(loan);
|
||||||
|
historiesForLoansNotFound.Add(_auditHistoryService.GetAuditHistoryForNonexistingClosedLoan(loan));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await _auditHistoryService.AddHistoriesAsync(historiesForClosedLoans);
|
||||||
|
await _auditHistoryService.AddHistoriesAsync(historiesForLoansNotFound);
|
||||||
|
await _loanRepository.UpdateAsync(loansToClose.Where(l => l.LoanStatus != "MissingActiveLoan"));
|
||||||
|
return loansToClose;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>This method was used for one time import, we want to save the original reserve info for an already closed loan pre Go-Live. </summary>
|
||||||
|
public async Task<List<Loan>> SaveWithReserveAndChargebackAsync(List<Loan> loans)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var loanTypes = await _loanTypeRepository.GetLoanTypesAsync();
|
||||||
|
var historiesForClosedLoans = new List<AuditHistory>();
|
||||||
|
var loansToClose = new List<Loan>();
|
||||||
|
var description = "Importing closed loan changed loan status";
|
||||||
|
|
||||||
|
loans.ForEach(loan =>
|
||||||
|
{
|
||||||
|
var originalLoan = _loanRepository.GetAllWithoutDealer().FirstOrDefault(l => l.LoanNumber == loan.LoanNumber);
|
||||||
|
|
||||||
|
if (originalLoan == null)
|
||||||
|
{
|
||||||
|
loan.LoanType = loanTypes.FirstOrDefault(x => x.LoanTypeId == loan.LoanTypeId);
|
||||||
|
loan = _loanCalculationService.CalculateLoanReserve(loan, null, null);
|
||||||
|
var chargebackResult = _loanCalculationService.CalculateSingleChargeback(loan);
|
||||||
|
AssignChargebackResult(loan, chargebackResult);
|
||||||
|
loansToClose.Add(loan);
|
||||||
|
historiesForClosedLoans.Add(_auditHistoryService.GetLoanStatusChangeHistory(loan, "", description));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await _auditHistoryService.AddHistoriesAsync(historiesForClosedLoans);
|
||||||
|
await _loanRepository.UpdateAsync(loansToClose);
|
||||||
|
|
||||||
|
return loansToClose;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex.Message);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<string>> SearchMembers(string searchText)
|
||||||
|
{
|
||||||
|
var memberNumbers = new List<string>();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
memberNumbers = await _loanRepository.GetAll().Where(x => x.MemberNumber.StartsWith(searchText))
|
||||||
|
.Select(y => y.MemberNumber)
|
||||||
|
.Distinct()
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, "Failure retrieving list of members.");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
return memberNumbers.OrderBy(x => long.Parse(x)).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<string>> SearchLoanNumbers(string searchText)
|
||||||
|
{
|
||||||
|
var loanNumbers = new List<string>();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
loanNumbers = await _loanRepository.GetAll().Where(x => x.LoanNumber.StartsWith(searchText))
|
||||||
|
.Select(x => x.LoanNumber)
|
||||||
|
.Distinct()
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, "Failure retrieving list of loan numbers.");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
return loanNumbers.OrderBy(x => long.Parse(x)).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<string>> SearchApplicationIds(string searchText)
|
||||||
|
{
|
||||||
|
var applicationIds = new List<string>();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
applicationIds = await _loanRepository.GetAll().Where(x => x.ApplicationId.StartsWith(searchText))
|
||||||
|
.Select(x => x.ApplicationId)
|
||||||
|
.Distinct()
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, "Failure retrieving list of application ids.");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
return applicationIds.OrderBy(x => long.Parse(x)).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UpdateDealerOriginalBalanceAsync(List<string> accountNumbers)
|
||||||
|
{
|
||||||
|
foreach(var account in accountNumbers)
|
||||||
|
{
|
||||||
|
var exportResult = await _coreApiServiceClient.PutDealerOriginalBalance(account);
|
||||||
|
|
||||||
|
if (exportResult != null)
|
||||||
|
{
|
||||||
|
foreach (var result in exportResult)
|
||||||
|
if (!string.IsNullOrEmpty(result.ErrorMessage))
|
||||||
|
{
|
||||||
|
Log.Error($"Failure to update dealer original balance loan: {result.AccountNumber} {result.ErrorMessage} ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else //if nothing is returned all updates succeeded
|
||||||
|
{
|
||||||
|
Log.Information($"Update to dealers original balances completed successfully");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AssignChargebackResult(Loan loan, LoanChargeback chargebackResult, bool skipExport = false)
|
||||||
|
{
|
||||||
|
loan.ChargeBack = Math.Round(chargebackResult.ChargebackAmount, 4);
|
||||||
|
loan.ChargebackMessage = chargebackResult.ChargebackTypeMessage;
|
||||||
|
loan.RemainingMonthsAtClose = chargebackResult.RemainingMonthsAtClose;
|
||||||
|
loan.ActionRequired = false;
|
||||||
|
|
||||||
|
//if skipping export then loan will already have ExportedChargebackDate set
|
||||||
|
loan.ExportedChargebackDate = skipExport ? loan.ExportedChargebackDate : null;
|
||||||
|
loan.LoanStatus = LoanStatus.Closed.ToString();
|
||||||
|
loan.Dealer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CopyFromDnaLoanToOriginalLoan(Loan loan, Loan originalLoan, bool needToUpdateReserve)
|
||||||
|
{
|
||||||
|
originalLoan.ActionRequired = loan.ActionRequired;
|
||||||
|
originalLoan.ImportId = loan.ImportId;
|
||||||
|
originalLoan.MemberNumber = loan.MemberNumber;
|
||||||
|
originalLoan.MemberFirstName = loan.MemberFirstName;
|
||||||
|
originalLoan.MemberInitial = loan.MemberInitial;
|
||||||
|
originalLoan.MemberLastName = loan.MemberLastName;
|
||||||
|
originalLoan.DealerOrganizationNumber = loan.DealerOrganizationNumber;
|
||||||
|
originalLoan.LoanDate = loan.LoanDate;
|
||||||
|
originalLoan.PostedDate = loan.PostedDate;
|
||||||
|
originalLoan.FirstPmtDate = loan.FirstPmtDate;
|
||||||
|
originalLoan.FinalPmtDate = loan.FinalPmtDate;
|
||||||
|
originalLoan.LoanAmount = loan.LoanAmount;
|
||||||
|
originalLoan.BuyRate = loan.BuyRate;
|
||||||
|
originalLoan.ContractRate = loan.ContractRate;
|
||||||
|
originalLoan.MonthlyPmt = loan.MonthlyPmt;
|
||||||
|
originalLoan.LoanTypeId = loan.LoanTypeId;
|
||||||
|
originalLoan.ApplicationId = loan.ApplicationId;
|
||||||
|
//suppressing these insurance updates until DNA has correct value
|
||||||
|
//originalLoan.Warranty = loan.Warranty;
|
||||||
|
//originalLoan.Gap = loan.Gap;
|
||||||
|
originalLoan.CreditLife = loan.CreditLife;
|
||||||
|
originalLoan.CreditDisability = loan.CreditDisability;
|
||||||
|
//originalLoan.Mbp = loan.Mbp;
|
||||||
|
originalLoan.AccountType = loan.AccountType;
|
||||||
|
|
||||||
|
if (originalLoan.Vehicle != null)
|
||||||
|
{
|
||||||
|
originalLoan.Vehicle.VINNumber = loan.Vehicle?.VINNumber;
|
||||||
|
originalLoan.Vehicle.Make = loan.Vehicle?.Make;
|
||||||
|
originalLoan.Vehicle.Model = loan.Vehicle?.Model;
|
||||||
|
originalLoan.Vehicle.Mileage = loan.Vehicle?.Mileage ?? 0;
|
||||||
|
originalLoan.Vehicle.Year = loan.Vehicle?.Year;
|
||||||
|
originalLoan.Vehicle.Color = loan.Vehicle?.Color;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needToUpdateReserve)
|
||||||
|
{
|
||||||
|
originalLoan.ReserveAmount = loan.ReserveAmount;
|
||||||
|
originalLoan.ReserveMessage = loan.ReserveMessage;
|
||||||
|
originalLoan.ExportedReserveDate = loan.ExportedReserveDate;
|
||||||
|
originalLoan.Term = loan.Term;
|
||||||
|
originalLoan.FlatFeePaid = loan.FlatFeePaid;
|
||||||
|
originalLoan.Adjustment = loan.Adjustment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
using ReserveManagementSystemLib.Models;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi.Services.QueueServices
|
||||||
|
{
|
||||||
|
public interface IQueueRmsActiveLoanService
|
||||||
|
{
|
||||||
|
Task QueueRmsActiveLoanServiceRequest(RmsActiveImportRequest request);
|
||||||
|
}
|
||||||
|
}
|
||||||
+36
@@ -0,0 +1,36 @@
|
|||||||
|
using LCU.Library.Internal.LcuMassTransitModels;
|
||||||
|
using MassTransit;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using ReserveManagementSystemApi.Configurations;
|
||||||
|
using ReserveManagementSystemLib.Models;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi.Services.QueueServices
|
||||||
|
{
|
||||||
|
public class QueueRmsActiveLoanService : IQueueRmsActiveLoanService
|
||||||
|
{
|
||||||
|
private readonly ISendEndpoint _sendEndpoint;
|
||||||
|
private readonly ReceiveEndpointConfiguration _rmsActiveLoanImportReceiveEndpoint;
|
||||||
|
|
||||||
|
public QueueRmsActiveLoanService(IBusControl busControl, ReceiveEndpointConfigurations receiveEndpointConfigurations)
|
||||||
|
{
|
||||||
|
_rmsActiveLoanImportReceiveEndpoint = receiveEndpointConfigurations.RmsActiveLoanReceiveEndpoint;
|
||||||
|
_sendEndpoint = busControl.GetSendEndpoint(_rmsActiveLoanImportReceiveEndpoint.ReceiveEndpointUri).Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task QueueRmsActiveLoanServiceRequest(RmsActiveImportRequest request)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(30));
|
||||||
|
await _sendEndpoint.Send(request, cancellationTokenSource.Token);
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
var message = "Failed to Queue RmsActiveLoanImport Request. " +
|
||||||
|
$"RmsActiveLoanImport: {JsonConvert.SerializeObject(request)}";
|
||||||
|
Log.Error(exception, message);
|
||||||
|
throw new ServiceException($"{message}, Exception Message: {exception.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+31
@@ -0,0 +1,31 @@
|
|||||||
|
using ReserveManagementSystemApi.Services.QueueServices;
|
||||||
|
using ReserveManagementSystemLib.Models;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi.Services
|
||||||
|
{
|
||||||
|
public class RmsActiveLoanService : IRmsActiveLoanService
|
||||||
|
{
|
||||||
|
private readonly IQueueRmsActiveLoanService _queueRmsActiveLoanService;
|
||||||
|
private readonly IImportReadService _importReadService;
|
||||||
|
|
||||||
|
public RmsActiveLoanService(
|
||||||
|
IQueueRmsActiveLoanService queueRmsActiveLoanService, IImportReadService importReadService
|
||||||
|
)
|
||||||
|
{
|
||||||
|
_queueRmsActiveLoanService = queueRmsActiveLoanService;
|
||||||
|
_importReadService = importReadService;
|
||||||
|
}
|
||||||
|
public async Task HandleRmsActiveImportRequest(RmsActiveImportRequest request)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await _importReadService.ImportActiveLoansFromDNA(request.ImportDateTime, request.SkipExport);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, $"Failure importing Active Loans from DNA");
|
||||||
|
throw new ServiceException($"Exception Message: {ex.Message} - Failure importing Active Loans from DNA");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+42
@@ -0,0 +1,42 @@
|
|||||||
|
namespace ReserveManagementSystemApi.Services
|
||||||
|
{
|
||||||
|
public class ScheduleService : IScheduleService
|
||||||
|
{
|
||||||
|
private readonly IImportReadService _importReadService;
|
||||||
|
private readonly IExportService _exportService;
|
||||||
|
|
||||||
|
public ScheduleService(IImportReadService importReadService, IExportService exportService)
|
||||||
|
{
|
||||||
|
_importReadService = importReadService;
|
||||||
|
_exportService = exportService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RunImportExportActive(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Log.Information("Importing active loans from DNA");
|
||||||
|
var activeImport = await _importReadService.ImportActiveLoansFromDNA(string.Empty);
|
||||||
|
Log.Information($"{activeImport.RecordsSaved} active loans were saved");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, $"Failed to perform scheduled active loan import.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RunImportExportClosed(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Log.Information("Importing closed loans from DNA");
|
||||||
|
var closedImport = await _importReadService.ImportClosedLoansFromDNA(string.Empty);
|
||||||
|
Log.Information($"{closedImport.RecordsSaved} loans were closed");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, $"Failed to perform scheduled closed loan import.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+28
@@ -0,0 +1,28 @@
|
|||||||
|
using LCU.Library.Internal.Status.Services;
|
||||||
|
using LCU.Library.Internal.StatusModels.Models;
|
||||||
|
namespace ReserveManagementSystemApi.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.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+29
@@ -0,0 +1,29 @@
|
|||||||
|
using ReserveManagementSystemLib.Models;
|
||||||
|
using ReserveManagementSystemLib.Repositories;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemApi.Services
|
||||||
|
{
|
||||||
|
public class VehicleService: IVehicleService
|
||||||
|
{
|
||||||
|
private readonly IVehicleRepository _vehicleRepository;
|
||||||
|
|
||||||
|
public VehicleService(IVehicleRepository vehicleRepository)
|
||||||
|
{
|
||||||
|
_vehicleRepository = vehicleRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async Task<Vehicle> GetVehicleByLoanIdAsync(int? loanId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await _vehicleRepository.FindByLoanIdAsync(loanId);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, "Failure retrieving vehicle by loan id.");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
global using Microsoft.AspNetCore.Mvc;
|
||||||
|
global using Microsoft.EntityFrameworkCore;
|
||||||
|
global using Serilog;
|
||||||
|
global using System;
|
||||||
|
global using System.Linq;
|
||||||
|
global using System.Threading.Tasks;
|
||||||
|
global using LCU.Library.Internal.Exceptions;
|
||||||
|
|
||||||
+59
@@ -0,0 +1,59 @@
|
|||||||
|
{
|
||||||
|
"Primary": {
|
||||||
|
"AppName": "Reserve Management System",
|
||||||
|
"SeqUrl": "http://localhost",
|
||||||
|
"SeqApiKey": "VALUE-IN-KEYVAULT",
|
||||||
|
"CorsAllowedOrigins": [
|
||||||
|
"http://localhost:3000",
|
||||||
|
"http://lcu-internal.com",
|
||||||
|
"https://lcu-internal.com",
|
||||||
|
"https://qa-api.lcu-internal.com"
|
||||||
|
],
|
||||||
|
"FeatureFlags": {
|
||||||
|
"RunRmsActiveLoanConsumer": true,
|
||||||
|
"EnableImportExportActive": false,
|
||||||
|
"EnableImportExportClosed": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"SqlConnectionConfiguration": {
|
||||||
|
"ConnectionString": "data source=localhost;initial catalog=ReserveManagementSystem;Integrated Security=SSPI;MultipleActiveResultSets=True;App=EntityFramework",
|
||||||
|
"MaxRetryCount": 3,
|
||||||
|
"MaxRetryDelay": "00:00:30"
|
||||||
|
},
|
||||||
|
"ConnectionConfiguration": {
|
||||||
|
"HostUrl": "localhost",
|
||||||
|
"UserName": "guest",
|
||||||
|
"Password": "guest"
|
||||||
|
},
|
||||||
|
"RmsActiveLoanReceiveEndpoint": {
|
||||||
|
"ReceiveEndpoint": "LCU.ReserveManagementSystem.ActiveImport",
|
||||||
|
"ReceiveEndpointType": "exchange",
|
||||||
|
"PrefetchLimit": 1
|
||||||
|
},
|
||||||
|
"ApiSecurityConfiguration": {
|
||||||
|
"ApiKeyAuthenticationFailureBehavior": "Error",
|
||||||
|
"InternalApiKeySet": {
|
||||||
|
"ReserveManagementSystem": "VALUE-IN-KEYVAULT"
|
||||||
|
},
|
||||||
|
"ExternalApiKeySet": {}
|
||||||
|
},
|
||||||
|
"CoreApiConfiguration": {
|
||||||
|
"ApiTimeOutInSeconds": 420,
|
||||||
|
"BaseUrl": "https://localhost:59303",
|
||||||
|
"GetIndirectLoansByPostedDate": "/api/core/IndirectLoan/",
|
||||||
|
"GetClosedLoansByPostedDate": "/api/core/IndirectLoan/Closed/",
|
||||||
|
"GetClosedIndirectLoansWithDetailByPostedDate": "/api/core/IndirectLoan/ClosedWithDetail/",
|
||||||
|
"PostMonetaryTransactions": "/api/core/Transaction/PostMonetaryTransactions",
|
||||||
|
"PutDealerOriginalBalance": "/api/core/IndirectLoan/PutDealerOriginalBalance"
|
||||||
|
},
|
||||||
|
"AllowedHosts": "*",
|
||||||
|
"HostedServices": {
|
||||||
|
"ImportExportActiveCronSchedule": "0 19 * * 0-6",
|
||||||
|
"ImportExportClosedCronSchedule": "15 19 * * 0-6"
|
||||||
|
},
|
||||||
|
"RmsApiConfiguration": {
|
||||||
|
"DefaultImportStartDate": "2021-07-01 00:00:00",
|
||||||
|
"DefaultBatchSize": 100,
|
||||||
|
"DefaultConvertedLoanPostDate": "2021-10-31"
|
||||||
|
}
|
||||||
|
}
|
||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
namespace ReserveManagementSystemLib.Configuration
|
||||||
|
{
|
||||||
|
public class CoreApiConfiguration
|
||||||
|
{
|
||||||
|
public string ClientName { get; set; }
|
||||||
|
public string ApiTimeOutInSeconds { get; set; }
|
||||||
|
public string BaseUrl { get; set; }
|
||||||
|
public string GetIndirectLoansByPostedDate { get; set; }
|
||||||
|
public string GetClosedLoansByPostedDate { get; set; }
|
||||||
|
public string GetClosedIndirectLoansWithDetailByPostedDate { get; set; }
|
||||||
|
public string PostMonetaryTransactions { get; set; }
|
||||||
|
public string PutDealerOriginalBalance { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
namespace ReserveManagementSystemLib.Configuration
|
||||||
|
{
|
||||||
|
public class RmsApiConfiguration
|
||||||
|
{
|
||||||
|
public string DefaultImportStartDate { get; set; }
|
||||||
|
public int DefaultBatchSize { get; set; }
|
||||||
|
public string DefaultConvertedLoanPostDate { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
namespace ReserveManagementSystemLib.Enums
|
||||||
|
{
|
||||||
|
public enum ImportType
|
||||||
|
{
|
||||||
|
Active,
|
||||||
|
Closed
|
||||||
|
}
|
||||||
|
}
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
namespace ReserveManagementSystemLib.Helpers
|
||||||
|
{
|
||||||
|
public static class StringExtensions
|
||||||
|
{
|
||||||
|
public static string Truncate(this string inputString, int numberOfCharacters)
|
||||||
|
{
|
||||||
|
if (inputString.Length <= numberOfCharacters)
|
||||||
|
{
|
||||||
|
return inputString;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return inputString.Substring(0, numberOfCharacters);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+34
@@ -0,0 +1,34 @@
|
|||||||
|
using FluentValidation;
|
||||||
|
using FluentValidation.Results;
|
||||||
|
using Microsoft.AspNetCore.Components.Forms;
|
||||||
|
using ReserveManagementSystemLib.Models;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemLib.Helpers
|
||||||
|
{
|
||||||
|
public class ValidationHelper
|
||||||
|
{
|
||||||
|
|
||||||
|
public static List<ValidationFailure> SetValidationErrors(Loan loanInfo)
|
||||||
|
{
|
||||||
|
var validator = GetValidatorForModel();
|
||||||
|
var editContext = new EditContext(loanInfo);
|
||||||
|
|
||||||
|
var context = new ValidationContext<object>(editContext.Model);
|
||||||
|
var validationResults = validator.Validate(context);
|
||||||
|
|
||||||
|
return new List<ValidationFailure>(validationResults.Errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IValidator GetValidatorForModel()
|
||||||
|
{
|
||||||
|
LoanValidator baseclass = new LoanValidator();
|
||||||
|
var modelValidatorInstance = (IValidator)Activator.CreateInstance(baseclass.GetType());
|
||||||
|
|
||||||
|
return modelValidatorInstance;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
namespace ReserveManagementSystemLib.Models
|
||||||
|
{
|
||||||
|
public class AuditHistory
|
||||||
|
{
|
||||||
|
[Key]
|
||||||
|
public int AuditId { get; set; }
|
||||||
|
public int? LoanId { get; set; }
|
||||||
|
public string MemberNumber { get; set; }
|
||||||
|
public string LoanNumber { get; set; }
|
||||||
|
public string ModifiedBy { get; set; }
|
||||||
|
public DateTime ModifiedDate { get; set; }
|
||||||
|
public string ActivityType { get; set; }
|
||||||
|
public string OldValue { get; set; }
|
||||||
|
public string NewValue { get; set; }
|
||||||
|
public string AuditDescription { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
+33
@@ -0,0 +1,33 @@
|
|||||||
|
namespace ReserveManagementSystemLib.Models
|
||||||
|
{
|
||||||
|
public class CalculationConfig
|
||||||
|
{
|
||||||
|
public readonly Loan _loanData;
|
||||||
|
|
||||||
|
public CalculationConfig(Loan loanData)
|
||||||
|
{
|
||||||
|
_loanData = loanData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Loan LoanData() { return _loanData; }
|
||||||
|
|
||||||
|
public decimal BuydownRateDifference() { return _loanData.BuyRate - _loanData.ContractRate; }
|
||||||
|
|
||||||
|
public decimal BuyFinanceCharge { get; set; }
|
||||||
|
|
||||||
|
public decimal ContractFinanceCharge { get; set; }
|
||||||
|
|
||||||
|
public int DaysToFirstPmt() { return (_loanData.FirstPmtDate - _loanData.LoanDate).Days - 30 > 0 ? (_loanData.FirstPmtDate - _loanData.LoanDate).Days - 30 : 0; }
|
||||||
|
|
||||||
|
public decimal ReserveDiscount() { return _loanData.LoanType?.ReserveDiscount ?? 25M; }
|
||||||
|
|
||||||
|
public decimal FlatFeePercent() { return _loanData.LoanType?.FlatFeePercent ?? 1M; }
|
||||||
|
|
||||||
|
public decimal NoReserveThreshold() { return _loanData.LoanType?.NoReserveThreshold ?? 0.25M; }
|
||||||
|
|
||||||
|
public decimal StdRate() { return (_loanData.ContractRate - _loanData.BuyRate); }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
+32
@@ -0,0 +1,32 @@
|
|||||||
|
namespace ReserveManagementSystemLib.Models
|
||||||
|
{
|
||||||
|
public class Dealer
|
||||||
|
{
|
||||||
|
|
||||||
|
public string DealerCode { get; set; }
|
||||||
|
|
||||||
|
string _dealerName;
|
||||||
|
public string Name { get { return _dealerName?.ToUpper(); } set => _dealerName = value?.ToUpper(); }
|
||||||
|
|
||||||
|
public string DealerGroupCode { get; set; }
|
||||||
|
|
||||||
|
public string DealerAccountNumber { get; set; }
|
||||||
|
|
||||||
|
[Key]
|
||||||
|
public string DealerOrganizationNumber { get; set; }
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
return obj is Dealer dealer &&
|
||||||
|
DealerCode == dealer.DealerCode &&
|
||||||
|
Name == dealer.Name?.ToUpper() &&
|
||||||
|
DealerAccountNumber == dealer.DealerAccountNumber &&
|
||||||
|
DealerOrganizationNumber == dealer.DealerOrganizationNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return HashCode.Combine(DealerCode, DealerAccountNumber, DealerOrganizationNumber);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
namespace ReserveManagementSystemLib.Models
|
||||||
|
{
|
||||||
|
public class Import
|
||||||
|
{
|
||||||
|
[Key]
|
||||||
|
public int ImportId { get; set; }
|
||||||
|
|
||||||
|
public DateTime StartDate { get; set; }
|
||||||
|
|
||||||
|
public DateTime? EndDate { get; set; }
|
||||||
|
|
||||||
|
public int RecordCount { get; set; }
|
||||||
|
|
||||||
|
public int RecordsSaved { get; set; }
|
||||||
|
|
||||||
|
public bool Success { get; set; }
|
||||||
|
|
||||||
|
public string FileName { get; set; }
|
||||||
|
|
||||||
|
public string ImportType { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
+204
@@ -0,0 +1,204 @@
|
|||||||
|
using FluentValidation;
|
||||||
|
using FluentValidation.Results;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
|
namespace ReserveManagementSystemLib.Models
|
||||||
|
{
|
||||||
|
public class Loan
|
||||||
|
{
|
||||||
|
[Key]
|
||||||
|
public int LoanId { get; set; }
|
||||||
|
|
||||||
|
public int ImportId { get; set; }
|
||||||
|
|
||||||
|
public string MemberNumber { get; set; }
|
||||||
|
|
||||||
|
public string LoanNumber { get; set; }
|
||||||
|
|
||||||
|
public string MemberLastName { get; set; }
|
||||||
|
|
||||||
|
public string MemberFirstName { get; set; }
|
||||||
|
|
||||||
|
public string MemberInitial { get; set; }
|
||||||
|
|
||||||
|
public string DealerOrganizationNumber { get; set; }
|
||||||
|
|
||||||
|
public DateTime LoanDate { get; set; }
|
||||||
|
|
||||||
|
public DateTime PostedDate { get; set; }
|
||||||
|
|
||||||
|
public DateTime FirstPmtDate { get; set; }
|
||||||
|
|
||||||
|
public DateTime FinalPmtDate { get; set; }
|
||||||
|
|
||||||
|
public decimal LoanAmount { get; set; }
|
||||||
|
|
||||||
|
public decimal BuyRate { get; set; }
|
||||||
|
|
||||||
|
public decimal ContractRate { get; set; }
|
||||||
|
|
||||||
|
public decimal MonthlyPmt { get; set; }
|
||||||
|
|
||||||
|
public string LoanTypeId { get; set; }
|
||||||
|
|
||||||
|
public int Term { get; set; }
|
||||||
|
|
||||||
|
public decimal ReserveAmount { get; set; }
|
||||||
|
|
||||||
|
public bool FlatFeePaid { get; set; }
|
||||||
|
|
||||||
|
public decimal? ChargeBack { get; set; }
|
||||||
|
|
||||||
|
public string ChargebackMessage { get; set; }
|
||||||
|
|
||||||
|
public byte? RemainingMonthsAtClose { get; set; }
|
||||||
|
|
||||||
|
public DateTime? PaidLoanDate { get; set; }
|
||||||
|
|
||||||
|
public string ReserveMessage { get; set; }
|
||||||
|
|
||||||
|
public bool ActionRequired { get; set; }
|
||||||
|
|
||||||
|
public DateTime? StatementDate { get; set; }
|
||||||
|
|
||||||
|
public decimal? Adjustment { get; set; }
|
||||||
|
|
||||||
|
public string LoanStatus { get; set; }
|
||||||
|
|
||||||
|
public DateTime? ExportedReserveDate { get; set; }
|
||||||
|
|
||||||
|
public DateTime? ExportedChargebackDate { get; set; }
|
||||||
|
|
||||||
|
public string ApplicationId { get; set; }
|
||||||
|
|
||||||
|
public bool Warranty { get; set; }
|
||||||
|
|
||||||
|
public bool Gap { get; set; }
|
||||||
|
|
||||||
|
public bool CreditLife { get; set; }
|
||||||
|
|
||||||
|
public bool CreditDisability { get; set; }
|
||||||
|
|
||||||
|
public bool Mbp { get; set; }
|
||||||
|
|
||||||
|
public string AccountType { get; set; }
|
||||||
|
|
||||||
|
[ForeignKey("DealerOrganizationNumber")]
|
||||||
|
public Dealer Dealer { get; set; }
|
||||||
|
|
||||||
|
[ForeignKey("LoanTypeId")]
|
||||||
|
public LoanType LoanType { get; set; }
|
||||||
|
|
||||||
|
public Vehicle Vehicle { get; set; }
|
||||||
|
|
||||||
|
[NotMapped]
|
||||||
|
public List<ValidationFailure> ValidationErrors { get; set; }
|
||||||
|
|
||||||
|
public bool HasSameReserve(object obj)
|
||||||
|
{
|
||||||
|
return obj is Loan loan &&
|
||||||
|
LoanDate == loan.LoanDate &&
|
||||||
|
Term == loan.Term &&
|
||||||
|
FirstPmtDate == loan.FirstPmtDate &&
|
||||||
|
FinalPmtDate == loan.FinalPmtDate &&
|
||||||
|
LoanAmount == loan.LoanAmount &&
|
||||||
|
LoanTypeId == loan.LoanTypeId &&
|
||||||
|
BuyRate == loan.BuyRate &&
|
||||||
|
ContractRate == loan.ContractRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsBoatLoan(object obj)
|
||||||
|
{
|
||||||
|
return obj is Loan loan &&
|
||||||
|
AccountType == "DL09" || AccountType == "DL10" || AccountType == "DL11" || AccountType == "DL12";
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
return obj is Loan loan &&
|
||||||
|
MemberNumber == loan.MemberNumber &&
|
||||||
|
LoanNumber == loan.LoanNumber &&
|
||||||
|
MemberLastName == loan.MemberLastName &&
|
||||||
|
MemberFirstName == loan.MemberFirstName &&
|
||||||
|
MemberInitial == loan.MemberInitial &&
|
||||||
|
DealerOrganizationNumber == loan.DealerOrganizationNumber &&
|
||||||
|
LoanDate == loan.LoanDate &&
|
||||||
|
PostedDate == loan.PostedDate &&
|
||||||
|
Term == loan.Term &&
|
||||||
|
FirstPmtDate == loan.FirstPmtDate &&
|
||||||
|
FinalPmtDate == loan.FinalPmtDate &&
|
||||||
|
LoanAmount == loan.LoanAmount &&
|
||||||
|
BuyRate == loan.BuyRate &&
|
||||||
|
ContractRate == loan.ContractRate &&
|
||||||
|
MonthlyPmt == loan.MonthlyPmt &&
|
||||||
|
LoanTypeId == loan.LoanTypeId &&
|
||||||
|
ApplicationId == loan.ApplicationId &&
|
||||||
|
Warranty == loan.Warranty &&
|
||||||
|
Gap == loan.Gap &&
|
||||||
|
Mbp == loan.Mbp &&
|
||||||
|
CreditLife == loan.CreditLife &&
|
||||||
|
CreditDisability == loan.CreditDisability &&
|
||||||
|
ActionRequired == loan.ActionRequired;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
HashCode hash = new HashCode();
|
||||||
|
hash.Add(MemberNumber);
|
||||||
|
hash.Add(LoanNumber);
|
||||||
|
hash.Add(MemberLastName);
|
||||||
|
hash.Add(MemberFirstName);
|
||||||
|
hash.Add(MemberInitial);
|
||||||
|
hash.Add(DealerOrganizationNumber);
|
||||||
|
hash.Add(LoanDate);
|
||||||
|
hash.Add(PostedDate);
|
||||||
|
hash.Add(FirstPmtDate);
|
||||||
|
hash.Add(FinalPmtDate);
|
||||||
|
hash.Add(LoanAmount);
|
||||||
|
hash.Add(BuyRate);
|
||||||
|
hash.Add(ContractRate);
|
||||||
|
hash.Add(MonthlyPmt);
|
||||||
|
hash.Add(LoanTypeId);
|
||||||
|
hash.Add(ApplicationId);
|
||||||
|
hash.Add(Warranty);
|
||||||
|
hash.Add(Gap);
|
||||||
|
hash.Add(Mbp);
|
||||||
|
hash.Add(CreditLife);
|
||||||
|
hash.Add(CreditDisability);
|
||||||
|
hash.Add(ActionRequired);
|
||||||
|
return hash.ToHashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public class LoanValidator : AbstractValidator<Loan>
|
||||||
|
{
|
||||||
|
public LoanValidator()
|
||||||
|
{
|
||||||
|
|
||||||
|
RuleFor(m => m.LoanTypeId).NotEmpty().WithMessage("Loan type cannot be empty!");
|
||||||
|
RuleFor(m => m.DealerOrganizationNumber).NotEmpty().WithMessage("Dealer Organization Number cannot be empty!");
|
||||||
|
When(m => m.Dealer != null && string.IsNullOrEmpty(m.Dealer.DealerCode), () =>
|
||||||
|
{
|
||||||
|
RuleFor(m => m.Dealer.DealerCode).NotEmpty().WithMessage("Dealer Code cannot be empty!");
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
When(m => m.Dealer != null && string.IsNullOrEmpty(m.Dealer.DealerAccountNumber), () =>
|
||||||
|
{
|
||||||
|
RuleFor(m => m.Dealer.DealerAccountNumber).NotEmpty().WithMessage("Dealer Account Number cannot be empty!");
|
||||||
|
});
|
||||||
|
|
||||||
|
When(m => m.Dealer != null && string.IsNullOrEmpty(m.Dealer.Name), () =>
|
||||||
|
{
|
||||||
|
RuleFor(m => m.Dealer.Name).NotEmpty().WithMessage("Dealer Name cannot be empty!");
|
||||||
|
});
|
||||||
|
|
||||||
|
When(m => m.Vehicle != null && string.IsNullOrEmpty(m.Vehicle.VINNumber), () =>
|
||||||
|
{
|
||||||
|
RuleFor(m => m.Vehicle.VINNumber).NotEmpty().WithMessage("VIN cannot be empty!");
|
||||||
|
});
|
||||||
|
|
||||||
|
RuleFor(m => m.LoanDate).LessThanOrEqualTo(m => m.FirstPmtDate).WithMessage("First Payment Date cannot be before Loan Date!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
namespace ReserveManagementSystemLib.Models
|
||||||
|
{
|
||||||
|
public class LoanChargeback
|
||||||
|
{
|
||||||
|
public decimal ChargebackAmount { get; set; }
|
||||||
|
|
||||||
|
public string ChargebackTypeMessage { get; set; }
|
||||||
|
|
||||||
|
public byte? RemainingMonthsAtClose { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
namespace ReserveManagementSystemLib.Models
|
||||||
|
{
|
||||||
|
public class LoanChargebackInput
|
||||||
|
{
|
||||||
|
public DateTime LoanDate { get; set; }
|
||||||
|
|
||||||
|
public DateTime FirstPmtDate { get; set; }
|
||||||
|
|
||||||
|
public DateTime FinalPmtDate { get; set; }
|
||||||
|
|
||||||
|
public string LoanType { get; set; }
|
||||||
|
|
||||||
|
public decimal ReserveAmount { get; set; }
|
||||||
|
|
||||||
|
public DateTime? PaidLoanDate { get; set; }
|
||||||
|
|
||||||
|
public int Term { get; set; }
|
||||||
|
|
||||||
|
public string AccountType { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user