Adding
This commit is contained in:
+38
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using LCU.API.Collections.RepoApi.Domain.Processing;
|
||||
using LCU.Shared.Collections.RepoApiLib.Models;
|
||||
|
||||
namespace LCU.API.Collections.RepoApi.Domain.AlertChecker
|
||||
{
|
||||
public class AuctionOnHoldChecker : IAlertChecker
|
||||
{
|
||||
private const string RehoStatus = "REHO";
|
||||
|
||||
public List<EventAlert> CheckForAlert(RepoAccountProcessingSlip slip)
|
||||
{
|
||||
var newEventAlerts = new List<EventAlert>();
|
||||
foreach (var auctionAssignment in slip.AuctionAssignments)
|
||||
{
|
||||
if (
|
||||
slip.UpdatedRepoAccount.Status == RehoStatus
|
||||
&& auctionAssignment?.HoldStatus != null
|
||||
&& auctionAssignment.HoldStatus > 0)
|
||||
{
|
||||
newEventAlerts.Add(
|
||||
new EventAlert()
|
||||
{
|
||||
RepoId = slip.UpdatedRepoAccount.RepoId,
|
||||
AccountNo = slip.UpdatedRepoAccount.AccountNo,
|
||||
Message = "Auction On Hold",
|
||||
CreatedBy = "Batch",
|
||||
DateAdded = DateTime.Now
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return newEventAlerts.Count > 0 ? newEventAlerts : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using LCU.API.Collections.RepoApi.Domain.Extensions;
|
||||
using LCU.API.Collections.RepoApi.Domain.Processing;
|
||||
using LCU.API.Collections.RepoApi.Extensions;
|
||||
using LCU.Shared.Collections.RepoApiLib.Models;
|
||||
|
||||
namespace LCU.API.Collections.RepoApi.Domain.AlertChecker
|
||||
{
|
||||
public class AuctionVinDifferentChecker : IAlertChecker
|
||||
{
|
||||
public List<EventAlert> CheckForAlert(RepoAccountProcessingSlip slip)
|
||||
{
|
||||
var newEventAlerts = new List<EventAlert>();
|
||||
var repoManagerVins = slip.UpdatedRepoAccount.GetCollateralVinList();
|
||||
foreach (var auctionAssignment in slip.AuctionAssignments)
|
||||
{
|
||||
if (auctionAssignment?.AutoIMS?.VIN != null
|
||||
&& !repoManagerVins.Contains(auctionAssignment.AutoIMS.VIN.Trim().ToUpper()))
|
||||
{
|
||||
newEventAlerts.Add(
|
||||
new EventAlert()
|
||||
{
|
||||
RepoId = slip.UpdatedRepoAccount.RepoId,
|
||||
AccountNo = slip.UpdatedRepoAccount.AccountNo,
|
||||
Message = "Auction VIN Different",
|
||||
SubMessage = FormatSubMessage(auctionAssignment.AutoIMS.VIN.Trim().ToUpper(), repoManagerVins),
|
||||
CreatedBy = "Batch",
|
||||
DateAdded = DateTime.Now
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return newEventAlerts.Count > 0 ? newEventAlerts : null;
|
||||
}
|
||||
|
||||
private static string FormatSubMessage(string auctionAssignmentVin, IReadOnlyCollection<string> vins)
|
||||
{
|
||||
if (vins.Count() == 1)
|
||||
{
|
||||
return
|
||||
$"Auction Assignment VIN: {auctionAssignmentVin} differs from RepoManager VIN: {vins.First()}";
|
||||
}
|
||||
|
||||
var repoVins = vins.Aggregate((x, y) => x + ", " + y);
|
||||
return $"Auction Assignment VIN: {auctionAssignmentVin} is not among RepoManager VINs: {repoVins}";
|
||||
}
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using LCU.API.Collections.RepoApi.Domain.Processing;
|
||||
using LCU.Shared.Collections.RepoApiLib.Models;
|
||||
|
||||
namespace LCU.API.Collections.RepoApi.Domain.AlertChecker
|
||||
{
|
||||
public class CreditAdjustmentChecker : TransactionHistoryChecker
|
||||
{
|
||||
private readonly List<string> _watchedStatuses = new List<string> { "O4R", "REPO", "SOLD" };
|
||||
private readonly List<string> _watchedTransactionTypes = new List<string> { "PDSB", "RPMT" };
|
||||
private const string Message = "Credit Adjustment Received";
|
||||
|
||||
public override List<EventAlert> CheckForAlert(RepoAccountProcessingSlip slip)
|
||||
{
|
||||
return StandardizedCheckForAlert(new AlertProcessingSlip(slip, Message, _watchedStatuses, _watchedTransactionTypes));
|
||||
}
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using LCU.API.Collections.RepoApi.Domain.Processing;
|
||||
using LCU.Shared.Collections.RepoApiLib.Models;
|
||||
|
||||
namespace LCU.API.Collections.RepoApi.Domain.AlertChecker
|
||||
{
|
||||
public class DebitAdjustmentChecker : TransactionHistoryChecker
|
||||
{
|
||||
private readonly List<string> _watchedStatuses = new List<string> { "O4R", "REPO", "SOLD" };
|
||||
private readonly List<string> _watchedTransactionTypes = new List<string> { "CHST", "PRCT" };
|
||||
private const string Message = "Debit Adjustment Received";
|
||||
|
||||
public override List<EventAlert> CheckForAlert(RepoAccountProcessingSlip slip)
|
||||
{
|
||||
return StandardizedCheckForAlert(new AlertProcessingSlip(slip, Message, _watchedStatuses, _watchedTransactionTypes));
|
||||
}
|
||||
}
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using LCU.API.Collections.RepoApi.Domain.Processing;
|
||||
using LCU.Shared.Collections.RepoApiLib.Models;
|
||||
|
||||
namespace LCU.API.Collections.RepoApi.Domain.AlertChecker
|
||||
{
|
||||
public class DocumentNotFoundChecker : IAlertChecker
|
||||
{
|
||||
private readonly string _document;
|
||||
private readonly string _ilActionCode;
|
||||
private readonly string _status;
|
||||
private readonly string _wiActionCode;
|
||||
private const string StateWisconsin = "WI";
|
||||
private const string StateIllinois = "IL";
|
||||
|
||||
public DocumentNotFoundChecker(string document, string wiActionCode, string ilActionCode = null,
|
||||
string status = null)
|
||||
{
|
||||
_document = document;
|
||||
_wiActionCode = wiActionCode.Trim().ToUpper();
|
||||
_ilActionCode = ilActionCode?.Trim().ToUpper();
|
||||
_status = status?.Trim().ToUpper();
|
||||
}
|
||||
|
||||
public List<EventAlert> CheckForAlert(RepoAccountProcessingSlip slip)
|
||||
{
|
||||
if (slip.Letters == null || slip.Member?.Address == null ||
|
||||
(_status != null && slip.UpdatedRepoAccount.Status != _status ||
|
||||
slip.UpdatedRepoAccount.Bankruptcy != null))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var isLetterMissing = false;
|
||||
if (slip.Member.Address.State == StateWisconsin)
|
||||
{
|
||||
isLetterMissing = slip.Letters.ToList().Find(x => x.ActionCode == _wiActionCode) == null;
|
||||
}
|
||||
else if (_ilActionCode != null && slip.Member.Address.State == StateIllinois)
|
||||
{
|
||||
isLetterMissing = slip.Letters.ToList().Find(x => x.ActionCode == _ilActionCode) == null;
|
||||
}
|
||||
|
||||
if (isLetterMissing)
|
||||
{
|
||||
return new List<EventAlert>
|
||||
{
|
||||
new EventAlert()
|
||||
{
|
||||
RepoId = slip.UpdatedRepoAccount.RepoId,
|
||||
AccountNo = slip.UpdatedRepoAccount.AccountNo,
|
||||
Message = _document + " Not Found",
|
||||
CreatedBy = "Batch",
|
||||
DateAdded = DateTime.Now
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
using System.Collections.Generic;
|
||||
using LCU.API.Collections.RepoApi.Domain.Processing;
|
||||
using EventAlert = LCU.Shared.Collections.RepoApiLib.Models.EventAlert;
|
||||
|
||||
namespace LCU.API.Collections.RepoApi.Domain.AlertChecker
|
||||
{
|
||||
public interface IAlertChecker
|
||||
{
|
||||
List<EventAlert> CheckForAlert(RepoAccountProcessingSlip slip);
|
||||
}
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using LCU.API.Collections.RepoApi.Domain.Processing;
|
||||
using LCU.Shared.Collections.RepoApiLib.Models;
|
||||
|
||||
namespace LCU.API.Collections.RepoApi.Domain.AlertChecker
|
||||
{
|
||||
public class NoticeOfSurplusDeficiencyNotSentChecker : IAlertChecker
|
||||
{
|
||||
private const int OwnershipTypeImportant = 6;
|
||||
private const int DaysBeforeConsideredNotSent = 2;
|
||||
|
||||
public List<EventAlert> CheckForAlert(RepoAccountProcessingSlip slip)
|
||||
{
|
||||
var updatedRepoAccount = slip.UpdatedRepoAccount;
|
||||
if (updatedRepoAccount.RefundStatus?.RefundsReceivedDate == null || updatedRepoAccount.DateClosed != null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var letterSentBy = DateTime.Now.AddDays(-DaysBeforeConsideredNotSent).Date;
|
||||
if (updatedRepoAccount.RefundStatus.RefundsReceivedDate < letterSentBy && updatedRepoAccount.Bankruptcy == null)
|
||||
{
|
||||
return new List<EventAlert>
|
||||
{
|
||||
new EventAlert()
|
||||
{
|
||||
RepoId = updatedRepoAccount.RepoId,
|
||||
AccountNo = updatedRepoAccount.AccountNo,
|
||||
Message = "Notice of Surplus Deficiency Letter Not Sent",
|
||||
CreatedBy = "Batch",
|
||||
DateAdded = DateTime.Now,
|
||||
EmailRecipient = "[email protected]",
|
||||
EmailBody = CreateEmailBody(updatedRepoAccount)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private string CreateEmailBody(RepoAccount repoAccount)
|
||||
{
|
||||
var message = "Notice of Surplus Deficiency Not Sent.<br/><br/>";
|
||||
var member = repoAccount.Borrowers?.First(b => b.OwnershipType == OwnershipTypeImportant);
|
||||
var memberName = "Member Name: " + member?.IndividualName + "<br/>";
|
||||
var accountNo = "Account No: " + repoAccount.AccountNo + "<br/>";
|
||||
return string.Concat(message, memberName, accountNo);
|
||||
}
|
||||
}
|
||||
}
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using LCU.API.Collections.CollectionsApiLib.Models;
|
||||
using LCU.API.Collections.RepoApi.Domain.Extensions;
|
||||
using LCU.API.Collections.RepoApi.Domain.Processing;
|
||||
using LCU.API.Collections.RepoApi.Extensions;
|
||||
using LCU.Shared.Collections.RepoApiLib.Models;
|
||||
|
||||
namespace LCU.API.Collections.RepoApi.Domain.AlertChecker
|
||||
{
|
||||
public class O4rNoRepoChecker : IAlertChecker
|
||||
{
|
||||
private readonly RepoType _repoType;
|
||||
private const string O4RStatus = "O4R";
|
||||
private const string EmailDestination = "[email protected]";
|
||||
|
||||
public O4rNoRepoChecker(RepoType repoType)
|
||||
{
|
||||
_repoType = repoType;
|
||||
}
|
||||
|
||||
private int GetDayCount()
|
||||
{
|
||||
switch (_repoType)
|
||||
{
|
||||
case RepoType.Voluntary: return 2;
|
||||
case RepoType.Involuntary: return 60;
|
||||
case RepoType.PreSkip: return 31;
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private int GetRepeatDayCount()
|
||||
{
|
||||
switch (_repoType)
|
||||
{
|
||||
case RepoType.Voluntary: return 1;
|
||||
case RepoType.Involuntary: return 30;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public bool ShouldSendRepeatedAlert(int daysInStatus, int dayCount, int repeatCount)
|
||||
{
|
||||
return (
|
||||
daysInStatus > dayCount
|
||||
&& (repeatCount > 0)
|
||||
&& ((daysInStatus - dayCount) % repeatCount == 0)
|
||||
);
|
||||
}
|
||||
|
||||
public bool IsRepoAssigned(RepoAccount repoAccount)
|
||||
{
|
||||
foreach (var collateral in repoAccount.Collaterals)
|
||||
{
|
||||
if (collateral.RepoCompanySelections?.FirstOrDefault(x => x.RepoCompanyAssignmentDate != null && x.RepoType == _repoType) != null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public List<EventAlert> CheckForAlert(RepoAccountProcessingSlip slip)
|
||||
{
|
||||
var daysInStatus = slip.UpdatedRepoAccount.GetDaysInStatus(O4RStatus);
|
||||
if (daysInStatus > 0 && slip.UpdatedRepoAccount.Status == O4RStatus)
|
||||
{
|
||||
// In order to reduce duplicate notifications, do not create a notification if no repo is assigned.
|
||||
// An 'action needed' item will be created for O4R No Repo if no repo is assigned. A notification is redundant.
|
||||
if (daysInStatus < GetDayCount() || !IsRepoAssigned(slip.UpdatedRepoAccount))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (daysInStatus == GetDayCount() || ShouldSendRepeatedAlert(daysInStatus, GetDayCount(), GetRepeatDayCount()))
|
||||
{
|
||||
return new List<EventAlert>
|
||||
{
|
||||
new EventAlert()
|
||||
{
|
||||
RepoId = slip.UpdatedRepoAccount.RepoId,
|
||||
AccountNo = slip.UpdatedRepoAccount.AccountNo,
|
||||
Message = "O4R No Repo",
|
||||
CreatedBy = "Batch",
|
||||
DateAdded = DateTime.Now,
|
||||
EmailRecipient = _repoType == RepoType.PreSkip
|
||||
? EmailDestination
|
||||
: null,
|
||||
EmailBody = _repoType == RepoType.PreSkip
|
||||
? CreateEmailBody(slip.UpdatedRepoAccount)
|
||||
: null
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private string CreateEmailBody(RepoAccount repoAccount)
|
||||
{
|
||||
var message = "PreSkip has ended, please file a Skip Claim.<br/><br/>";
|
||||
var member = repoAccount.Borrowers?.First(b => b.OwnershipType == 6);
|
||||
var memberName = "Member Name: " + member?.IndividualName + "<br/>";
|
||||
var accountNo = "Account No: " + repoAccount.AccountNo + "<br/>";
|
||||
var collateral = repoAccount.Collaterals.FirstOrDefault(c => c.RepoCompanySelections?.FirstOrDefault(x => x.RepoType == _repoType) != null);
|
||||
var year = "Year: " + collateral.Year + "<br/>";
|
||||
var make = "Make: " + collateral.Make + "<br/>";
|
||||
var model = "Model: " + collateral.Model + "<br/>";
|
||||
var vin = "VIN: " + collateral.Vin + "<br/>";
|
||||
|
||||
return string.Concat(message, memberName, accountNo, year, make, model, vin);
|
||||
}
|
||||
}
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using LCU.API.Collections.RepoApi.Domain.Processing;
|
||||
using LCU.Shared.Collections.RepoApiLib.Models;
|
||||
using LCU.Shared.Collections.RepoApiLib.Models.Consumer;
|
||||
|
||||
namespace LCU.API.Collections.RepoApi.Domain.AlertChecker
|
||||
{
|
||||
public class PaymentReceivedChecker : TransactionHistoryChecker
|
||||
{
|
||||
private readonly List<string> _watchedStatuses = new List<string> { "O4R", "REPO", "SOLD" };
|
||||
private readonly List<string> _watchedTransactionTypes = new List<string> { "COFR", "POFF", "EXT", "SPMT", "XPMT" };
|
||||
private const string EmailDestination = "[email protected]";
|
||||
|
||||
public override List<EventAlert> CheckForAlert(RepoAccountProcessingSlip slip)
|
||||
{
|
||||
var newEventAlerts = new List<EventAlert>();
|
||||
var results = GetRecentTransactionsFromType(_watchedTransactionTypes, slip.TransactionHistory);
|
||||
if (results != null && _watchedStatuses.Contains(slip.UpdatedRepoAccount.Status))
|
||||
{
|
||||
var dueDate = slip.Loan?.NextDueDate.ToString(CultureInfo.CurrentCulture) ?? "Unknown";
|
||||
foreach (var result in results)
|
||||
{
|
||||
newEventAlerts.Add(new EventAlert()
|
||||
{
|
||||
RepoId = slip.UpdatedRepoAccount.RepoId,
|
||||
AccountNo = slip.UpdatedRepoAccount.AccountNo,
|
||||
Message = "Payment Received",
|
||||
SubMessage = FormatTransactionMessage(result),
|
||||
CreatedBy = "Batch",
|
||||
DateAdded = DateTime.Now,
|
||||
EmailRecipient = EmailDestination,
|
||||
EmailBody = CreateEmailBody(slip.UpdatedRepoAccount, result, dueDate)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return newEventAlerts.Count > 0 ? newEventAlerts : null;
|
||||
}
|
||||
|
||||
private string CreateEmailBody(RepoAccount repoAccount, CoreTransaction coreTransaction, string nextDueDate)
|
||||
{
|
||||
var message = "Loan Payment<br/><br/>";
|
||||
var member = repoAccount.Borrowers?.First(b => b.OwnershipType == 6);
|
||||
var memberName = "Member Name: " + member?.IndividualName + "<br/>";
|
||||
var accountNo = "Account No: " + repoAccount.AccountNo + "<br/>";
|
||||
var paymentAmount = "Payment Amount: " + coreTransaction.amount + "<br/>";
|
||||
var nextDueDateString = "Next Due Date: " + nextDueDate + "<br/>";
|
||||
var loanBalance = "Loan Balance: " + coreTransaction.runningBalance + "<br/>";
|
||||
|
||||
return string.Concat(message, memberName, accountNo, paymentAmount, nextDueDateString, loanBalance);
|
||||
}
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using LCU.API.Collections.RepoApi.Domain.Processing;
|
||||
using LCU.Shared.Collections.RepoApiLib.Models;
|
||||
|
||||
namespace LCU.API.Collections.RepoApi.Domain.AlertChecker
|
||||
{
|
||||
public class RedemptionEndedNoTitleOrderedChecker : IAlertChecker
|
||||
{
|
||||
private const string RepoStatus = "REPO";
|
||||
private const int RedemptionExpiredDaysToWait = 7;
|
||||
|
||||
public List<EventAlert> CheckForAlert(RepoAccountProcessingSlip slip)
|
||||
{
|
||||
if (slip.UpdatedRepoAccount.Status.ToUpper() == RepoStatus &&
|
||||
DateTime.Now.Date > slip.UpdatedRepoAccount.RedemptionExpiredDate?.AddDays(RedemptionExpiredDaysToWait) &&
|
||||
slip.UpdatedRepoAccount.Collaterals.FirstOrDefault(x => x.RetitledInLandmarkName == null) != null)
|
||||
{
|
||||
return new List<EventAlert>
|
||||
{
|
||||
new EventAlert()
|
||||
{
|
||||
RepoId = slip.UpdatedRepoAccount.RepoId,
|
||||
AccountNo = slip.UpdatedRepoAccount.AccountNo,
|
||||
Message = "Redemption Ended No Title Ordered",
|
||||
CreatedBy = "Batch",
|
||||
DateAdded = DateTime.Now
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using LCU.API.Collections.RepoApi.Domain.Extensions;
|
||||
using LCU.API.Collections.RepoApi.Domain.Processing;
|
||||
using LCU.API.Collections.RepoApi.Extensions;
|
||||
using LCU.Shared.Collections.RepoApiLib.Models;
|
||||
|
||||
namespace LCU.API.Collections.RepoApi.Domain.AlertChecker
|
||||
{
|
||||
public class RepoNotMovedChecker : IAlertChecker
|
||||
{
|
||||
private readonly int _dayCount;
|
||||
private const string RepoStatus = "REPO";
|
||||
private const int DaysBeforeSendEmail = 14;
|
||||
private const string EmailDestination = "[email protected]";
|
||||
|
||||
public RepoNotMovedChecker(int dayCount = 30)
|
||||
{
|
||||
_dayCount = dayCount;
|
||||
}
|
||||
|
||||
public List<EventAlert> CheckForAlert(RepoAccountProcessingSlip slip)
|
||||
{
|
||||
var daysInStatus = slip.UpdatedRepoAccount.GetDaysInStatus(RepoStatus);
|
||||
if (slip.UpdatedRepoAccount.Status.ToUpper() != RepoStatus ||
|
||||
slip.UpdatedRepoAccount.Collaterals == null || !slip.UpdatedRepoAccount.Collaterals.Any()
|
||||
|| daysInStatus < _dayCount)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
foreach (var collateral in slip.UpdatedRepoAccount.Collaterals)
|
||||
{
|
||||
if (collateral.AuctionAssignmentToCollaterals != null &&
|
||||
collateral.AuctionAssignmentToCollaterals.Any())
|
||||
{
|
||||
var assignment = collateral.AuctionAssignmentToCollaterals
|
||||
.Where(x => x.AuctionAssignment != null && x.AuctionAssignment.DateSubmitted == null)
|
||||
.ToList();
|
||||
|
||||
if (assignment.Any() && daysInStatus >= _dayCount)
|
||||
{
|
||||
return new List<EventAlert>
|
||||
{
|
||||
new EventAlert()
|
||||
{
|
||||
RepoId = slip.UpdatedRepoAccount.RepoId,
|
||||
AccountNo = slip.UpdatedRepoAccount.AccountNo,
|
||||
Message = "Repo Not Moved",
|
||||
CreatedBy = "Batch",
|
||||
DateAdded = DateTime.Now,
|
||||
EmailRecipient = daysInStatus == DaysBeforeSendEmail
|
||||
? EmailDestination
|
||||
: null,
|
||||
EmailBody = daysInStatus == DaysBeforeSendEmail
|
||||
? string.Format("{0} Account status REPO, Not Moved for extended time.", slip.UpdatedRepoAccount.AccountNo)
|
||||
: null
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using LCU.API.Collections.RepoApi.Domain.Extensions;
|
||||
using LCU.API.Collections.RepoApi.Domain.Processing;
|
||||
using LCU.API.Collections.RepoApi.Extensions;
|
||||
using EventAlert = LCU.Shared.Collections.RepoApiLib.Models.EventAlert;
|
||||
|
||||
namespace LCU.API.Collections.RepoApi.Domain.AlertChecker
|
||||
{
|
||||
public class RepoNotSoldChecker : IAlertChecker
|
||||
{
|
||||
private readonly int _dayCount;
|
||||
private readonly int _repeatDayCount;
|
||||
private const string RepoStatus = "REPO";
|
||||
private const string DestinationEmail = "[email protected]";
|
||||
|
||||
public RepoNotSoldChecker(int dayCount = 30, int repeatDayCount = 0)
|
||||
{
|
||||
_dayCount = dayCount;
|
||||
_repeatDayCount = repeatDayCount;
|
||||
}
|
||||
|
||||
public List<EventAlert> CheckForAlert(RepoAccountProcessingSlip slip)
|
||||
{
|
||||
var status = slip.UpdatedRepoAccount.Status.ToUpper().Trim();
|
||||
var days = slip.UpdatedRepoAccount.GetDaysInStatus(status);
|
||||
if (status == RepoStatus && days > 0)
|
||||
{
|
||||
if ((days == _dayCount) || days >= _dayCount && ((days - _dayCount) % _repeatDayCount == 0))
|
||||
{
|
||||
var member = slip.UpdatedRepoAccount.Borrowers?.First(b => b.OwnershipType == 6);
|
||||
return new List<EventAlert>
|
||||
{
|
||||
new EventAlert()
|
||||
{
|
||||
RepoId = slip.UpdatedRepoAccount.RepoId,
|
||||
AccountNo = slip.UpdatedRepoAccount.AccountNo,
|
||||
Message = "Repo Not Sold",
|
||||
CreatedBy = "Batch",
|
||||
DateAdded = DateTime.Now,
|
||||
EmailRecipient = DestinationEmail,
|
||||
EmailBody = string.Format("{0} {1} Account status REPO, Not Sold for extended time.",
|
||||
slip.UpdatedRepoAccount.AccountNo, member?.IndividualName)
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using LCU.API.Collections.CollectionsApiLib.Models;
|
||||
using LCU.API.Collections.RepoApi.Domain.Processing;
|
||||
using LCU.Shared.Collections.RepoApiLib.Models;
|
||||
|
||||
namespace LCU.API.Collections.RepoApi.Domain.AlertChecker
|
||||
{
|
||||
public class RtcLetterNotFoundChecker : IAlertChecker
|
||||
{
|
||||
private readonly string _document;
|
||||
private readonly IEnumerable<string> _actionCodes;
|
||||
private const string O4RStatus = "O4R";
|
||||
private const string StateWisconsin = "WI";
|
||||
|
||||
public RtcLetterNotFoundChecker(string document, IEnumerable<string> actionCodes)
|
||||
{
|
||||
_document = document;
|
||||
_actionCodes = actionCodes.Select(code => code.Trim().ToUpper());
|
||||
}
|
||||
|
||||
public List<EventAlert> CheckForAlert(RepoAccountProcessingSlip slip)
|
||||
{
|
||||
if (slip.Member?.Address == null || slip.Member.Address.State != StateWisconsin || slip.Letters == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
foreach (var collateral in slip.UpdatedRepoAccount.Collaterals)
|
||||
{
|
||||
if (collateral.RepoCompanySelections?.FirstOrDefault(x => x.RepoType == RepoType.Voluntary) != null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
var letters = slip.Letters;
|
||||
if (IsLetterMissing(letters) && (slip.UpdatedRepoAccount.Status.ToUpper().Trim() == O4RStatus))
|
||||
{
|
||||
return new List<EventAlert>
|
||||
{
|
||||
new EventAlert()
|
||||
{
|
||||
RepoId = slip.UpdatedRepoAccount.RepoId,
|
||||
AccountNo = slip.UpdatedRepoAccount.AccountNo,
|
||||
Message = _document + " Not Found",
|
||||
CreatedBy = "Batch",
|
||||
DateAdded = DateTime.Now
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private bool IsLetterMissing(IEnumerable<RepoLetter> letters)
|
||||
{
|
||||
var sentLetterCodes = letters.Select(x => x.ActionCode).ToList();
|
||||
foreach (var actionCode in _actionCodes)
|
||||
{
|
||||
if (sentLetterCodes.Contains(actionCode))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using LCU.API.Collections.RepoApi.Domain.Processing;
|
||||
using LCU.Shared.Collections.RepoApiLib.Models;
|
||||
|
||||
namespace LCU.API.Collections.RepoApi.Domain.AlertChecker
|
||||
{
|
||||
public class SaleFundsReceivedChecker : TransactionHistoryChecker
|
||||
{
|
||||
private readonly List<string> _watchedStatuses = null;
|
||||
private readonly List<string> _watchedTransactionTypes = new List<string> { "PRCT" };
|
||||
private const string Message = "Sale Funds Received";
|
||||
|
||||
public override List<EventAlert> CheckForAlert(RepoAccountProcessingSlip slip)
|
||||
{
|
||||
return StandardizedCheckForAlert(new AlertProcessingSlip(slip, Message, _watchedStatuses, _watchedTransactionTypes));
|
||||
}
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using LCU.API.Collections.RepoApi.Domain.Extensions;
|
||||
using LCU.API.Collections.RepoApi.Domain.Processing;
|
||||
using LCU.API.Collections.RepoApi.Extensions;
|
||||
using LCU.Shared.Collections.RepoApiLib.Models;
|
||||
|
||||
namespace LCU.API.Collections.RepoApi.Domain.AlertChecker
|
||||
{
|
||||
public class SkipEndChecker : IAlertChecker
|
||||
{
|
||||
private readonly int _dayCount;
|
||||
private const string O4RStatus = "O4R";
|
||||
|
||||
public SkipEndChecker(int dayCount = 30)
|
||||
{
|
||||
_dayCount = dayCount;
|
||||
}
|
||||
|
||||
public List<EventAlert> CheckForAlert(RepoAccountProcessingSlip slip)
|
||||
{
|
||||
if (slip.UpdatedRepoAccount.Status == O4RStatus
|
||||
&& slip.UpdatedRepoAccount.GetDaysInStatus(O4RStatus) >= _dayCount
|
||||
&& slip.UpdatedRepoAccount.IsCurrentlySkipClaim())
|
||||
{
|
||||
return new List<EventAlert>
|
||||
{
|
||||
new EventAlert()
|
||||
{
|
||||
RepoId = slip.UpdatedRepoAccount.RepoId,
|
||||
AccountNo = slip.UpdatedRepoAccount.AccountNo,
|
||||
Message = "Skip Claim Ended",
|
||||
CreatedBy = "Batch",
|
||||
DateAdded = DateTime.Now
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using LCU.API.Collections.RepoApi.Domain.Extensions;
|
||||
using LCU.API.Collections.RepoApi.Domain.Processing;
|
||||
using LCU.API.Collections.RepoApi.Extensions;
|
||||
using LCU.Shared.Collections.RepoApiLib.Models;
|
||||
|
||||
namespace LCU.API.Collections.RepoApi.Domain.AlertChecker
|
||||
{
|
||||
public class SkipNotPaidChecker : IAlertChecker
|
||||
{
|
||||
private readonly int _dayCount;
|
||||
private readonly int _repeatDayCount;
|
||||
private const string O4RStatus = "O4R";
|
||||
private const string RepoSubStatusPaidSkip = "PSKP";
|
||||
|
||||
|
||||
public SkipNotPaidChecker(int dayCount = 30, int repeatDayCount = 0)
|
||||
{
|
||||
_dayCount = dayCount;
|
||||
_repeatDayCount = repeatDayCount;
|
||||
}
|
||||
|
||||
public List<EventAlert> CheckForAlert(RepoAccountProcessingSlip slip)
|
||||
{
|
||||
var days = slip.UpdatedRepoAccount.GetDaysInStatus(O4RStatus);
|
||||
if (slip.UpdatedRepoAccount.Status == O4RStatus
|
||||
&& days >= _dayCount && slip.UpdatedRepoAccount.IsCurrentlySkipClaim())
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(slip.UpdatedRepoAccount.SubStatus) &&
|
||||
slip.UpdatedRepoAccount.SubStatus.Trim().ToUpper() == RepoSubStatusPaidSkip)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if ((days == _dayCount) || days >= _dayCount && ((days - _dayCount) % _repeatDayCount == 0))
|
||||
{
|
||||
return new List<EventAlert>
|
||||
{
|
||||
new EventAlert()
|
||||
{
|
||||
RepoId = slip.UpdatedRepoAccount.RepoId,
|
||||
AccountNo = slip.UpdatedRepoAccount.AccountNo,
|
||||
Message = "Skip Not Paid",
|
||||
CreatedBy = "Batch",
|
||||
DateAdded = DateTime.Now
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using LCU.API.Collections.RepoApi.Domain.Processing;
|
||||
using LCU.Shared.Collections.RepoApiLib.Models;
|
||||
|
||||
namespace LCU.API.Collections.RepoApi.Domain.AlertChecker
|
||||
{
|
||||
public class SkipPaidChecker : IAlertChecker
|
||||
{
|
||||
public const string RepoSubStatusPaidSkip = "PSKP";
|
||||
|
||||
public List<EventAlert> CheckForAlert(RepoAccountProcessingSlip slip)
|
||||
{
|
||||
if (slip.UpdatedRepoAccount != null && !string.IsNullOrWhiteSpace(slip.UpdatedRepoAccount.SubStatus) &&
|
||||
slip.UpdatedRepoAccount.SubStatus.Trim().ToUpper() == RepoSubStatusPaidSkip &&
|
||||
slip.UpdatedRepoAccount.Status.ToUpper().Trim() != RepoSubStatusPaidSkip)
|
||||
{
|
||||
slip.UpdatedRepoAccount.Status = RepoSubStatusPaidSkip; // TODO Does this get saved? Is it ok to do? (NO)
|
||||
return new List<EventAlert>
|
||||
{
|
||||
new EventAlert()
|
||||
{
|
||||
RepoId = slip.UpdatedRepoAccount.RepoId,
|
||||
AccountNo = slip.UpdatedRepoAccount.AccountNo,
|
||||
Message = "Skip Claim Paid",
|
||||
CreatedBy = "Batch",
|
||||
DateAdded = DateTime.Now
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using LCU.API.Collections.RepoApi.Domain.Processing;
|
||||
using LCU.Shared.Collections.RepoApiLib.Models;
|
||||
|
||||
namespace LCU.API.Collections.RepoApi.Domain.AlertChecker
|
||||
{
|
||||
public class SoldNoProceedsChecker : IAlertChecker
|
||||
{
|
||||
private const int DaysToWaitForSold = 5;
|
||||
|
||||
public List<EventAlert> CheckForAlert(RepoAccountProcessingSlip slip)
|
||||
{
|
||||
foreach (var auctionAssignment in slip.AuctionAssignments)
|
||||
{
|
||||
if (
|
||||
auctionAssignment?.AutoIMS?.SoldDate != null
|
||||
&& auctionAssignment.AutoIMS.SoldDate < DateTime.Now.AddDays(-DaysToWaitForSold)
|
||||
&& auctionAssignment.AutoIMS.FundsSent == null)
|
||||
{
|
||||
return new List<EventAlert>
|
||||
{
|
||||
new EventAlert()
|
||||
{
|
||||
RepoId = slip.UpdatedRepoAccount.RepoId,
|
||||
AccountNo = slip.UpdatedRepoAccount.AccountNo,
|
||||
Message = "Sold No Proceeds",
|
||||
CreatedBy = "Batch",
|
||||
DateAdded = DateTime.Now
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using LCU.API.Collections.RepoApi.Domain.Processing;
|
||||
using LCU.Shared.Collections.RepoApiLib.Models;
|
||||
|
||||
namespace LCU.API.Collections.RepoApi.Domain.AlertChecker
|
||||
{
|
||||
public class StatusChangeChecker : IAlertChecker
|
||||
{
|
||||
private readonly string _watchStatus;
|
||||
private readonly IEnumerable<string> _fromStatusList;
|
||||
private const string NoStatus = "";
|
||||
|
||||
public StatusChangeChecker(string watchStatus, IEnumerable<string> fromStatusList = null)
|
||||
{
|
||||
_watchStatus = watchStatus.Trim().ToUpper();
|
||||
_fromStatusList = fromStatusList;
|
||||
}
|
||||
|
||||
public List<EventAlert> CheckForAlert(RepoAccountProcessingSlip slip)
|
||||
{
|
||||
var originalStatus = slip.ExistingRepoAccount?.Status.ToUpper().Trim();
|
||||
var updatedStatus = slip.UpdatedRepoAccount.Status.ToUpper().Trim();
|
||||
|
||||
// new account.
|
||||
if (originalStatus == null)
|
||||
{
|
||||
originalStatus = NoStatus;
|
||||
}
|
||||
|
||||
if (updatedStatus == _watchStatus
|
||||
&& originalStatus != _watchStatus
|
||||
&& (_fromStatusList == null || _fromStatusList.Contains(originalStatus)))
|
||||
{
|
||||
return new List<EventAlert>
|
||||
{
|
||||
new EventAlert()
|
||||
{
|
||||
RepoId = slip.UpdatedRepoAccount.RepoId,
|
||||
AccountNo = slip.UpdatedRepoAccount.AccountNo,
|
||||
Message = "Status Changed to " + _watchStatus,
|
||||
SubMessage =
|
||||
$"Previously {originalStatus}. I confirm that I have updated the Status to {updatedStatus} in RDN.",
|
||||
CreatedBy = "Batch",
|
||||
DateAdded = DateTime.Now
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using LCU.API.Collections.RepoApi.Domain.Extensions;
|
||||
using LCU.API.Collections.RepoApi.Domain.Processing;
|
||||
using LCU.API.Collections.RepoApi.Extensions;
|
||||
using EventAlert = LCU.Shared.Collections.RepoApiLib.Models.EventAlert;
|
||||
|
||||
namespace LCU.API.Collections.RepoApi.Domain.AlertChecker
|
||||
{
|
||||
public class TimeInStatusChecker : IAlertChecker
|
||||
{
|
||||
private readonly string _checkStatus;
|
||||
private readonly int _dayCount;
|
||||
private readonly int _repeatDayCount;
|
||||
|
||||
public TimeInStatusChecker(string checkStatus, int dayCount = 30, int repeatDayCount = 0)
|
||||
{
|
||||
_checkStatus = checkStatus;
|
||||
_dayCount = dayCount;
|
||||
_repeatDayCount = repeatDayCount;
|
||||
}
|
||||
|
||||
public List<EventAlert> CheckForAlert(RepoAccountProcessingSlip slip)
|
||||
{
|
||||
var status = slip.UpdatedRepoAccount.Status.ToUpper().Trim();
|
||||
var days = slip.UpdatedRepoAccount.GetDaysInStatus(status);
|
||||
if (days <= 0 || status != _checkStatus)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if ((days == _dayCount) || days >= _dayCount && ((days - _dayCount) % _repeatDayCount == 0))
|
||||
{
|
||||
return new List<EventAlert>
|
||||
{
|
||||
new EventAlert()
|
||||
{
|
||||
RepoId = slip.UpdatedRepoAccount.RepoId,
|
||||
AccountNo = slip.UpdatedRepoAccount.AccountNo,
|
||||
Message = days + " days in " + _checkStatus,
|
||||
CreatedBy = "Batch",
|
||||
DateAdded = DateTime.Now
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using LCU.API.Collections.RepoApi.Domain.Processing;
|
||||
using LCU.Shared.Collections.RepoApiLib.Models;
|
||||
using LCU.Shared.Collections.RepoApiLib.Models.Consumer;
|
||||
|
||||
namespace LCU.API.Collections.RepoApi.Domain.AlertChecker
|
||||
{
|
||||
public abstract class TransactionHistoryChecker : IAlertChecker
|
||||
{
|
||||
private readonly int _daysInPastToSearch;
|
||||
|
||||
protected TransactionHistoryChecker(int daysInPastToSearch = 3)
|
||||
{
|
||||
_daysInPastToSearch = daysInPastToSearch;
|
||||
}
|
||||
|
||||
public abstract List<EventAlert> CheckForAlert(RepoAccountProcessingSlip slip);
|
||||
|
||||
protected List<EventAlert> StandardizedCheckForAlert(AlertProcessingSlip alertProcessingSlip)
|
||||
{
|
||||
var newEventAlerts = new List<EventAlert>();
|
||||
var results = GetRecentTransactionsFromType
|
||||
(
|
||||
alertProcessingSlip.WatchedTransactionTypes,
|
||||
alertProcessingSlip.AccountProcessingSlip.TransactionHistory
|
||||
);
|
||||
if (results != null && AccountStatusIsQualified(alertProcessingSlip.WatchedStatusTypes,
|
||||
alertProcessingSlip.AccountProcessingSlip.UpdatedRepoAccount.Status))
|
||||
{
|
||||
foreach (var result in results)
|
||||
{
|
||||
newEventAlerts.Add(new EventAlert()
|
||||
{
|
||||
RepoId = alertProcessingSlip.AccountProcessingSlip.UpdatedRepoAccount.RepoId,
|
||||
AccountNo = alertProcessingSlip.AccountProcessingSlip.UpdatedRepoAccount.AccountNo,
|
||||
Message = alertProcessingSlip.Message,
|
||||
SubMessage = FormatTransactionMessage(result),
|
||||
CreatedBy = "Batch",
|
||||
DateAdded = DateTime.Now
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return newEventAlerts.Count > 0 ? newEventAlerts : null;
|
||||
}
|
||||
|
||||
private static bool AccountStatusIsQualified(List<string> watchedStatusTypes, string status)
|
||||
{
|
||||
return watchedStatusTypes?.Contains(status.ToUpper()) ?? true;
|
||||
}
|
||||
|
||||
public static string FormatTransactionMessage(CoreTransaction transaction)
|
||||
{
|
||||
var message = "";
|
||||
if (transaction.transactionTypeCode.ToLower().Contains("undo"))
|
||||
{
|
||||
message += "***TRANSACTION UNDONE*** - ";
|
||||
}
|
||||
|
||||
return message +
|
||||
$"Transaction Type: \"{transaction.transactionTypeCode}\" | Posting: {transaction.postingDate} | Transaction: {transaction.amount?.ToString("C2")} | Balance: {transaction.runningBalance?.ToString("C2")} | Description: \"{transaction.transactionTypeDescription}\"";
|
||||
}
|
||||
|
||||
protected List<CoreTransaction> GetRecentTransactionsFromType(List<string> transactionTypes, IReadOnlyCollection<CoreTransaction> transactions)
|
||||
{
|
||||
var returnItems = new List<CoreTransaction>();
|
||||
|
||||
if (transactions != null && transactions.Any())
|
||||
{
|
||||
foreach (var transactionType in transactionTypes)
|
||||
{
|
||||
returnItems.AddRange(GetRecentTransactionsFromType(transactionType, _daysInPastToSearch, transactions));
|
||||
}
|
||||
}
|
||||
|
||||
return returnItems.Count > 0 ? returnItems : null;
|
||||
}
|
||||
|
||||
private static IEnumerable<CoreTransaction> GetRecentTransactionsFromType(string transactionType, int daysInPast, IReadOnlyCollection<CoreTransaction> transactions)
|
||||
{
|
||||
return (
|
||||
from transaction in transactions
|
||||
where (
|
||||
transaction.postingDate > DateTime.Now.AddDays(-daysInPast)
|
||||
&& transaction.transactionTypeCode.ToLower().Contains(transactionType.ToLower()
|
||||
)
|
||||
)
|
||||
select transaction
|
||||
).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user