first commit

This commit is contained in:
Zeeshaun
2026-03-11 11:18:25 -05:00
commit f3cb730f3b
472 changed files with 53651 additions and 0 deletions
@@ -0,0 +1,32 @@
using MongoDB.Bson.Serialization.Attributes;
using System.ComponentModel.DataAnnotations;
namespace Landmark.OLA.Models.Loan
{
public class BranchData
{
[Required]
[StringLength(5, MinimumLength = 5, ErrorMessage = "Zipcodes must be 5 digits")]
public string Zipcode { get; set; }
[Required]
[Range(minimum: 1, maximum: 99999999)]
public int ChannelId { get; set; }
public BranchData(string zip, int channel)
{
this.Zipcode = zip;
this.ChannelId = channel;
}
}
[BsonIgnoreExtraElements]
public class BranchConfig : OlaModel
{
public DateTime Date { get; set; }
[Required]
public List<BranchData> BranchCodesByZip { get; set; }
}
}
@@ -0,0 +1,485 @@
namespace Landmark.OLA.Models.Loan
{
public static class BranchMapping
{
public static Dictionary<string, int> BranchCodesByZip = new Dictionary<string, int>
{
{"53001", 1561599},
{"53002", 1561599},
{"53003", 1561245},
{"53004", 1561591},
{"53005", 1561255},
{"53006", 1561657},
{"53007", 1561255},
{"53008", 1561255},
{"53010", 1561599},
{"53011", 1561599},
{"53012", 1561591},
{"53013", 1561591},
{"53014", 1561657},
{"53015", 1561241},
{"53016", 1561665},
{"53017", 1561664},
{"53018", 1561267},
{"53019", 1561599},
{"53020", 1561599},
{"53021", 1561604},
{"53022", 1561288},
{"53023", 1561288},
{"53024", 1561591},
{"53026", 1561591},
{"53027", 1561662},
{"53029", 1561267},
{"53031", 1561599},
{"53032", 1561657},
{"53033", 1561664},
{"53034", 1561665},
{"53035", 1561657},
{"53036", 1561284},
{"53037", 1561604},
{"53038", 1561284},
{"53039", 1561665},
{"53040", 1561599},
{"53042", 1561599},
{"53044", 1561599},
{"53045", 1561588},
{"53046", 1561265},
{"53047", 1561284},
{"53048", 1561662},
{"53049", 1561657},
{"53050", 1561657},
{"53051", 1561288},
{"53052", 1561288},
{"53056", 1561267},
{"53057", 1561599},
{"53058", 1561267},
{"53059", 1561662},
{"53060", 1561599},
{"53061", 1561599},
{"53062", 1561599},
{"53063", 1561599},
{"53064", 1561267},
{"53065", 1561657},
{"53066", 1561245},
{"53069", 1561267},
{"53070", 1561591},
{"53072", 1561262},
{"53073", 1561599},
{"53074", 1561591},
{"53075", 1561599},
{"53076", 1561664},
{"53078", 1561662},
{"53079", 1561599},
{"53080", 1561591},
{"53081", 1561591},
{"53082", 1561604},
{"53083", 1561599},
{"53085", 1561599},
{"53086", 1561662},
{"53088", 1561657},
{"53089", 1561265},
{"53090", 1561599},
{"53091", 1561657},
{"53092", 1561591},
{"53093", 1561599},
{"53094", 1561284},
{"53095", 1561604},
{"53096", 1561599},
{"53097", 1561591},
{"53098", 1561284},
{"53099", 1561662},
{"53101", 1561631},
{"53102", 1561631},
{"53103", 2081492},
{"53104", 1561624},
{"53105", 1561631},
{"53108", 1561598},
{"53109", 1561631},
{"53110", 1561616},
{"53114", 1561631},
{"53115", 1561631},
{"53118", 1561245},
{"53119", 1561245},
{"53120", 1561631},
{"53121", 1561631},
{"53122", 1561588},
{"53125", 1561631},
{"53126", 1561624},
{"53127", 1561262},
{"53128", 1561631},
{"53129", 1561289},
{"53130", 1561289},
{"53132", 1561289},
{"53137", 1561284},
{"53138", 1561661},
{"53139", 1561631},
{"53140", 1561639},
{"53141", 1561639},
{"53142", 1561639},
{"53143", 1561639},
{"53144", 1561639},
{"53146", 1561243},
{"53147", 1561631},
{"53148", 1561631},
{"53149", 2081492},
{"53150", 2081492},
{"53151", 1561243},
{"53152", 1561631},
{"53153", 1561262},
{"53154", 1561598},
{"53156", 1561245},
{"53157", 1561631},
{"53158", 1561639},
{"53159", 1561631},
{"53167", 1561631},
{"53168", 1561631},
{"53170", 1561631},
{"53171", 1561639},
{"53172", 1561598},
{"53176", 1561631},
{"53177", 1561624},
{"53178", 1561245},
{"53179", 1561631},
{"53181", 1561631},
{"53182", 1561624},
{"53183", 1561267},
{"53184", 1561631},
{"53185", 1561631},
{"53186", 1561262},
{"53187", 1561262},
{"53188", 1561262},
{"53189", 1561262},
{"53190", 1561245},
{"53191", 1561631},
{"53192", 1561631},
{"53194", 1561624},
{"53195", 1561631},
{"53199", 1561631},
{"53201", 1561241},
{"53202", 1561615},
{"53203", 1561241},
{"53204", 1561241},
{"53205", 1561241},
{"53206", 1561241},
{"53207", 1561615},
{"53208", 1561241},
{"53209", 1561255},
{"53210", 1561241},
{"53211", 1561615},
{"53212", 1561241},
{"53213", 1561241},
{"53214", 1561587},
{"53215", 1561283},
{"53216", 1561241},
{"53217", 1561255},
{"53218", 1561255},
{"53219", 1561241},
{"53220", 1561283},
{"53221", 1561283},
{"53222", 1561255},
{"53223", 1561255},
{"53224", 1561255},
{"53225", 1561255},
{"53226", 1561255},
{"53227", 1561587},
{"53228", 1561587},
{"53233", 1561241},
{"53234", 1561241},
{"53235", 1561616},
{"53237", 1561283},
{"53259", 1561615},
{"53263", 1561255},
{"53267", 1561241},
{"53268", 1561615},
{"53274", 1561283},
{"53278", 1561241},
{"53288", 1561615},
{"53290", 1561241},
{"53293", 1561241},
{"53295", 1561241},
{"53401", 1561639},
{"53402", 1561285},
{"53403", 1561639},
{"53404", 1561639},
{"53405", 1561285},
{"53406", 1561624},
{"53407", 1561639},
{"53408", 1561624},
{"53490", 1561285},
{"53501", 1561661},
{"53502", 1561661},
{"53503", 1561661},
{"53505", 1561631},
{"53506", 1561661},
{"53507", 1561661},
{"53508", 1561661},
{"53511", 1561661},
{"53512", 1561661},
{"53515", 1561661},
{"53517", 1561661},
{"53520", 1561661},
{"53521", 1561661},
{"53522", 1561661},
{"53523", 1561284},
{"53525", 1561661},
{"53526", 1561661},
{"53527", 1561661},
{"53528", 1561661},
{"53529", 1561661},
{"53531", 1561661},
{"53532", 1561661},
{"53533", 1561661},
{"53534", 1561661},
{"53535", 1561661},
{"53536", 1561661},
{"53537", 1561661},
{"53538", 1561284},
{"53542", 1561661},
{"53543", 1561661},
{"53544", 1561661},
{"53545", 1561661},
{"53546", 1561631},
{"53547", 1561661},
{"53548", 1561661},
{"53549", 1561284},
{"53550", 1561661},
{"53551", 1561284},
{"53553", 1561661},
{"53555", 1561661},
{"53557", 1561665},
{"53558", 1561661},
{"53559", 1561660},
{"53560", 1561661},
{"53562", 1561661},
{"53563", 1561284},
{"53565", 1561661},
{"53566", 1561661},
{"53570", 1561661},
{"53571", 1561661},
{"53572", 1561661},
{"53574", 1561661},
{"53575", 1561661},
{"53576", 1561661},
{"53579", 1561660},
{"53580", 1561661},
{"53582", 1561661},
{"53585", 1561631},
{"53589", 1561661},
{"53590", 1561661},
{"53593", 1561661},
{"53594", 1561284},
{"53595", 1561661},
{"53596", 1561661},
{"53597", 1561661},
{"53598", 1561661},
{"53701", 1561661},
{"53702", 1561661},
{"53703", 1561661},
{"53704", 1561661},
{"53705", 1561661},
{"53706", 1561661},
{"53707", 1561661},
{"53708", 1561661},
{"53711", 1561661},
{"53713", 1561661},
{"53714", 1561661},
{"53715", 1561661},
{"53716", 1561661},
{"53717", 1561661},
{"53718", 1561661},
{"53719", 1561661},
{"53725", 1561661},
{"53726", 1561661},
{"53744", 1561661},
{"53774", 1561661},
{"53777", 1561661},
{"53778", 1561661},
{"53779", 1561661},
{"53782", 1561661},
{"53783", 1561661},
{"53784", 1561661},
{"53785", 1561661},
{"53786", 1561661},
{"53788", 1561661},
{"53789", 1561661},
{"53790", 1561661},
{"53791", 1561661},
{"53792", 1561661},
{"53793", 1561661},
{"53794", 1561661},
{"53901", 1561660},
{"53911", 1561661},
{"53916", 1561649},
{"53919", 1561649},
{"53920", 1561660},
{"53922", 1561657},
{"53923", 1561660},
{"53925", 1561660},
{"53926", 1561660},
{"53928", 1561660},
{"53930", 1561660},
{"53931", 1561649},
{"53932", 1561660},
{"53933", 1561649},
{"53935", 1561660},
{"53939", 1561649},
{"53946", 1561649},
{"53947", 1561649},
{"53949", 1561660},
{"53952", 1561660},
{"53953", 1561660},
{"53954", 1561660},
{"53955", 1561660},
{"53956", 1561660},
{"53957", 1561649},
{"53960", 1561660},
{"53963", 1561657},
{"53964", 1561660},
{"53965", 1561660},
{"53969", 1561661},
{"54106", 1561657},
{"54110", 1561599},
{"54113", 1561657},
{"54115", 1561657},
{"54123", 1561657},
{"54126", 1561599},
{"54129", 1561657},
{"54130", 1561657},
{"54131", 1561657},
{"54136", 1561657},
{"54140", 1561657},
{"54152", 1561657},
{"54155", 1561657},
{"54160", 1561599},
{"54162", 1561657},
{"54165", 1561657},
{"54169", 1561657},
{"54170", 1561657},
{"54173", 1561657},
{"54180", 1561657},
{"54207", 1561599},
{"54208", 1561599},
{"54214", 1561599},
{"54215", 1561599},
{"54220", 1561599},
{"54221", 1561599},
{"54227", 1561599},
{"54228", 1561599},
{"54229", 1561599},
{"54230", 1561599},
{"54232", 1561599},
{"54240", 1561599},
{"54241", 1561599},
{"54245", 1561599},
{"54247", 1561599},
{"54301", 1561657},
{"54302", 1561599},
{"54303", 1561657},
{"54304", 1561657},
{"54305", 1561657},
{"54306", 1561657},
{"54307", 1561657},
{"54308", 1561657},
{"54311", 1561599},
{"54313", 1561657},
{"54324", 1561657},
{"54344", 1561657},
{"54901", 1561657},
{"54902", 1561657},
{"54903", 1561657},
{"54904", 1561657},
{"54906", 1561657},
{"54911", 1561657},
{"54912", 1561657},
{"54913", 1561657},
{"54914", 1561657},
{"54915", 1561657},
{"54919", 1561657},
{"54922", 1561657},
{"54923", 1561615},
{"54927", 1561657},
{"54931", 1561657},
{"54932", 1561657},
{"54934", 1561649},
{"54935", 1561657},
{"54936", 1561657},
{"54937", 1561657},
{"54941", 1561649},
{"54942", 1561657},
{"54944", 1561657},
{"54947", 1561657},
{"54952", 1561657},
{"54956", 1561657},
{"54957", 1561657},
{"54960", 1561649},
{"54963", 1561657},
{"54964", 1561657},
{"54968", 1561649},
{"54971", 1561649},
{"54974", 1561657},
{"54979", 1561657},
{"54980", 1561649},
{"54985", 1561657},
{"54986", 1561657},
{"60001", 1561631},
{"60002", 1561624},
{"60010", 1561631},
{"60011", 1561631},
{"60012", 1561631},
{"60013", 1561631},
{"60014", 1561631},
{"60015", 1561639},
{"60020", 1561631},
{"60021", 1561631},
{"60030", 1561631},
{"60031", 1561639},
{"60033", 1561631},
{"60034", 1561631},
{"60035", 1561639},
{"60037", 1561639},
{"60039", 1561631},
{"60040", 1561639},
{"60041", 1561631},
{"60042", 1561631},
{"60044", 1561639},
{"60045", 1561639},
{"60046", 1561631},
{"60047", 1561631},
{"60048", 1561639},
{"60049", 1561631},
{"60050", 1561631},
{"60051", 1561631},
{"60060", 1561639},
{"60061", 1561639},
{"60064", 1561639},
{"60069", 1561639},
{"60071", 1561631},
{"60072", 1561631},
{"60073", 1561631},
{"60075", 1561639},
{"60079", 1561639},
{"60081", 1561631},
{"60083", 1561639},
{"60084", 1561631},
{"60085", 1561639},
{"60086", 1561631},
{"60087", 1561639},
{"60088", 1561639},
{"60089", 1561639},
{"60092", 1561631},
{"60096", 1561639},
{"60097", 1561631},
{"60098", 1561631},
{"60099", 1561639},
{"60102", 1561631},
{"60142", 1561631},
{"60152", 1561631},
{"60156", 1561631},
{"60180", 1561631}
};
}
}
@@ -0,0 +1,27 @@
using System.ComponentModel.DataAnnotations;
using MongoDB.Bson.Serialization.Attributes;
namespace Landmark.OLA.Models.Loan
{
public class BranchNameData
{
[Required]
[Range(minimum: 1, maximum: 99999999)]
public int ChannelId { get; set; }
[Required]
[RegularExpression("^[a-zA-Z ]*$")]
[StringLength(150, ErrorMessage = "Branch Names must be less than 150 characters")]
public string BranchName { get; set; }
}
[BsonIgnoreExtraElements]
public class BranchNameConfig : OlaModel
{
public DateTime Date { get; set; }
[Required]
public List<BranchNameData> BranchNamesByChannelId { get; set; }
}
}
@@ -0,0 +1,60 @@
using System.ComponentModel.DataAnnotations;
using MongoDB.Bson.Serialization.Attributes;
namespace Landmark.OLA.Models.Loan
{
[BsonIgnoreExtraElements]
public class DealershipAuthRequest
{
[Required]
public string DealershipCode { get; set; }
public string DealershipName { get; set; }
[Required]
public string DealershipPassword { get; set; }
[Required]
public string ApplicantLastName { get; set; }
[Required]
public string ApplicationId { get; set; }
public DealershipAuthRequest(string dealershipCode, string dealershipName, string dealershipPassword, string applicantLastName, string applicationId)
{
this.DealershipCode = dealershipCode;
this.DealershipName = dealershipName;
this.DealershipPassword = dealershipPassword;
this.ApplicantLastName = applicantLastName;
this.ApplicationId = applicationId;
}
public static bool ValidateAuthRequest(DealershipAuthRequest dealershipRequest, DealershipAuthRequest actionResponse)
{
return dealershipRequest?.Equals(actionResponse) ?? false;
}
public override bool Equals(Object authRequest)
{
if (authRequest is not DealershipAuthRequest request)
{
return false;
}
return string.Equals(DealershipCode, request.DealershipCode, StringComparison.Ordinal) &&
string.Equals(DealershipPassword, request.DealershipPassword, StringComparison.Ordinal) &&
string.Equals(ApplicantLastName, request.ApplicantLastName, StringComparison.OrdinalIgnoreCase) &&
string.Equals(ApplicationId, request.ApplicationId, StringComparison.OrdinalIgnoreCase);
}
public override int GetHashCode()
{
return HashCode.Combine(
DealershipCode?.ToUpperInvariant(),
DealershipPassword,
ApplicantLastName?.ToUpperInvariant(),
ApplicationId?.ToUpperInvariant()
);
}
}
}
@@ -0,0 +1,28 @@
using Microsoft.AspNetCore.Http;
namespace Landmark.OLA.Models.Loan
{
public class DocumentUploadFromLoanApplication
{
public IFormFile File { get; set; }
public string Section { get; set; }
public string SectionId { get; set; }
public string Description { get; set; }
public static bool IsNullOrEmpty(DocumentUploadFromLoanApplication file)
{
if(file == null || file.File == null || String.IsNullOrEmpty(file.SectionId) || String.IsNullOrEmpty(file.Description))
{
return true;
}
if(file.File.Length == 0 || String.IsNullOrEmpty(file.File.FileName))
{
return true;
}
return false;
}
}
}
@@ -0,0 +1,11 @@
namespace Landmark.OLA.Models.Loan.Enums
{
public enum LoanErrorCode
{
No_Error,
Error_Updating,
Error_Submitting,
Error_Deleting
}
}
@@ -0,0 +1,13 @@
namespace Landmark.OLA.Models.Loan.Enums
{
public enum LoanStatus
{
Application_Error,
Vendor_Error,
In_Progress,
Deleted,
Submitted,
Decisioned
}
}
@@ -0,0 +1,29 @@
namespace Landmark.OLA.Models.Loan.Enums
{
public enum LoanType
{
CC_CashBack,
CC_Rewards,
CC_Student,
CC_Secure,
EQ_HELOC_Flex,
EQ_Home_Equity_Fixed,
EQ_Mtg_Refi_Express,
EQ_Mfg_Home_With_or_Without_Land,
V_Vehicle,
V_VehiclePreapproval,
M_Boat,
P_Powersport,
T_TrailerMotorhome,
S_Signature,
S_Special
}
public enum HMDALoanType
{
EQ_HELOC_Flex,
EQ_Home_Equity_Fixed,
EQ_Mtg_Refi_Express,
EQ_Mfg_Home_With_or_Without_Land
}
}
@@ -0,0 +1,13 @@
namespace Landmark.OLA.Models.Loan
{
public class Filter
{
public int Count { get; set; }
public bool SortDesc { get; set; }
public string SortField { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public FilterField[] FilterField { get; set; }
}
}
@@ -0,0 +1,13 @@
namespace Landmark.OLA.Models.Loan
{
public class FilterField
{
public string Field { get; set; }
public string FilterValue { get; set; }
public bool Equal { get; set; }
public bool NotEqual { get; set; }
public bool GreaterThan { get; set; }
public bool LessThan { get; set; }
}
}
@@ -0,0 +1,80 @@
using System.ComponentModel.DataAnnotations;
using Landmark.OLA.Models.Individuals;
using Landmark.OLA.Models.Assets;
using Landmark.OLA.Models.Loan.Enums;
using MongoDB.Bson.Serialization.Attributes;
namespace Landmark.OLA.Models.Loan
{
[BsonIgnoreExtraElements]
public class LoanApplication : OlaModel
{
[Required]
//Nullable so that there is no default value
public LoanType? LoanType { get; set; }
[Required]
//One Billion is an arbitrary limit but I'm pretty confidant that it will be an acceptable upper limit for a long time.
[Range(minimum: 0, maximum: 1000000000)]
//Nullable so that there is no default value
public decimal? RequestedAmount { get; set; }
//Required for Personal Signature loans.
[StringLength(100)]
public string PurposeOfLoanSignature { get; set; }
public DateTime Date { get; private set; }
[Range(minimum: 0, maximum: 1000000000)]
//Required for certain loan types. Checked by FluentValidation.
public int? TermLengthInMonths { get; set; }
//these could be ICollection if needed, would impact builders
public RealEstate RealEstate { get; set; }
public Vehicle Vehicle { get; set; }
public ManufacturedHome ManufacturedHome { get; set; }
public Guid SecuredCardCollateralId { get; }
[Required]
//Nullable so that there is no default value
//Values must match loan type. Checked by FluentValidation.
public LoanPurpose.Purpose? Purpose { get; set; }
[Required]
public Individual PrimaryBorrower { get; set; }
public CoApplicant CoApplicant { get; set; }
public string ModFeeAccount { get; set; }
//3500 is maximum crif note length
[StringLength(3500)]
[RegularExpression(@"[\w\d\s\.\,\&\n\r\@\-\;\'\!]*")]
public string Note { get; set; }
public string PrimaryContactMethod { get; set; }
public string PromoCode { get; set; }
public string LoanTitle { get; set; }
[StringLength(3450)]
public string ClientMessage { get; set; }
public DateTime DisclosureDate { get; set; }
public string IPAddress { get; set; }
public IList<LoanApplicationFile> Files { get; set; }
public LoanApplication()
{
Date = DateTime.Now;
SecuredCardCollateralId = Guid.NewGuid();
Files = [];
}
public LoanApplication(DateTime? loanDate = null, Guid? securedCardCollateralId = null, string loanId = null)
{
Date = loanDate ?? DateTime.Now;
SecuredCardCollateralId = securedCardCollateralId ?? Guid.NewGuid();
Id = loanId ?? null;
Files = [];
}
}
}
@@ -0,0 +1,42 @@
namespace Landmark.OLA.Models.Loan
{
public class LoanApplicationFile
{
public string CosmosLoanId { get; set; }
public Guid FileId { get; set; }
public string Name { get; set; }
public string Section { get; set; }
public string SectionId { get; set; }
public string Description { get; set; }
public LoanApplicationFile(string cosmosLoanId, Guid fileId, string name, string section, string sectionId, string description)
{
CosmosLoanId = cosmosLoanId;
FileId = fileId;
Name = name;
Section = section;
SectionId = sectionId;
Description = description;
}
public string GetBlobPath()
{
return $"{CosmosLoanId}/{FileId}";
}
public Dictionary<string, string> GetMetadata()
{
var metadata = new Dictionary<string, string>
{
{ "Name", Name },
{ "Section", Section },
{ "SectionId", SectionId.ToString() },
{ "Description", Description },
{ "CosmosLoanId", CosmosLoanId }
};
return metadata;
}
}
}
@@ -0,0 +1,34 @@
using Landmark.OLA.Models.Loan.Enums;
using MongoDB.Bson.Serialization.Attributes;
namespace Landmark.OLA.Models.Loan
{
[BsonIgnoreExtraElements]
public class LoanContainer : OlaModel
{
public LoanApplication LoanApplication { get; set; }
public LoanType LoanType { get; set; }
public LoanPage Page { get; set; }
public LoanStatus Status { get; set; }
public LoanError Error { get; set; }
public DateTime Date { get; private set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Branch { get; set; }
public string LoanId { get; set; }
public string MemberId { get; set; }
public string IndividualId { get; set; }
public LoanContainer()
{
Date = DateTime.UtcNow; //allows us to have control over date format
}
public LoanContainer(LoanApplication loanApplication, DateTime? loanDate = null, LoanStatus status = LoanStatus.In_Progress)
{
LoanApplication = loanApplication ?? null;
Date = loanDate ?? DateTime.UtcNow;
Status = status;
}
}
}
@@ -0,0 +1,15 @@
using Landmark.OLA.Models.Loan.Enums;
namespace Landmark.OLA.Models.Loan {
public class LoanError
{
public LoanErrorCode code;
public string message;
public LoanError(LoanErrorCode code, string message)
{
this.code = code;
this.message = message;
}
}
}
@@ -0,0 +1,36 @@
using Landmark.OLA.Models.Loan.Enums;
namespace Landmark.OLA.Models.Loan
{
public class LoanLimits
{
private static Limit EqLimit => new() { min = 10000, max = 250000 };
private static Limit EqHighLimit => new() { min = 10000, max = 500000 };
private static Limit VLimit => new() { min = 250, max = 250000 };
private static Limit MfgHome => new() { min = 250, max = 250000 };
private static Limit SLimit => new() { min = 250, max = 25000 };
private static Limit SpecLimit => new() { min = 250, max = 10000 };
public static Dictionary<LoanType, Limit> Limits => new()
{
{ LoanType.EQ_HELOC_Flex, EqHighLimit },
{ LoanType.EQ_Mtg_Refi_Express, EqLimit },
{ LoanType.EQ_Home_Equity_Fixed, EqHighLimit },
{ LoanType.EQ_Mfg_Home_With_or_Without_Land, MfgHome },
{ LoanType.V_Vehicle, VLimit },
{ LoanType.V_VehiclePreapproval, VLimit },
{ LoanType.M_Boat, VLimit },
{ LoanType.P_Powersport, VLimit },
{ LoanType.T_TrailerMotorhome, MfgHome }, //same limits as mfHome
{ LoanType.S_Signature, SLimit },
{ LoanType.S_Special, SpecLimit },
};
public static bool IsValidAmountForType(LoanType loanType, decimal requestedAmount)
{
var limit = Limits[loanType];
return requestedAmount >= limit.min && requestedAmount <= limit.max;
}
}
}
@@ -0,0 +1,18 @@
namespace Landmark.OLA.Models.Loan
{
public class LoanPage
{
public bool hasPersonal;
public bool hasAddress;
public bool hasEmployment;
public bool hasMemberInfo;
public bool hasSpouseInfo;
public bool hasTattleSpouseInfo;
public bool hasResidenceInfo;
public bool hasVehicleCollateral;
public bool hasHMDA;
public bool hasDisclosure;
public bool hasCollateralInfo;
public bool hasNote;
}
}
@@ -0,0 +1,109 @@
using Landmark.OLA.Models.Loan.Enums;
namespace Landmark.OLA.Models.Loan
{
public static class LoanPurpose
{
//Acceptable values taken from CRIF database
/*
select p.shortname, p.name, p.productid, lp.name, lp.[description],
lp.loanpurposeid, lp.isactivefl from v_RptProduct_v001 as p
inner join v_RptProductLoanPurpose_v001 as plp
on plp.productid = p.productid
inner join v_RptLoanPurpose_v001 as lp
on lp.loanpurposeid = plp.loanpurposeid
order by p.productid
*/
private static readonly List<Purpose> _ccPurposes = new List<Purpose>
{ Purpose.Other, Purpose.Consolidation, Purpose.Reestablish_Credit};
private static readonly List<Purpose> _eqPurposes = new List<Purpose>
{ Purpose.Home_Improvement, Purpose.Home_Purchase, Purpose.Home_Refinance,
Purpose.Other, Purpose.Cash_Out_Refinance };
private static readonly List<Purpose> _mfgHomePurposes = new List<Purpose>
{ Purpose.Home_Improvement, Purpose.Purchase_Manufactured_Home, Purpose.Home_Refinance,
Purpose.Other, Purpose.Cash_Out_Refinance };
private static readonly List<Purpose> _vPurposes = new List<Purpose>
{ Purpose.Purchase, Purpose.Cash_Out_Refinance, Purpose.Refinance_Vehicle };
private static readonly List<Purpose> _mPurposes = new List<Purpose>
{ Purpose.Purchase, Purpose.Refinance_Vehicle };
private static readonly List<Purpose> _pPurposes = new List<Purpose>
{ Purpose.Purchase, Purpose.Refinance_Vehicle };
private static readonly List<Purpose> _tPurposes = new List<Purpose>
{ Purpose.Purchase, Purpose.Refinance_Vehicle };
private static readonly List<Purpose> _sPurposes = new List<Purpose>
{ Purpose.Other, Purpose.Consolidation};
public static Dictionary<LoanType, List<Purpose>> TypePurposes => new Dictionary<LoanType, List<Purpose>>
{
{ LoanType.CC_CashBack, _ccPurposes },
{ LoanType.CC_Rewards, _ccPurposes },
{ LoanType.CC_Student, _ccPurposes },
{ LoanType.CC_Secure, _ccPurposes },
{ LoanType.EQ_HELOC_Flex, _eqPurposes },
{ LoanType.EQ_Mtg_Refi_Express, _eqPurposes },
{ LoanType.EQ_Home_Equity_Fixed, _eqPurposes },
{ LoanType.EQ_Mfg_Home_With_or_Without_Land, _mfgHomePurposes },
{ LoanType.V_Vehicle, _vPurposes },
{ LoanType.V_VehiclePreapproval, _vPurposes },
{ LoanType.M_Boat, _mPurposes },
{ LoanType.P_Powersport, _pPurposes },
{ LoanType.T_TrailerMotorhome, _tPurposes },
{ LoanType.S_Signature, _sPurposes },
{ LoanType.S_Special, _sPurposes },
};
public static bool IsValidPurposeForType(LoanType? type, Purpose? purpose)
{
if (!type.HasValue)
throw new ArgumentException("LoanType cannot be null");
if (!purpose.HasValue)
throw new ArgumentException("Purpose cannot be null");
return IsValidPurposeForType(type.Value, purpose.Value);
}
public static bool IsValidPurposeForType(LoanType type, Purpose purpose)
{
return TypePurposes[type].Contains(purpose);
}
//Enum names and values based on CRIF's v_RptProductLoanPurpose_v001 table
//joined with v_RptProductLoanPurpose_v001
//to find purposes that are active and in use
/*
select distinct lp.loanpurposeid, lp.name,lp.[description]
from v_RptLoanPurpose_v001 as lp
inner join v_RptProductLoanPurpose_v001 as plp
on lp.loanpurposeid = plp.loanpurposeid
where isactivefl = 1
*/
public enum Purpose
{
Home_Improvement = 3,
Home_Purchase = 4,
Home_Refinance = 5,
Purchase_Boat = 8,
Purchase = 12,
Other = 149,
Refinance = 141,
Dental_Expense = 142,
Medical_Expense = 143,
Cash_Out_Refinance = 144,
Refinance_Vehicle = 146,
Consolidation = 148,
Reestablish_Credit = 150,
Purchase_Manufactured_Home = 151,
}
}
}
@@ -0,0 +1,155 @@
using Landmark.OLA.Models.Addresses;
using Landmark.OLA.Models.Addresses.Enums;
using Landmark.OLA.Models.Individuals;
using Landmark.OLA.Models.Individuals.Enums;
using Landmark.OLA.Models.Loan.Enums;
using Landmark.OLA.Models.Residences;
namespace Landmark.OLA.Models.Loan
{
public class MockApplication
{
public readonly LoanApplication LoanApplication =
new(DateTime.Parse("2018-02-21T16:52:47.62"), new Guid("9ed5a50f-279c-49b0-b5b4-d5b614e42501"))
{
LoanType = LoanType.CC_Secure,
RequestedAmount = 1320,
PrimaryContactMethod = "1234567890",
Purpose = LoanPurpose.Purpose.Other,
PrimaryBorrower = new Individual(new Guid("8066fa2a-16ba-4148-b28c-2926ba263c5f"))
{
FirstName = "Jane",
MiddleInitial = "A",
LastName = "Doe",
DOB = new DateTime(2018, 7, 9),
Phone = "1235555555",
PhoneType = PhoneType.Home,
SSN = "000090001",
Email = "[email protected]",
IsMarried = false,
Language = LanguageOption.English,
Address = new CurrentResidenceAddress(new Guid("bf7e502a-9830-43c6-b603-1a32294c7e1a"))
{
Address1 = "123 Main St",
City = "New Berlin",
State = StateOption.WI,
Country = CountryOption.UnitedStates,
PostalCode = "53151",
MonthsResided = 24,
ResidenceType = ResidenceTypeOption.Own,
MonthlyPayment = 100,
},
MailingAddress = new Address(new Guid("f84db562-36a0-4039-9ce5-346a2ba6899b"))
{
Address1 = "321 Main St",
City = "New Berlin",
State = StateOption.WI,
Country = CountryOption.UnitedStates,
PostalCode = "53151"
},
Employers =
[
new Employer(employerId: new Guid("eee4efa3-327f-4ce5-9e8b-8c3e7a865fff"))
{
Name = "College Pro Painters",
Title = "tester",
WorkPhone = "9992245555",
MonthsEmployed = 60,
StartDate = new DateTime(2017, 01, 01),
CurrentEmployer = true,
EmploymentType = EmploymentTypeOption.FullTime,
Language = LanguageOption.English,
Income = new Income
{
IncomeTypeCD = IncomeType.Salary,
SourceName = "Salary",
AmountPerPeriod = 5000,
Frequency = Frequency.Annually,
IncomeStatus = IncomeStatus.IncomeStatus_Included
}
}
]
},
CoApplicant = new CoApplicant(new Guid("ba99037f-df92-46d4-a477-ffecea1f4837"))
{
FirstName = "John",
LastName = "Smith",
DOB = new DateTime(2018, 7, 25),
SSN = "111221111",
Phone = "5555550983",
PhoneType = PhoneType.Mobile,
Email = "[email protected]",
IsMarried = true,
IsMarriedToPrimaryBorrower = false,
Language = LanguageOption.English,
Address = new CurrentResidenceAddress(new Guid("ae795a5f-1ea3-4186-b4b8-e9f9b81e3059"))
{
Address1 = "339 1st St",
Address2 = "#76",
City = "Milwaukee",
State = StateOption.IL,
Country = CountryOption.UnitedStates,
PostalCode = "53202",
ResidenceType = ResidenceTypeOption.Rent,
MonthsResided = 12,
MonthlyPayment = 100,
},
PreviousAddresses =
[
new ResidenceAddress(new Guid("e7e881f0-d371-4371-8022-cce4f700e6d6"))
{
Address1 = "339 1st St",
Address2 = "#80",
City = "Milwaukee",
State = StateOption.WI,
Country = CountryOption.UnitedStates,
PostalCode = "53202",
ResidenceType = ResidenceTypeOption.Rent,
MonthsResided = 28,
},
],
Employers =
[
new Employer(employerId: new Guid("e8436884-0e6c-4144-8de5-1f44c7936a23"))
{
StartDate = new DateTime(2015, 01, 01),
Name = "Chocolate Teapot Manfuacturing Inc",
EmploymentType = EmploymentTypeOption.PartTime,
Title = "Lead Teapot Assembler",
WorkPhone = "5556783241",
CurrentEmployer = true,
Language = LanguageOption.English,
Income = new Income
{
IncomeTypeCD = IncomeType.Salary,
SourceName = "Work",
HoursPerWeek = 24,
AmountPerPeriod = 10,
Frequency = Frequency.Hourly,
IncomeStatus = IncomeStatus.IncomeStatus_Included
},
},
new Employer(employerId: new Guid("58d25f44-1260-428d-ac2c-d8804b06ed66"))
{
StartDate = new DateTime(2015, 01, 01),
Name = "Vanilla Teapot Manfuacturing Coop",
EmploymentType = EmploymentTypeOption.PartTime,
Title = "Junior Teapot Assembler",
WorkPhone = "5559572318",
CurrentEmployer = true,
Language = LanguageOption.English,
Income = new Income
{
IncomeTypeCD = IncomeType.Salary,
SourceName = "Work",
HoursPerWeek = 32,
AmountPerPeriod = 50,
Frequency = Frequency.Hourly,
IncomeStatus = IncomeStatus.IncomeStatus_Included
},
},
],
},
};
}
}
@@ -0,0 +1,223 @@
using System.ComponentModel.DataAnnotations;
namespace Landmark.OLA.Models.Loan
{
public static class TermLengths
{
//All lengths are in months.
public class UiTermOption
{
[Required]
public int value;
[Required]
public string desc;
}
public static List<UiTermOption> AvailableTermOptions =
[
new UiTermOption {value = 12, desc = "12 months / 1 year"},
new UiTermOption {value = 24, desc = "24 months / 2 years"},
new UiTermOption {value = 36, desc = "36 months / 3 years"},
new UiTermOption {value = 48, desc = "48 months / 4 years"},
new UiTermOption {value = 60, desc = "60 months / 5 years"},
new UiTermOption {value = 63, desc = "63 months"},
new UiTermOption {value = 72, desc = "72 months / 6 years"},
new UiTermOption {value = 75, desc = "75 months"},
new UiTermOption {value = 84, desc = "84 months / 7 years"},
new UiTermOption {value = 96, desc = "96 months / 8 years"},
new UiTermOption {value = 120, desc = "120 months / 10 years"},
new UiTermOption {value = 144, desc = "144 months / 12 years"},
new UiTermOption {value = 180, desc = "180 months / 15 years"},
new UiTermOption {value = 240, desc = "240 months / 20 years"}
];
public static List<UiTermOption> AvailableTermOptionsWithoutYears =
[
new UiTermOption {value = 12, desc = "12 months"},
new UiTermOption {value = 24, desc = "24 months"},
new UiTermOption {value = 36, desc = "36 months"},
new UiTermOption {value = 48, desc = "48 months"},
new UiTermOption {value = 60, desc = "60 months"},
new UiTermOption {value = 63, desc = "63 months"},
new UiTermOption {value = 72, desc = "72 months"},
new UiTermOption {value = 75, desc = "75 months"},
new UiTermOption {value = 84, desc = "84 months"},
new UiTermOption {value = 96, desc = "96 months"},
new UiTermOption {value = 120, desc = "120 months"},
new UiTermOption {value = 144, desc = "144 months"},
new UiTermOption {value = 180, desc = "180 months"},
new UiTermOption {value = 240, desc = "240 months"}
];
public static Dictionary<decimal, List<int>> BoatLoansByAmount = new()
{
//Loan amount can be greater than or equal to the amount listed here.
{0,
new List<int>
{
48
}
},
{10000,
new List<int>
{
48,
63,
72,
84
}
},
{20000,
new List<int>
{
48,
63,
72,
84,
120,
180,
}
},
};
public static Dictionary<decimal, List<int>> MfdHomeAndRvByAmount = new()
{
//Loan amount can be greater than or equal to the amount listed here.
{0,
new List<int>
{
48
}
},
{10000,
new List<int>
{
48,
60,
72,
84
}
},
{20000,
new List<int>
{
48,
60,
72,
84,
120,
180
}
},
};
public static List<int> Special =
[
36
];
public static List<int> HomeEquity =
[
60,
84,
120,
180,
240,
];
public static List<int> MortgageRefiExpress =
[
96,
120,
144,
];
public static List<int> VehiclePreApproval =
[
36,
48,
63,
75,
];
public static Dictionary<int, List<int>> TermsByYear = new()
{
{2023,
new List<int>
{
36,
48,
63,
75,
84
}
},
{2022,
new List<int>
{
36,
48,
63,
75
}
},
{2021,
new List<int>
{
36,
48,
63
}
},
{2020,
new List<int>
{
36,
48
}
}
};
public static Dictionary<decimal, List<int>> PowersportByAmount = new()
{
//Loan amount can be greater than or equal to the amount listed here.
{0,
new List<int>
{
36,
48,
63
}
},
{10000,
new List<int>
{
36,
48,
63,
72
}
}
};
public static Dictionary<decimal, List<int>> SignatureByAmount = new()
{
//Loan amount can be greater than or equal to the amount listed here.
{0,
new List<int>
{
12,
24,
36
}
},
{5000,
new List<int>
{
48
}
},
};
}
}
@@ -0,0 +1,33 @@
using FluentValidation;
namespace Landmark.OLA.Models.Loan.Validators
{
public class BranchConfigValidator : AbstractValidator<BranchConfig>
{
public BranchConfigValidator() {
RuleFor(x => x.BranchCodesByZip).Must((x, branchCodes) => NoZipcodeDuplicates(branchCodes))
.WithMessage("You cannot have duplicate zipcodes.");
}
private static bool NoZipcodeDuplicates(List<BranchData> branchData)
{
var matchFound = false;
foreach (var eachMapping in branchData)
{
int matchCount = 0;
foreach (var otherMapping in branchData)
{
if( otherMapping.Zipcode == eachMapping.Zipcode)
{
matchCount++;
}
}
if( matchCount > 1 )
{
matchFound = true;
}
}
return !matchFound;
}
}
}
@@ -0,0 +1,283 @@
using FluentValidation;
using Landmark.OLA.Models.Assets;
using Landmark.OLA.Models.HomeMortgageDisclosureAct.Validators;
using Landmark.OLA.Models.Individuals.Validators;
using Landmark.OLA.Models.Loan.Enums;
namespace Landmark.OLA.Models.Loan.Validators
{
public class LoanApplicationValidator : AbstractValidator<LoanApplication>
{
public LoanApplicationValidator()
{
RuleFor(x => x.PrimaryBorrower).SetValidator(new ApplicantValidator());
//when primary is married and in a state requiring spouse information
When(x =>
(x.PrimaryBorrower.IsMarried ?? false) &&
(x.PrimaryBorrower.Address?.State.HasValue ?? false) &&
ValidationConstants.StatesRequiringSpouseInformation.Contains(x.PrimaryBorrower.Address.State.Value),
() =>
{
//Primary must have spouse data if not married to coapplicant
RuleFor(x => x.PrimaryBorrower.HasAnyNonApplicantSpouse()).Equal(true)
.Unless(x => x.CoApplicant?.IsMarriedToPrimaryBorrower ?? false)
.WithMessage("PrimaryBorrower must include spouse information due to marriage in a community property state.");
});
//when coapp is married and in a state requiring spouse information
When(x =>
(x.CoApplicant?.IsMarried ?? false) &&
(x.CoApplicant?.Address?.State.HasValue ?? false) &&
ValidationConstants.StatesRequiringSpouseInformation.Contains(x.CoApplicant.Address.State.Value),
() =>
{
//coapp must have spouse data if not married to coapplicant
RuleFor(x => x.CoApplicant.HasAnyNonApplicantSpouse()).Equal(true)
.Unless(x => x.CoApplicant?.IsMarriedToPrimaryBorrower ?? false)
.WithMessage("CoApplicant must include spouse information due to marriage in a community property state.");
});
Unless(x => x.CoApplicant is null, () =>
{
RuleFor(x => x.CoApplicant).SetValidator(new ApplicantValidator());
When(x => x.CoApplicant.IsMarriedToPrimaryBorrower, () =>
{
//If the two applicants are married there should be no other spouse information
RuleFor(x => x.PrimaryBorrower.NonApplicantSpouse).Null();
RuleFor(x => x.PrimaryBorrower.DetailedNonApplicantSpouse).Null();
RuleFor(x => x.CoApplicant.NonApplicantSpouse).Null();
RuleFor(x => x.CoApplicant.DetailedNonApplicantSpouse).Null();
});
});
When(x => (x.PrimaryBorrower?.IsMarried ?? false) == false, () =>
{
RuleFor(x => x.PrimaryBorrower.HasAnyNonApplicantSpouse()).Equal(false)
.WithMessage("PrimaryBorrower is set as not married but includes spouse information.");
});
When(x => IsHmdaLoan(x.LoanType), () =>
{
RuleFor(x => x.PrimaryBorrower.HmdaValues).SetValidator(new HmdaValidator());
RuleFor(x => x.CoApplicant.HmdaValues).SetValidator(new HmdaValidator())
.Unless(x => x.CoApplicant is null);
});
When(x => IsVehicleRequired(x.LoanType), () =>
{
RuleFor(x => x.Vehicle).NotNull();
RuleFor(x => x).SetValidator(new VehicleValidator());
});
When(x => IsRealEstateRequired(x.LoanType), () =>
{
RuleFor(x => x.RealEstate).NotNull();
});
When(x => IsTermRequired(x.LoanType), () =>
{
RuleFor(x => x.TermLengthInMonths).NotNull();
RuleFor(x => x.TermLengthInMonths).Must((x, termLength) => IsValidTermLength(x) == true)
.WithMessage("TermLengthInMonths is not set to a valid value for this loan type.");
});
RuleFor(x => x.Purpose).Must((x, purpose) => LoanPurpose.IsValidPurposeForType(x.LoanType, purpose));
Unless(x => x.LoanType.Value == LoanType.CC_CashBack || x.LoanType.Value == LoanType.CC_Rewards || x.LoanType.Value == LoanType.CC_Secure
|| x.LoanType.Value == LoanType.CC_Student, () => {
RuleFor(x => x.RequestedAmount).Must((x, requestedAmount) => LoanLimits.IsValidAmountForType(x.LoanType.Value, requestedAmount.Value))
.WithMessage("The requested loan amount is outside the limits for this product type.");
});
//They actually can, but for now that means something went wrong on the frontend.
//To allow vehicle details on preapprovals, simply remove this validation and everything should likely work.
RuleFor(x => x.Vehicle).Null().When(x => x.LoanType == LoanType.V_VehiclePreapproval)
.WithMessage("Vehicle PreApproval loans cannot include vehicle details");
When(x => IsClientMessageRequired(x.LoanType), () =>
{
RuleFor(x => x.ClientMessage).NotNull();
RuleFor(x => x.ClientMessage.Trim()).Must((x, clientMessage) => clientMessage.Length >= 5)
.WithMessage("Applications for this type of loan must include a client message");
});
}
private bool IsValidTermLength(LoanApplication loanApplication)
{
if ((!loanApplication.LoanType.HasValue) || (!loanApplication.TermLengthInMonths.HasValue))
return false;
List<int> validTermLengths = this.GetValidTermLengthsForLoanType(loanApplication);
return validTermLengths.Contains(loanApplication.TermLengthInMonths.Value);
}
private List<int> GetValidTermLengthsForLoanType(LoanApplication loanApplication)
{
return loanApplication.LoanType.Value switch
{
LoanType.EQ_Mtg_Refi_Express => TermLengths.MortgageRefiExpress,
LoanType.EQ_Home_Equity_Fixed => TermLengths.HomeEquity,
LoanType.V_VehiclePreapproval => TermLengths.VehiclePreApproval,
LoanType.V_Vehicle => GetVehicleTermList(loanApplication.Vehicle),
LoanType.EQ_Mfg_Home_With_or_Without_Land or LoanType.T_TrailerMotorhome => GetMfdHomeAndRvTermList(loanApplication.RequestedAmount.Value),
LoanType.M_Boat => GetBoatTermList(loanApplication.RequestedAmount.Value),
LoanType.P_Powersport => GetPowersportTermList(loanApplication.Vehicle.InitialEstimatedValue.Value),
LoanType.S_Signature => GetSignatureTermList(loanApplication.RequestedAmount.Value),
LoanType.S_Special => GetSpecialTermList(loanApplication.RequestedAmount.Value),
LoanType.CC_CashBack => [],
LoanType.CC_Rewards => [],
LoanType.CC_Student => [],
LoanType.CC_Secure => [],
LoanType.EQ_HELOC_Flex => [],
_ => [],
};
}
private static List<int> GetSignatureTermList(decimal loanAmount)
{
var applicableKeys = TermLengths.SignatureByAmount.Keys.Where(x => loanAmount >= x);
var allowedTerms = new List<int>();
foreach (var key in applicableKeys)
{
allowedTerms.AddRange(TermLengths.SignatureByAmount[key]);
}
return allowedTerms;
}
private static List<int> GetSpecialTermList(decimal loanAmount)
{
var allowedTerms = new List<int>
{
36
};
return allowedTerms;
}
private static List<int> GetMfdHomeAndRvTermList(decimal loanAmount)
{
var availableTermLengths = new List<int>();
foreach (var amount in TermLengths.MfdHomeAndRvByAmount.Keys)
{
if (loanAmount >= amount)
{
availableTermLengths.AddRange(TermLengths.MfdHomeAndRvByAmount[amount]);
}
}
return availableTermLengths;
}
public static List<int> GetVehicleTermList(Vehicle vehicle)
{
if ((vehicle is null) || (!vehicle.Condition.HasValue) || (!vehicle.Year.HasValue))
return [];
var yearList = TermLengths.TermsByYear;
int lookupYear = vehicle.Year.Value;
if (yearList.TryGetValue(lookupYear, out List<int> value))
{
return value;
}
else if (lookupYear >= yearList.First().Key)
{
return yearList.First().Value;
}
else
{
return yearList.Last().Value;
}
}
private static List<int> GetBoatTermList(decimal loanAmount)
{
var applicableKeys = TermLengths.BoatLoansByAmount.Keys.Where(x => loanAmount >= x);
var allowedTerms = new List<int>();
foreach (var key in applicableKeys)
{
allowedTerms.AddRange(TermLengths.BoatLoansByAmount[key]);
}
return allowedTerms;
}
private static List<int> GetPowersportTermList(decimal loanAmount)
{
var applicableKeys = TermLengths.PowersportByAmount.Keys.Where(x => loanAmount >= x);
var allowedTerms = new List<int>();
foreach (var key in applicableKeys)
{
allowedTerms.AddRange(TermLengths.PowersportByAmount[key]);
}
return allowedTerms;
}
public static bool IsTermRequired(LoanType? loanType)
{
if (!loanType.HasValue)
{
return false;
}
return !ValidationConstants.LoansNotRequiringTerm.Contains(loanType.Value);
}
private static bool IsVehicleRequired(LoanType? loanType)
{
if (!loanType.HasValue)
{
return false;
}
return ValidationConstants.LoansRequiringVehicle.Contains(loanType.Value);
}
private static bool IsRealEstateRequired(LoanType? loanType)
{
if (!loanType.HasValue)
{
return false;
}
return ValidationConstants.LoansRequiringRealEstate.Contains(loanType.Value);
}
private static bool IsHmdaLoan(LoanType? loanType)
{
if (!loanType.HasValue)
{
return false;
}
return ValidationConstants.HmdaLoans.Contains(loanType.Value);
}
private static bool IsClientMessageRequired(LoanType? loanType)
{
if (!loanType.HasValue)
{
return false;
}
return loanType.Value == LoanType.S_Special;
}
}
}
@@ -0,0 +1,80 @@
using FluentValidation;
using Landmark.OLA.Models.Assets.Enums;
using Landmark.OLA.Models.Loan.Enums;
namespace Landmark.OLA.Models.Loan.Validators
{
class VehicleValidator : AbstractValidator<LoanApplication>
{
private readonly Dictionary<VehicleType, List<LoanType>> _VehiclesToLoans = new()
{
{ VehicleType.Automobile,
new List<LoanType>
{
LoanType.V_Vehicle,
LoanType.V_VehiclePreapproval,
}
},
{ VehicleType.Motorcycle,
new List<LoanType>
{
LoanType.V_Vehicle,
LoanType.V_VehiclePreapproval,
}
},
{ VehicleType.Boat,
new List<LoanType>
{
LoanType.M_Boat,
}
},
{ VehicleType.ATV,
new List<LoanType>
{
LoanType.P_Powersport,
}
},
{ VehicleType.PWC,
new List<LoanType>
{
LoanType.P_Powersport,
}
},
{ VehicleType.RecreationalVehicle,
new List<LoanType>
{
LoanType.P_Powersport,
}
},
{ VehicleType.Snowmobile,
new List<LoanType>
{
LoanType.P_Powersport,
}
},
{ VehicleType.TrailerMotorHome,
new List<LoanType>
{
LoanType.T_TrailerMotorhome,
}
},
};
public VehicleValidator()
{
RuleFor(x => x.Vehicle.Type).Must((x, vehicleType) => IsAllowedVehicleTypeForLoan(x.LoanType.Value, vehicleType.Value))
.WithMessage($"Vehicle type is not allowed for this loan type.");
}
private bool IsAllowedVehicleTypeForLoan(LoanType loanType, VehicleType vehicleType)
{
if (_VehiclesToLoans.TryGetValue(vehicleType, out var loanTypeList))
{
return loanTypeList.Contains(loanType);
}
return false;
}
}
}