385 lines
16 KiB
C#
385 lines
16 KiB
C#
using System.Xml.Linq;
|
|
using CRIF.ACTion.Common;
|
|
using CRIF.ACTion.Common.Builders;
|
|
using CRIF.ACTion.Configuration;
|
|
using CRIF.ACTion.Services.Landmark.DistributionChannel;
|
|
using CRIF.ACTion.Loan.Assets;
|
|
using CRIF.ACTion.Loan.Individuals;
|
|
using Landmark.OLA.Models.Addresses;
|
|
using Landmark.OLA.Models.Individuals;
|
|
using Landmark.OLA.Models.Loan;
|
|
using Landmark.OLA.Models.Loan.Enums;
|
|
|
|
namespace CRIF.ACTion.Loan
|
|
{
|
|
public class LoanApplicationRequestBuilder : BuilderBase, IParties, IAppDetails, IAppParties,
|
|
IAddresses, IOrg, IProperties, IVehicleValuations, IAppNotes
|
|
{
|
|
public readonly LoanApplication LoanApplication;
|
|
private readonly Guid OrgRef;
|
|
public readonly Guid _sourceChannel;
|
|
public readonly Guid _servicingChannel;
|
|
|
|
public AppPartiesSection AppParties { get; set; }
|
|
|
|
public PartiesSection Parties { get; set; }
|
|
|
|
public AppDetailsSection AppDetails { get; set; }
|
|
|
|
public AddressesSection Addresses { get; set; }
|
|
|
|
public AppNotesSectionBuilder AppNotes { get; set; }
|
|
|
|
public OrgSection Org { get; set; }
|
|
|
|
public PropertiesSection Properties { get; set; }
|
|
|
|
public VehicleValuationsSection VehicleValuations { get; set; }
|
|
|
|
public LoanApplicationRequestBuilder(LoanApplication loanApplication,
|
|
CrifSettings settings,
|
|
Guid? orgRef = null,
|
|
Guid? sourceChannel = null,
|
|
Guid? servicingChannel = null,
|
|
IDistributionChannelLookupService distributionChannelLookupService = null)
|
|
: base(CrifNamespaces.App.Namespace, settings)
|
|
{
|
|
LoanApplication = loanApplication;
|
|
|
|
OrgRef = orgRef ?? Guid.NewGuid();
|
|
_sourceChannel = sourceChannel ?? Guid.NewGuid();
|
|
_servicingChannel = servicingChannel ?? Guid.NewGuid();
|
|
|
|
AppParties = new AppPartiesSection(CrifRequestSectionNamespace, settings);
|
|
Parties = new PartiesSection(CrifRequestSectionNamespace, settings, distributionChannelLookupService);
|
|
Addresses = new AddressesSection(CrifRequestSectionNamespace, settings);
|
|
AppNotes = new AppNotesSectionBuilder(CrifRequestSectionNamespace, settings);
|
|
Org = new OrgSection(CrifRequestSectionNamespace, settings);
|
|
Properties = new PropertiesSection(CrifRequestSectionNamespace, settings);
|
|
VehicleValuations = new VehicleValuationsSection(CrifRequestSectionNamespace, settings);
|
|
}
|
|
|
|
public override XElement Build(params XElement[] content)
|
|
{
|
|
Org.SetOrgId(OrgRef);
|
|
|
|
Parties.AddOrganizationParty(OrgRef);
|
|
|
|
Parties.AddSourceChannelParty(_sourceChannel, LoanApplication.LoanType.Value);
|
|
|
|
Parties.AddServicingChannelParty(_servicingChannel, LoanApplication?.PrimaryBorrower?.Address?.PostalCode ?? "");
|
|
|
|
AppParties.SetSourceChannel(_sourceChannel);
|
|
|
|
AppParties.SetServicingChannel(_servicingChannel);
|
|
|
|
AddApplicationNotes();
|
|
|
|
var productDetails = CreateProductDetails(LoanApplication.LoanType, _settings);
|
|
productDetails.SetDetails(this);
|
|
|
|
Guid? externalSpouseId = null;
|
|
if (LoanApplication.CoApplicant is not null && LoanApplication.CoApplicant.IsMarriedToPrimaryBorrower)
|
|
{
|
|
externalSpouseId = LoanApplication.CoApplicant.Id;
|
|
}
|
|
|
|
|
|
PropertyLot mfgHomeLot = null;
|
|
|
|
if (!(LoanApplication.ManufacturedHome?.Lot?.RentalAmt is null))
|
|
{
|
|
//needed to pass long possible Lot rent amount
|
|
mfgHomeLot = LoanApplication.ManufacturedHome.Lot;
|
|
}
|
|
|
|
ProcessIndividual(LoanApplication.PrimaryBorrower,
|
|
AppPartiesSection.PartyType.primaryBorrower,
|
|
externalSpouseId,
|
|
mfgHomeLot);
|
|
|
|
if (LoanApplication.CoApplicant is not null)
|
|
{
|
|
ProcessIndividual(LoanApplication.CoApplicant, AppPartiesSection.PartyType.borrower);
|
|
|
|
CheckForAndProcessSpouses(LoanApplication.CoApplicant);
|
|
}
|
|
|
|
CheckForAndProcessSpouses(LoanApplication.PrimaryBorrower, true);
|
|
|
|
var createAppElement = GetCreateAppElement(LoanApplication.Date,
|
|
AppParties.Build(),
|
|
Parties.Build(),
|
|
AppDetails.Build(),
|
|
Properties.Build(),
|
|
Addresses.Build(),
|
|
AppNotes.Build(),
|
|
Org.Build(),
|
|
VehicleValuations.Build());
|
|
|
|
var baseElement = base.Build(createAppElement);
|
|
|
|
return baseElement;
|
|
}
|
|
|
|
private void AddApplicationNotes()
|
|
{
|
|
AppNotes.AddAppNote("IP: " + LoanApplication.IPAddress + ", DISCLOSURE DATE: " + ConvertUtcToCentral(LoanApplication.DisclosureDate));
|
|
if (!string.IsNullOrWhiteSpace(LoanApplication.PrimaryContactMethod))
|
|
{
|
|
AppNotes.AddAppNote("PRIMARY CONTACT METHOD: " + LoanApplication.PrimaryContactMethod);
|
|
}
|
|
|
|
if (!string.IsNullOrWhiteSpace(LoanApplication.PromoCode))
|
|
{
|
|
AppNotes.AddAppNote("PROMO CODE: " + LoanApplication.PromoCode);
|
|
}
|
|
|
|
if (!string.IsNullOrWhiteSpace(LoanApplication.Note))
|
|
{
|
|
AppNotes.AddAppNote(LoanApplication.Note);
|
|
}
|
|
|
|
if (LoanApplication.RealEstate is not null && LoanApplication.RealEstate.LienPosition is not null &&
|
|
LoanApplication.LoanTitle != "Heloc Rate Modification")
|
|
{
|
|
if (LoanApplication.RealEstate.LienPosition.PayoffFirstMortgage)
|
|
{
|
|
AppNotes.AddAppNote("I INTEND TO PAYOFF MY FIRST MORTGAGE WITH THIS LOAN.");
|
|
}
|
|
if (LoanApplication.RealEstate.LienPosition.PayoffSecondMortgage)
|
|
{
|
|
AppNotes.AddAppNote("I INTEND TO PAYOFF MY SECOND MORTGAGE WITH THIS LOAN.");
|
|
}
|
|
}
|
|
|
|
if (LoanApplication.LoanType == LoanType.S_Special)
|
|
{
|
|
AppNotes.AddAppNote("Special Loan: " + LoanApplication.LoanTitle);
|
|
AppNotes.AddAppNote("Client Message: " + LoanApplication.ClientMessage);
|
|
}
|
|
|
|
if (LoanApplication.LoanType == LoanType.S_Signature && !string.IsNullOrWhiteSpace(LoanApplication.PurposeOfLoanSignature))
|
|
{
|
|
AppNotes.AddAppNote("PURPOSE OF LOAN: " + LoanApplication.PurposeOfLoanSignature);
|
|
}
|
|
|
|
if (LoanApplication.LoanType == LoanType.EQ_HELOC_Flex) {
|
|
if (!string.IsNullOrWhiteSpace(LoanApplication.ModFeeAccount))
|
|
{
|
|
AppNotes.AddAppNote("MOD FEE ACCOUNT: " + LoanApplication.ModFeeAccount);
|
|
}
|
|
|
|
if (!string.IsNullOrWhiteSpace(LoanApplication.PrimaryBorrower.PrimaryApplicantEmail))
|
|
{
|
|
AppNotes.AddAppNote("PRIMARY APPLICANT EMAIL (E-DOC SIGNATURE): " + LoanApplication.PrimaryBorrower.PrimaryApplicantEmail);
|
|
}
|
|
|
|
if (!string.IsNullOrWhiteSpace(LoanApplication.PrimaryBorrower.CoApplicantEmail))
|
|
{
|
|
AppNotes.AddAppNote("CO-APPLICANT EMAIL (E-DOC SIGNATURE): " + LoanApplication.PrimaryBorrower.CoApplicantEmail);
|
|
}
|
|
}
|
|
|
|
if (LoanApplication.Vehicle != null)
|
|
{
|
|
if (LoanApplication.Vehicle.Type == Landmark.OLA.Models.Assets.Enums.VehicleType.Motorcycle
|
|
&& !string.IsNullOrWhiteSpace(LoanApplication.Vehicle.StateTitled))
|
|
{
|
|
AppNotes.AddAppNote("State of Registration: " + LoanApplication.Vehicle.StateTitled);
|
|
}
|
|
|
|
if (LoanApplication.Vehicle.Lien == "yes")
|
|
{
|
|
AppNotes.AddAppNote("Vehicle has a lien");
|
|
}
|
|
|
|
var seller = LoanApplication.Vehicle?.Seller;
|
|
|
|
if (seller != null)
|
|
{
|
|
|
|
var sellerStr = "INTERESTED IN BUYING FROM A " + seller.Value;
|
|
sellerStr = sellerStr.Replace('_', ' ');
|
|
|
|
if (!string.IsNullOrWhiteSpace(LoanApplication.Vehicle.DealerName) || !string.IsNullOrWhiteSpace(LoanApplication.Vehicle.DealerPhone))
|
|
{
|
|
bool bothSeller = !string.IsNullOrWhiteSpace(LoanApplication.Vehicle.DealerName) && !string.IsNullOrWhiteSpace(LoanApplication.Vehicle.DealerPhone);
|
|
|
|
sellerStr += ":";
|
|
sellerStr += !string.IsNullOrWhiteSpace(LoanApplication.Vehicle.DealerName) ? " " + LoanApplication.Vehicle.DealerName : "";
|
|
sellerStr += bothSeller ? " - " : "";
|
|
sellerStr += !string.IsNullOrWhiteSpace(LoanApplication.Vehicle.DealerPhone) ? " " + String.Format("{0:(###) ###-####}", LoanApplication.Vehicle.DealerPhone) : "";
|
|
}
|
|
|
|
AppNotes.AddAppNote(sellerStr);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void CheckForAndProcessSpouses(IApplicant individual, bool isPrimaryBorrowerSpouse = false)
|
|
{
|
|
var partyType = isPrimaryBorrowerSpouse ? AppPartiesSection.PartyType.NonSigningSpouseMarriedToPrimary
|
|
: AppPartiesSection.PartyType.NonSigningSpouseMarriedToCoBorrower;
|
|
|
|
//Validation can esnure that only one of these holds data
|
|
|
|
if (individual.NonApplicantSpouse is not null)
|
|
{
|
|
ProcessIndividual(individual.NonApplicantSpouse, partyType);
|
|
}
|
|
|
|
if (individual.DetailedNonApplicantSpouse is not null)
|
|
{
|
|
ProcessIndividual(individual.DetailedNonApplicantSpouse, partyType);
|
|
}
|
|
}
|
|
|
|
private void ProcessIndividual(INonApplicant individual, AppPartiesSection.PartyType partyType)
|
|
{
|
|
var isMarried = partyType == AppPartiesSection.PartyType.NonSigningSpouseMarriedToCoBorrower
|
|
|| partyType == AppPartiesSection.PartyType.NonSigningSpouseMarriedToPrimary;
|
|
|
|
Parties.AddNonApplicant(individual, isMarried);
|
|
|
|
Addresses.AddAddress(individual.MailingAddress,
|
|
ContactMechanisms.CrifContactMechanism.CurrentAddress);
|
|
}
|
|
|
|
private void ProcessIndividual(IApplicant individual,
|
|
AppPartiesSection.PartyType partyType,
|
|
Guid? externalSpouseId = null,
|
|
PropertyLot mfgHomeLot = null)
|
|
{
|
|
Parties.AddApplicant(individual, externalSpouseId, mfgHomeLot);
|
|
|
|
ProcessHistory(individual, partyType);
|
|
}
|
|
|
|
private void ProcessIndividual(IIndividualHistory individual, AppPartiesSection.PartyType partyType)
|
|
{
|
|
var isMarried = partyType == AppPartiesSection.PartyType.NonSigningSpouseMarriedToCoBorrower
|
|
|| partyType == AppPartiesSection.PartyType.NonSigningSpouseMarriedToPrimary;
|
|
|
|
bool requiresHMDA = IsHMDARequired(LoanApplication.LoanType.ToString());
|
|
Parties.AddHistory(individual, isMarried, requiresHMDA);
|
|
|
|
ProcessHistory(individual, partyType);
|
|
}
|
|
|
|
public static bool IsHMDARequired(string loanType)
|
|
{
|
|
HMDALoanType parsedLoanType;
|
|
if (Enum.TryParse(loanType, out parsedLoanType))
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private void ProcessHistory(IIndividualHistory individual, AppPartiesSection.PartyType partyType)
|
|
{
|
|
AddHistory(individual, partyType);
|
|
|
|
if (individual.Employers?.Count > 0)
|
|
{
|
|
foreach (var employer in individual.Employers)
|
|
{
|
|
Parties.AddEmployer(employer);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static XElement GetCreateAppElement(DateTime date, params XElement[] content)
|
|
{
|
|
var element = new XElement(CrifNamespaces.Empty + "createApp",
|
|
new XElement(CrifNamespaces.App + "application",
|
|
new XAttribute(CrifNamespaces.App + "appReceivedDate",
|
|
Dates.GetFormattedApplicationDate(date)),
|
|
new XAttribute(CrifNamespaces.App + "appInitiatedDate",
|
|
Dates.GetFormattedApplicationDate(date)),
|
|
new XAttribute(CrifNamespaces.App + "priorityCD", "High"), //Per vendor examples
|
|
content));
|
|
|
|
return element;
|
|
}
|
|
|
|
private void AddHistory(IIndividualHistory individual, AppPartiesSection.PartyType partyType)
|
|
{
|
|
AppParties.AddIndividualParty(individual, partyType, individual.HasOptedOutTCPA);
|
|
|
|
Addresses.AddAddress(individual.Address,
|
|
ContactMechanisms.CrifContactMechanism.CurrentAddress);
|
|
|
|
if (!(individual.MailingAddress is null))
|
|
{
|
|
Addresses.AddAddress(individual.MailingAddress, ContactMechanisms.CrifContactMechanism.MailingAddress);
|
|
}
|
|
|
|
if (individual.PreviousAddresses?.Count > 0)
|
|
{
|
|
foreach (var previousAddress in individual.PreviousAddresses)
|
|
{
|
|
Addresses.AddAddress(previousAddress, ContactMechanisms.CrifContactMechanism.PreviousAddress);
|
|
}
|
|
}
|
|
}
|
|
|
|
private ILoanApplicationRequestBuilder CreateProductDetails(LoanType? loanType, CrifSettings settings)
|
|
{
|
|
if (!loanType.HasValue)
|
|
throw new ArgumentException("LoanType must have a value.");
|
|
|
|
if (settings == null)
|
|
throw new ArgumentException("Product Details requires CrifSettings");
|
|
|
|
ILoanApplicationRequestBuilder appBuilder = null;
|
|
|
|
switch (loanType.Value)
|
|
{
|
|
case LoanType.CC_CashBack:
|
|
case LoanType.CC_Rewards:
|
|
case LoanType.CC_Student:
|
|
case LoanType.CC_Secure:
|
|
appBuilder = new CreditCardAppBuilder(settings);
|
|
break;
|
|
case LoanType.EQ_HELOC_Flex:
|
|
appBuilder = new HelocFlexAppBuilder(settings);
|
|
break;
|
|
case LoanType.EQ_Mtg_Refi_Express:
|
|
case LoanType.EQ_Home_Equity_Fixed:
|
|
appBuilder = new RealEstateEquityAppBuilder(settings);
|
|
break;
|
|
case LoanType.EQ_Mfg_Home_With_or_Without_Land:
|
|
appBuilder = new MfgHousingAndLandAppBuilder(settings);
|
|
break;
|
|
case LoanType.V_VehiclePreapproval:
|
|
case LoanType.V_Vehicle:
|
|
case LoanType.M_Boat:
|
|
case LoanType.P_Powersport:
|
|
case LoanType.T_TrailerMotorhome:
|
|
appBuilder = new VehicleAppBuilder(settings);
|
|
break;
|
|
case LoanType.S_Special:
|
|
case LoanType.S_Signature:
|
|
appBuilder = new SignatureAppBuilder(settings);
|
|
break;
|
|
default:
|
|
throw new ArgumentOutOfRangeException(nameof(loanType), $"The requested loan type {loanType.Value} is not implemented.");
|
|
}
|
|
|
|
return appBuilder;
|
|
}
|
|
|
|
private static string ConvertUtcToCentral(DateTime date)
|
|
{
|
|
TimeZoneInfo timeZone = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
|
|
DateTime centralDate = TimeZoneInfo.ConvertTimeFromUtc(date.ToUniversalTime(), timeZone);
|
|
return centralDate.ToString("g");
|
|
}
|
|
}
|
|
}
|