first commit
This commit is contained in:
@@ -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()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
+28
@@ -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
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
+33
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
+283
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
+80
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user