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