This commit is contained in:
Zeeshaun
2026-04-20 14:47:24 -05:00
parent 89057eceea
commit 8b3ea92501
485 changed files with 71042 additions and 0 deletions
@@ -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;
}
}
}
@@ -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}";
}
}
}
@@ -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));
}
}
}
@@ -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));
}
}
}
@@ -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;
}
}
}
@@ -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);
}
}
@@ -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);
}
}
}
@@ -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);
}
}
}
@@ -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);
}
}
}
@@ -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;
}
}
}
@@ -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;
}
}
}
@@ -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;
}
}
}
@@ -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;
}
}
}
@@ -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));
}
}
}
@@ -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;
}
}
}
@@ -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;
}
}
}
@@ -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;
}
}
}
@@ -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;
}
}
}
@@ -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;
}
}
}
@@ -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;
}
}
}
@@ -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();
}
}
}