This commit is contained in:
Zeeshaun
2026-03-17 11:09:46 -05:00
parent bd1a9744ad
commit 6e7edcfe1b
332 changed files with 64174 additions and 0 deletions
@@ -0,0 +1,94 @@
import moment, { Moment } from "moment";
import {
combineCaseAndAccountHistories
} from "./AccountHistoryService";
import {
HistorySource,
HistoryType,
ITemenosHistory
} from "./service-types/AccountHistoryTypes";
const getCreatedYear = (createdDate : Moment | undefined): string =>{
// eslint-disable-next-line eqeqeq
if(createdDate == undefined){
return "";
}else{
return createdDate.format("YYYY");
}
};
describe("AccountHistoryService Tests", () => {
var caseHistories: ITemenosHistory[], accountHistories:ITemenosHistory[];
beforeEach(() => {
caseHistories = [{
"Message": "Redemption Calc IL Date Set",
"Name": "Completed",
"UserId": 0,
"Created": moment("2020-09-22T06:22:51.49"),
"Type": HistoryType.Comment,
"Source": HistorySource.Case
}, {
"Message": "Redemption Calc IL 30%",
"Name": "Completed",
"UserId": 2,
"Created": moment("2018-09-22T06:15:28.19"),
"Type": HistoryType.Worfklow,
"Source": HistorySource.Case
}, {
"Message": "Redemption Calc WI Date Set",
"Name": "Completed",
"UserId": 4,
"Created": moment("2016-09-22T06:10:11.63"),
"Type": HistoryType.Comment,
"Source": HistorySource.Case
}];
accountHistories = [{
"Message": "Redemption Calc IL Date Set",
"Name": "Completed",
"UserId": 1,
"Created": moment("2019-09-22T06:22:51.49"),
"Type": HistoryType.Comment,
"Source": HistorySource.Account
}, {
"Message": "Redemption Calc IL 30%",
"Name": "Completed",
"UserId": 3,
"Created": moment("2017-09-22T06:15:28.19"),
"Type": HistoryType.Worfklow,
"Source": HistorySource.Account
}, {
"Message": "Redemption Calc WI Date Set",
"Name": "Completed",
"UserId": 5,
"Created": moment("2016-09-22T06:10:11.63"),
"Type": HistoryType.Comment,
"Source": HistorySource.Account
}];
});
it("Properly Sorts the ", () => {
var combinedHistories = combineCaseAndAccountHistories(caseHistories, accountHistories);
expect(getCreatedYear(combinedHistories[0].Created)).toBe("2020");
expect(combinedHistories[0].UserId).toBe(0);
expect(getCreatedYear(combinedHistories[1].Created)).toBe("2019");
expect(combinedHistories[1].UserId).toBe(1);
expect(getCreatedYear(combinedHistories[2].Created)).toBe("2018");
expect(combinedHistories[2].UserId).toBe(2);
expect(getCreatedYear(combinedHistories[3].Created)).toBe("2017");
expect(combinedHistories[3].UserId).toBe(3);
expect(getCreatedYear(combinedHistories[4].Created)).toBe("2016");
expect(combinedHistories[4].UserId).toBeGreaterThanOrEqual(4);
expect(getCreatedYear(combinedHistories[5].Created)).toBe("2016");
expect(combinedHistories[5].UserId).toBeGreaterThanOrEqual(4);
});
});
@@ -0,0 +1,46 @@
import { HistorySource, HistoryType, ITemenosHistory} from "./service-types/AccountHistoryTypes";
export function combineCaseAndAccountHistories(caseHistories: ITemenosHistory[] | undefined, accountHistories: ITemenosHistory[]| undefined): ITemenosHistory[]{
var allHistory : ITemenosHistory[] = [];
if(caseHistories) allHistory = allHistory.concat(caseHistories);
if(accountHistories) allHistory = allHistory.concat(accountHistories);
allHistory = allHistory.sort((a,b) => {
if(a.Created && b.Created){
return (a.Created > b.Created)? -1 : 1;
}else if(!a.Created&& !b.Created){
return 1;
}else if(a.Created && !b.Created){
return -1;
}else{
return 0;
}
});
return allHistory;
}
export function getHistoryTypeString(historyType: HistoryType) : string{
switch(historyType){
case HistoryType.Worfklow:
return "Workflow";
case HistoryType.Comment:
return "Comment";
case HistoryType.Letter:
return "Letter";
default:
return historyType;
}
}
export function getHistorySourceStrng(historySource: HistorySource) : string{
switch(historySource){
case HistorySource.Account:
return "Account";
case HistorySource.Case:
return "Case";
default:
return historySource;
}
}
@@ -0,0 +1,30 @@
import {IAuctionHouse} from "../reducers/AuctionHouseReducer";
const clonedeep = require("lodash.clonedeep");
export default class AuctionHouseService{
public static CopyAndInsertIntoAuctionHouses(auctionHouseMap: IAuctionHouse[] | undefined, newAuctionHouse: IAuctionHouse){
if(!auctionHouseMap){
return [newAuctionHouse];
}
const copiedAuctionHouses = clonedeep(auctionHouseMap);
copiedAuctionHouses.push(newAuctionHouse);
return copiedAuctionHouses;
}
public static CopyAndUpdateAuctionHouse(auctionHouseMap: IAuctionHouse[] | undefined, auctionHouseToUpdate: IAuctionHouse){
if(!auctionHouseMap){
return [auctionHouseToUpdate];
}
const copiedAuctionHouses = clonedeep(auctionHouseMap);
return copiedAuctionHouses.map((house: IAuctionHouse) => {
if(house.auctionID === auctionHouseToUpdate.auctionID){
return auctionHouseToUpdate;
}else{
return house;
}
});
}
}
@@ -0,0 +1,64 @@
import {ICollectionsAccount, ICollectionsCase} from "../reducers/CollectionsAccountReducer"
class CollectionsAccountService{
public static mapResponseToCollectionsAccount(response : any[]) : ICollectionsAccount[]{
var ret : ICollectionsAccount[] = [];
response.forEach(r => {
var collectionsAccount: ICollectionsAccount = {
accountId : r.AccountId,
accountIdentifier: r.AccountIdentifier,
accountNumber: r.AccountNumber,
accountStatus: r.AccountStatus,
accountTypeId: r.AccountTypeId,
activeFlag: r.ActiveFlag,
amountLastPaid: r.AmountLastPaid,
balance: r.Balance,
bankruptcyFlag: r.BankruptcyFlag,
branch: r.Branch,
dueDate: r.DueDate,
firstPaymentDueDate: r.FirstPaymentDueDate,
originalLoanAmount: r.OriginalLoanAmount,
originalLoanDate: r.OriginalLoanDate,
dqAmount: r.DQAmount,
daysDq: r.DaysDq,
cases : this.mapResponsesToCollectionsCase(r.Cases)
}
ret.push(collectionsAccount);
});
return ret;
}
public static mapResponsesToCollectionsCase(cases: any[]) : ICollectionsCase[]{
var ret: ICollectionsCase[] = [];
cases.forEach(c => {
var collectionsCase: ICollectionsCase = {
caseId: c.CaseId,
caseNumber: c.CaseNumber,
caseDescription: c.CaseDescription,
caseSTageId: c.CaseStageId,
repoStatus: c.RepoStatus,
caseStatusId: c.CaseStatusId,
caseTitle: c.CaseTitle,
caseTypeBasisId: c.CaseTypeBasisId,
caseTypeId: c.CaseTypeId,
closedDate: c.ClosedDate,
createDate: c.CreatedDate,
createdUserId: c.CreatedUserId,
currentStageDate: c.CurrentStageDate,
currentStatusDate: c.CurrentStatusDate,
lastReviewDate: c.LastReviewDate,
nextReviewDate: c.NextReviewDate,
stage1CompletionDate: c.Stage1CompletionDate,
stage2CompletionDate: c.Stage2CompletionDate,
stage3CompletionDate: c.Stage3CompletionDate,
stage4CompletionDate: c.Stage4CompletionDate,
stage5CompletionDate: c.Stage5CompletionDate
}
ret.push(collectionsCase);
});
return ret;
}
}
export default CollectionsAccountService;
@@ -0,0 +1,50 @@
import * as FileSaver from "file-saver";
import * as XLSX from "xlsx";
import { WorkBook } from "xlsx";
import { IReport } from "../reducers/ReportingReducer";
export default class ExportService {
static fileType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8";
static fileExtension = ".xlsx";
public static ExportReport(report: IReport, name: string) {
var simpleDataTable =
[report.dataTable.headers]
.concat(
report.dataTable.rows.map(row =>
row.cells.map(cell => {
if (cell.value !== null && cell.value !== undefined)
{
return cell.value;
}
return cell.display;
})
)
);
var simpleReportTable: string[][] = [];
if (report.reportTable) {
simpleReportTable =
[report.reportTable.headers]
.concat(
report.reportTable.cells.map(row =>
row.map(cell => {
if (cell.value !== null && cell.value !== undefined)
{
return cell.value;
}
return cell.display;
})
)
);
}
const reportTableWS = XLSX.utils.json_to_sheet(simpleReportTable);
const dataTableWS = XLSX.utils.json_to_sheet(simpleDataTable);
const wb: WorkBook = {Sheets: {"report": reportTableWS, "data": dataTableWS}, SheetNames: ["report", "data"]};
const excelBuffer = XLSX.write(wb, {bookType: "xlsx", type: "array"});
const data = new Blob([excelBuffer], {type: ExportService.fileType});
FileSaver.saveAs(data, name + ExportService.fileExtension);
}
}
@@ -0,0 +1,103 @@
import FactoidService from './FactoidService';
import { IFactoidResponse } from './service-types/FactoidTypes';
import { IRepoAccount } from './service-types/RepoAccountTypes';
describe('FactoidService', () => {
const createTestConvertedRepoAccount = (repoId: number) => {
return {
repoId: repoId,
borrowers: [],
collaterals: [],
repoStatusChanges: [],
};
};
it ('ConvertResponsesToFactoids() Returns Expected Value Without Mutations', () => {
const dummyFactoidResponses: IFactoidResponse[] = [
{
name: 'Dummy Name #1',
description: 'Desc. #1',
fontAwesomeIcon: 'fa-test #1',
cumulativeValue: '12.5',
records: [
{
repoId: 1
} as IRepoAccount,
{
repoId: 2
} as IRepoAccount,
]
},
{
name: 'Dummy Name #2',
description: 'Desc. #2',
fontAwesomeIcon: 'fa-test #2',
cumulativeValue: '25%',
records: [
{
repoId: 1
} as IRepoAccount,
{
repoId: 4
} as IRepoAccount,
]
}
];
const createdFactoids = FactoidService.CreateFactoidsFromResponse(dummyFactoidResponses);
expect(createdFactoids).toEqual([
{
name: 'Dummy Name #1',
description: 'Desc. #1',
fontAwesomeIcon: 'fa-test #1',
cumulativeValue: '12.5',
factoidAccountIds: [1, 2]
},
{
name: 'Dummy Name #2',
description: 'Desc. #2',
fontAwesomeIcon: 'fa-test #2',
cumulativeValue: '25%',
factoidAccountIds: [1, 4]
}
]);
expect(createdFactoids).not.toBe(dummyFactoidResponses);
});
it ('ExtractRepoAccountsFromFactoidResponses() Returns all RepoAccounts', () => {
expect(FactoidService.ExtractRepoAccountsFromFactoidResponses([
{
records: [
{ repoId: 1 },
{ repoId: 2 },
{ repoId: 3 },
{ repoId: 4 }
]
} as IFactoidResponse,
{
records: [
{ repoId: 2 },
{ repoId: 5 }
]
} as IFactoidResponse,
{
records: [
{ repoId: 1 },
{ repoId: 6 }
]
} as IFactoidResponse
])).toEqual([
createTestConvertedRepoAccount(1),
createTestConvertedRepoAccount(2),
createTestConvertedRepoAccount(3),
createTestConvertedRepoAccount(4),
createTestConvertedRepoAccount(2),
createTestConvertedRepoAccount(5),
createTestConvertedRepoAccount(1),
createTestConvertedRepoAccount(6)
]);
});
});
@@ -0,0 +1,34 @@
import { IFactoid, IFactoidResponse } from "./service-types/FactoidTypes";
import RepoAccountService from "./RepoAccountService";
import { IRepoAccount } from "./service-types/RepoAccountTypes";
class FactoidService {
public static CreateFactoidsFromResponse(factoidResponses: IFactoidResponse[]): IFactoid[] {
return factoidResponses.map((factoidResponse) => {
return {
cumulativeValue: factoidResponse.cumulativeValue,
name: factoidResponse.name,
description: factoidResponse.description,
fontAwesomeIcon: factoidResponse.fontAwesomeIcon,
factoidAccountIds: RepoAccountService.CreateRepoAccountIdMap(factoidResponse.records),
};
});
}
/**
* NOTE: This will return duplicates if duplicates exist.
*/
public static ExtractRepoAccountsFromFactoidResponses(factoidResponses: IFactoidResponse[]): IRepoAccount[] {
return factoidResponses.reduce((reducedAccounts: IRepoAccount[], currentFactoid) =>
{
RepoAccountService.ConvertResponseToRepoAccounts(currentFactoid.records);
return reducedAccounts.concat(currentFactoid.records);
},
[]
);
}
}
export default FactoidService;
@@ -0,0 +1,87 @@
import HashRouterService from "./HashRouterService";
describe('HashRouterService', () => {
it ('Creates HashSelector from Valid Route Strings', () => {
const hashSelector = HashRouterService.createHashSelector(
'#/foo/123/bar/test/',
'/foo/:fooId/bar/:barId/'
);
expect(hashSelector).toEqual({
fooId: '123',
barId: 'test'
});
});
it ('Creates HashSelector From Partial HashRoute', () => {
const hashSelector = HashRouterService.createHashSelector(
'#/foo/123/',
'/foo/:fooId/bar/:barId/'
);
expect(hashSelector).toEqual({
fooId: '123'
});
});
it ('Creates Partial HashSelector From Partial MatchedRoute', () => {
const hashSelector = HashRouterService.createHashSelector(
'#/foo/123/bar/test/',
'/foo/:fooId/'
);
expect(hashSelector).toEqual({
fooId: '123'
});
});
it ('Creates Empty Object From Unmatched Route', () => {
const hashSelector = HashRouterService.createHashSelector(
'#/bar/test/',
'/foo/:fooId/bar/:barId/'
);
expect(hashSelector).toEqual({});
});
it ('Creates HashSelector from Hash String With Extra Characters', () => {
const hashSelector = HashRouterService.createHashSelector(
'#?1234567890abcdABCD-_/foo/123/bar/test/',
'/foo/:fooId/bar/:barId/'
);
expect(hashSelector).toEqual({
fooId: '123',
barId: 'test'
});
});
it ('Creates Empty Object From Invalid Hash Route (1)', () => {
const hashSelector = HashRouterService.createHashSelector(
'/foo/123/bar/test/',
'/foo/:fooId/bar/:barId/'
);
expect(hashSelector).toEqual({});
});
it ('Creates Empty Object From Invalid Hash Route (2)', () => {
const hashSelector = HashRouterService.createHashSelector(
'?#/foo/123/bar/test/',
'/foo/:fooId/bar/:barId/'
);
expect(hashSelector).toEqual({});
});
it ('Creates Empty Object From Invalid Matching Route', () => {
const hashSelector = HashRouterService.createHashSelector(
'#/foo/123/bar/test/',
'foo/:fooId/bar/:barId/'
);
expect(hashSelector).toEqual({});
});
it ('Creates Empty Object From Invalid Matching Route (2)', () => {
const hashSelector = HashRouterService.createHashSelector(
'#/foo/123/bar/test/',
'#/foo/:fooId/bar/:barId/'
);
expect(hashSelector).toEqual({});
});
});
@@ -0,0 +1,112 @@
export interface IUrlSelectorMap {
[key: string]: string | undefined;
}
class HashRouterService {
/**
* Create a paramaterized map of url paramaters from a matching route string
*
* Example #1:
*
* hashRoute: "#/foo/123/bar/test"
*
* matchingRoute: "/foo/:fooId/bar/:barId/foobar/:foobarId"
*
* returns: {
* fooId: "123",
* barId: "test"
* }
*
* Example #2:
*
* hashRoute: "#/account/123/bar/test"
*
* matchingRoute: "/foo/:fooId/bar/:barId/foobar/:foobarId"
*
* returns: {}
*
* Note: This returns empty object since it will only lazy search the route.
* The moment a string value doesn't match, the currently created object
* is returned (which in this case is an empty object).
*
* @param hashRoute The current hash route
* @param matchingRoute The route matching parameters, colon prefaced
*
* @returns An object of string or undefined values mapped to the matchingRoute's parameter names.
*/
public static createHashSelector(hashRoute: string, matchingRoute: string): IUrlSelectorMap {
const hashRouteArray = this.createHashSelectorArray(hashRoute);
if (!hashRouteArray) {
return {};
}
const matchingRouteArray = this.createMatchingSelectorArray(matchingRoute);
if (!matchingRouteArray) {
return {};
}
return this.createUrlSelectorMapFromRouteArrays(hashRouteArray, matchingRouteArray);
}
private static createHashSelectorArray(hashRoute: string): string[] | undefined {
if (hashRoute[0] !== '#') {
console.warn('createHashSelector(): The first character of the hashRoute MUST be the pound symbol (#). Returning.');
return;
}
const hashSlpitUrl = hashRoute.split('/');
if (hashSlpitUrl[0].match(/[^#]/) !== null) {
console.warn('createHashSelector(): Unrecognized characters before first slash in hashRoute. These characters will be ignored.');
}
hashSlpitUrl.shift();
return hashSlpitUrl;
}
private static createMatchingSelectorArray(matchingRoute: string): string[] | undefined {;
if (matchingRoute[0] !== '/') {
console.warn('createHashSelector(): The first character of the matchingRoute MUST be a slash. Returning.');
return;
}
const matchingSlpitUrl = matchingRoute.split('/');
matchingSlpitUrl.shift();
return matchingSlpitUrl;
}
private static createUrlSelectorMapFromRouteArrays(hashRouteArray: string[], matchingRouteArray: string[]) {
const selectorMap: IUrlSelectorMap = {};
for (let i = 0; i < hashRouteArray.length; i++) {
const currentHashRoute = hashRouteArray[i];
const currentMatchingRoute = matchingRouteArray[i];
if (currentMatchingRoute === undefined) {
return selectorMap;
}
if (this.isRouteSectionKey(currentMatchingRoute)) {
const key = this.extractRouteKeyName(currentMatchingRoute);
selectorMap[key] = currentHashRoute;
} else if (currentHashRoute.toLowerCase() !== currentMatchingRoute.toLowerCase()) {
// The two routes don't match, return what has been matched so far
return selectorMap;
}
}
return selectorMap;
}
private static isRouteSectionKey(section: string): boolean {
return section[0] === ':';
}
private static extractRouteKeyName(section: string): string {
return section.replace(':', '');
}
}
export default HashRouterService;
@@ -0,0 +1,33 @@
import pick from "lodash.pick";
import {DeepPartial} from "redux";
import {IAppState} from "../store/Store";
class LocalStorageService {
private static StorageKey: string = "RepoState";
public static loadAppSavedState(paths?: string[]): DeepPartial<IAppState> {
try {
const serializedState = localStorage.getItem(LocalStorageService.StorageKey);
if (serializedState === null) {
return {};
}
const parsed = JSON.parse(serializedState);
return paths ? pick(parsed, paths) : parsed;
} catch (err) {
return {};
}
}
public static saveAppState(state: IAppState, paths?: string[]) {
try {
const targetObj = paths ? pick(state, paths) : state;
const serializedState = JSON.stringify(targetObj);
localStorage.setItem(LocalStorageService.StorageKey, serializedState);
} catch {
// Not logging because this can happen for normal reasons.
}
}
}
export default LocalStorageService;
@@ -0,0 +1,27 @@
import Axios from "axios";
import { ILocationCoordinates } from "./service-types/LocationTypes";
export default class NetworkService {
public static FetchWithJSONP(url: string, JSONPFunctionIdentifier: string, callback: (data: any) => any) {
const windowCallbackNamne = "bingMapLocationCallback";
const jsonPUrl = url;
(window as any)[windowCallbackNamne] = (data: any) => {
delete (window as any)[windowCallbackNamne];
document.body.removeChild(script);
callback(data);
};
var script = document.createElement("script");
script.src = jsonPUrl;
document.body.appendChild(script);
}
public static async FetchLocationData(url: string) {
const result = await Axios.get(url);
const locationResult = result.data as ILocationCoordinates;
return locationResult;
}
}
@@ -0,0 +1,40 @@
import { IProcessingReceipt, RepoProcessingResults } from "./service-types/ProcessingReceiptTypes";
export default class ProcessingReceiptService{
public static sortByProcessedDate(receipts: IProcessingReceipt[]): IProcessingReceipt[]{
return receipts.sort((a,b) => {
if(a.processed && b.processed){
return (a.processed > b.processed)? -1 : 1;
}else if(!a.processed&& !b.processed){
return 1;
}else if(a.processed && !b.processed){
return -1;
}else{
return 0;
}
});
}
public static getOutcomeFromProcessingResult(outcome: RepoProcessingResults): string{
switch(outcome){
case(RepoProcessingResults.Autoclosed):
return "AutoClosed";
case(RepoProcessingResults.Created):
return "Created";
case(RepoProcessingResults.Error):
return "Error";
case(RepoProcessingResults.Ineligible):
return "Ineligible";
case(RepoProcessingResults.MissingRequirement):
return "MissingRequirement";
case(RepoProcessingResults.Unconverted):
return "Unconverted";
case(RepoProcessingResults.Updated):
return "Updated";
default:
return outcome;
}
}
}
@@ -0,0 +1,70 @@
import moment, { Moment } from "moment";
import { ProcessingReceiptTable } from './../containers/processing-receipt-table/processingReceiptTable';
import { IProcessingReceipt, RepoProcessingResults } from './service-types/ProcessingReceiptTypes';
import ProcessingReceiptService from './ProccessingReceiptService';
const getCreatedYear = (createdDate : Moment | undefined): string =>{
// eslint-disable-next-line eqeqeq
if(createdDate == undefined){
return "";
}else{
return createdDate.format("YYYY");
}
};
describe("AccountHistoryService Tests", () => {
var processingReceipts: IProcessingReceipt[];
beforeEach(() => {
processingReceipts = [ {
accountId: "3",
accountNo: "123",
caseId: "123",
message: "message123",
outcome: RepoProcessingResults.Created,
queuedBy: "Queue",
processed: moment("2018-09-22T06:15:28.19"),
},
{
accountId: "2",
accountNo: "123",
caseId: "123",
message: "message123",
outcome: RepoProcessingResults.Created,
queuedBy: "Queue",
processed: moment("2020-09-22T06:15:28.19"),
},
{
accountId: "1",
accountNo: "123",
caseId: "123",
message: "message123",
outcome: RepoProcessingResults.Created,
queuedBy: "Queue",
processed: moment("2019-09-22T06:15:28.19")
},
{
accountId: "0",
accountNo: "123",
caseId: "123",
message: "message123",
outcome: RepoProcessingResults.Created,
queuedBy: "Queue",
processed: undefined
}];
});
it("Properly Sorts processing receipts", () => {
var sortedReceipts = ProcessingReceiptService.sortByProcessedDate(processingReceipts);
expect(getCreatedYear(sortedReceipts[0].processed)).toBe("2020");
expect(sortedReceipts[0].accountId).toBe("2");
expect(getCreatedYear(sortedReceipts[1].processed)).toBe("2019");
expect(sortedReceipts[1].accountId).toBe("1");
expect(getCreatedYear(sortedReceipts[2].processed)).toBe("2018");
expect(sortedReceipts[2].accountId).toBe("3");
expect(sortedReceipts[3].accountId).toBe("0");
});
});
@@ -0,0 +1,418 @@
import moment from "moment";
import RepoAccountService from "./RepoAccountService";
import { ICollateral, IRepoAccount, IRepoAccountMap } from "./service-types/RepoAccountTypes";
const buildTestRepoAccount = (repoId: number, collaterals: ICollateral[]): IRepoAccount => {
return {
repoId: repoId,
collaterals: collaterals,
accountNo: "accountNo",
status: "status",
memberNo: 1,
loanNo: 1,
accountTypeCode: "code",
branch: 1,
balance: 1,
delinquentAmount: 1,
daysDelinquent: 1,
requiredPaymentAmount: 1,
origAmount: 1,
primaryIndividualId: "id",
borrowers: [],
repoStatusChanges: []
};
};
const buildTestCollateralResponse = (collateralId: number, isVoluntaryRepo?: boolean | number | null) => {
return {
collateralId: collateralId,
isVoluntaryRepo: isVoluntaryRepo,
repoCompanyAssignedDate: "2001-01-01",
dateRepoed: "2001-01-02",
retitledInLandmarkName: "2001-01-04",
auctionAssignmentDate: "2001-01-05"
};
};
const buildTestConvertedCollateral = (collateralId: number, isVoluntaryRepo: boolean) => {
return {
collateralId: collateralId,
repoCompanyAssignedDate: moment("2001-01-01"),
dateRepoed: moment("2001-01-02"),
isVoluntaryRepo: isVoluntaryRepo,
retitledInLandmarkName: moment("2001-01-04"),
auctionAssignmentDate: moment("2001-01-05")
};
};
const buildTestRepoAccountResponse = (repoId: number) => {
return {
repoId: repoId,
dateFirstDelinquent: "1990-12-01",
dateFirstIntellect: "1990-12-02",
o4RDate: "1990-12-03",
dueToPayDate: "1990-12-04",
lastPaymentDate: "1990-12-05",
manualRedemptionDate: "1990-12-06",
repoStatusChanges: [
{ changedDate: "1969-06-05" },
{ changedDate: "1969-06-10" },
{ changedDate: "1969-06-06" },
],
collaterals: [
buildTestCollateralResponse(1),
buildTestCollateralResponse(2, 1)
]
};
};
const buildTestConvertedRepoAccount = (repoId: number) => {
return {
repoId: repoId,
dateFirstDelinquent: moment("1990-12-01"),
dateFirstIntellect: moment("1990-12-02"),
o4RDate: moment("1990-12-03"),
dueToPayDate: moment("1990-12-04"),
lastPaymentDate: moment("1990-12-05"),
manualRedemptionDate: moment("1990-12-06"),
repoStatusChanges: [
{ changedDate: moment("1969-06-10") },
{ changedDate: moment("1969-06-06") },
{ changedDate: moment("1969-06-05") },
],
collaterals: [
buildTestConvertedCollateral(1, false),
buildTestConvertedCollateral(2, true)
],
borrowers: []
};
};
describe("RepoAccountService", () => {
let dummyRepoAccounts: IRepoAccountMap;
let dummyBaseCollateral: any;
let dummyRepoAccountsCopy: IRepoAccountMap;
beforeEach(() => {
dummyBaseCollateral = {
vin: "vin",
make: "make",
model: "model",
year: 2019,
isVoluntaryRepo: false
};
dummyRepoAccounts = {
"1": buildTestRepoAccount(1, []),
"2": buildTestRepoAccount(2, []),
"3": buildTestRepoAccount(3, [{
...dummyBaseCollateral,
collateralId: 1,
repoId: 3,
}]),
"4": buildTestRepoAccount(4, [{
...dummyBaseCollateral,
collateralId: 2,
repoId: 4,
}, {
...dummyBaseCollateral,
collateralId: 5,
repoId: 4,
}])
};
dummyRepoAccountsCopy = Object.assign({}, dummyRepoAccounts);
});
it ("GetDaysInStatus() Retuns Expected Value", () => {
const dummyRepoAccount = buildTestRepoAccount(1, []);
dummyRepoAccount.repoStatusChanges = [{
repoId: 1,
statusFrom: "some_previous_status",
statusTo: "status",
changedBy: "some person",
changedDate: moment().subtract(42, "days"),
}, {
repoId: 1,
statusFrom: "status",
statusTo: "some_previous_status",
changedBy: "some person",
changedDate: moment().subtract(45, "days"),
}, {
repoId: 1,
statusFrom: "some_previous_status",
statusTo: "status",
changedBy: "some person",
changedDate: moment().subtract(48, "days"),
}];
expect(RepoAccountService.GetDaysInStatus(dummyRepoAccount)).toBe(42);
});
// it ('GetMemberName() Retuns Expected Value', () => {
// const dummyRepoAccount = buildTestRepoAccount(1, []);
// dummyRepoAccount.borrowers = [{
// repoId: 1,
// individualId: '2',
// individualName: 'John jacob Jingleheimer SCHMIDT',
// ownershipType: 6
// }];
// expect(RepoAccountService.GetMemberName(dummyRepoAccount)).toEqual('John Jacob Jingleheimer Schmidt');
// });
// it ('GetRepoAccountByAccountNo() Returns Expected Value', () => {
// const dummyRepoAccounts: IRepoAccountMap = {
// '1': {
// ...buildTestRepoAccount(1, []),
// accountNo: '123123'
// },
// '2': {
// ...buildTestRepoAccount(2, []),
// accountNo: 'abcdefg'
// },
// '3': {
// ...buildTestRepoAccount(3, []),
// accountNo: '0987654321'
// },
// };
// expect(RepoAccountService.GetRepoAccountByAccountNo(dummyRepoAccounts, 'abcdefg')).toBe(dummyRepoAccounts['2']);
// });
// it ('GetRepoAccountByRepoId() Returns Excpected Value', () => {
// const dummyRepoAccounts: IRepoAccountMap = {
// '1': buildTestRepoAccount(1, []),
// '2': buildTestRepoAccount(2, []),
// '3': buildTestRepoAccount(3, [])
// };
// expect(RepoAccountService.GetRepoAccountByRepoId(dummyRepoAccounts, 3)).toBe(dummyRepoAccounts['3']);
// });
// it ('GetFilteredRepoAccounts() Returns Expected Value', () => {
// const dummyRepoAccounts: IRepoAccountMap = {
// '1': buildTestRepoAccount(1, []),
// '2': buildTestRepoAccount(2, []),
// '3': buildTestRepoAccount(3, []),
// '4': buildTestRepoAccount(4, []),
// '5': buildTestRepoAccount(5, []),
// '6': buildTestRepoAccount(6, []),
// '7': buildTestRepoAccount(7, [])
// };
// expect(RepoAccountService.GetFilteredRepoAccounts(dummyRepoAccounts, [7,1,6,4])).toEqual([
// dummyRepoAccounts['7'],
// dummyRepoAccounts['1'],
// dummyRepoAccounts['6'],
// dummyRepoAccounts['4']
// ]);
// });
// it ('CreateRepoAccountIdMap() Returns Expected Value', () => {
// expect(RepoAccountService.CreateRepoAccountIdMap([
// buildTestRepoAccount(9, []),
// buildTestRepoAccount(1, []),
// buildTestRepoAccount(2, []),
// buildTestRepoAccount(5, [])
// ])).toEqual([9,1,2,5]);
// });
// it ('CreateAmmendedRepoAccountMap() Returns Expected Values', () => {
// const dummyRepoAccounts: IRepoAccountMap = {
// '7': buildTestRepoAccount(7, []),
// '4': buildTestRepoAccount(4, []),
// '1': buildTestRepoAccount(1, []),
// '5': buildTestRepoAccount(5, [])
// };
// const newAccount1 = buildTestRepoAccount(8,[]);
// const newAccount2 = buildTestRepoAccount(7, []);
// const newAccount3 = buildTestRepoAccount(2, []);
// expect(RepoAccountService.CreateAmmendedRepoAccountMap(dummyRepoAccounts, newAccount1))
// .toEqual({
// ...dummyRepoAccounts,
// '8': newAccount1
// });
// expect(RepoAccountService.CreateAmmendedRepoAccountMap(dummyRepoAccounts, newAccount2)).toEqual(dummyRepoAccounts);
// expect(RepoAccountService.CreateAmmendedRepoAccountMap(dummyRepoAccounts, [newAccount1, newAccount2, newAccount3]))
// .toEqual({
// ...dummyRepoAccounts,
// '2': newAccount3,
// '8': newAccount1
// });
// expect(dummyRepoAccounts).toEqual({
// '7': buildTestRepoAccount(7, []),
// '4': buildTestRepoAccount(4, []),
// '1': buildTestRepoAccount(1, []),
// '5': buildTestRepoAccount(5, [])
// });
// });
// it ('ConvertResponseToCollateral() Mutates Expected Values', () => {
// let dummyCollateralResponse = buildTestCollateralResponse(1);
// RepoAccountService.ConvertResponseToCollateral(dummyCollateralResponse);
// expect(dummyCollateralResponse)
// .toEqual(buildTestConvertedCollateral(1, false));
// dummyCollateralResponse = buildTestCollateralResponse(2, false);
// RepoAccountService.ConvertResponseToCollateral(dummyCollateralResponse);
// expect(dummyCollateralResponse)
// .toEqual(buildTestConvertedCollateral(2, false));
// dummyCollateralResponse = buildTestCollateralResponse(3, true);
// RepoAccountService.ConvertResponseToCollateral(dummyCollateralResponse);
// expect(dummyCollateralResponse)
// .toEqual(buildTestConvertedCollateral(3, true));
// dummyCollateralResponse = buildTestCollateralResponse(4, 1);
// RepoAccountService.ConvertResponseToCollateral(dummyCollateralResponse);
// expect(dummyCollateralResponse)
// .toEqual(buildTestConvertedCollateral(4, true));
// dummyCollateralResponse = buildTestCollateralResponse(5, 0);
// RepoAccountService.ConvertResponseToCollateral(dummyCollateralResponse);
// expect(dummyCollateralResponse)
// .toEqual(buildTestConvertedCollateral(5, false));
// const minimalCollateral = {
// collateralId: 6,
// isVoluntaryRepo: null
// };
// RepoAccountService.ConvertResponseToCollateral(minimalCollateral)
// expect(minimalCollateral).toEqual({
// collateralId: 6,
// isVoluntaryRepo: false
// });
// });
// it ('ConvertResponseToRepoAccount() Mutates Expected Value', () => {
// const originalRepoAccountResponse = buildTestRepoAccountResponse(1);
// RepoAccountService.ConvertResponseToRepoAccount(originalRepoAccountResponse);
// expect(originalRepoAccountResponse).toEqual(buildTestConvertedRepoAccount(1));
// });
// it ('ConvertResponseToRepoAccounts() Mutates Expected Value', () => {
// const originalRepoAccountResponses = [
// buildTestRepoAccountResponse(1),
// buildTestRepoAccountResponse(2),
// buildTestRepoAccountResponse(3)
// ];
// RepoAccountService.ConvertResponseToRepoAccounts(originalRepoAccountResponses);
// expect(originalRepoAccountResponses)
// .toEqual([
// buildTestConvertedRepoAccount(1),
// buildTestConvertedRepoAccount(2),
// buildTestConvertedRepoAccount(3)
// ]);
// })
// it ('ConvertRepoAccountToResponse() Returns Expected Value', () => {
// const dummyRepoAccount: IRepoAccount = {
// dateFirstDelinquent: moment('2008-10-21'),
// dateFirstIntellect: moment('2008-10-22'),
// o4RDate: moment('2008-10-23'),
// dueToPayDate: moment('2008-10-24'),
// lastPaymentDate: moment('2008-10-25'),
// manualRedemptionDate: moment('2008-10-26')
// } as IRepoAccount;
// expect(RepoAccountService.CreateRepoAccountResponse(dummyRepoAccount)).toEqual({
// dateFirstDelinquent: '2008-10-21T00:00:00Z',
// dateFirstIntellect: '2008-10-22T00:00:00Z',
// o4RDate: '2008-10-23T00:00:00Z',
// dueToPayDate: '2008-10-24T00:00:00Z',
// lastPaymentDate: '2008-10-25T00:00:00Z',
// manualRedemptionDate: '2008-10-26T00:00:00Z'
// });
// })
// it ('ConvertCollateralToResponse() Returns Expected Value', () => {
// const dummyRepoAccount: ICollateral = {
// repoCompanyAssignedDate: moment('1916-02-01'),
// dateRepoed: moment('1916-02-02'),
// isVoluntaryRepo: false,
// auctionAssignmentDate: moment('1916-02-03'),
// retitledInLandmarkName: moment('1916-02-04')
// } as ICollateral;
// const expectedConversion = {
// repoCompanyAssignedDate: '1916-02-01T00:00:00Z',
// dateRepoed: '1916-02-02T00:00:00Z',
// auctionAssignmentDate: '1916-02-03T00:00:00Z',
// retitledInLandmarkName: '1916-02-04T00:00:00Z',
// isVoluntaryRepo: 0
// }
// const dummyRepoAccount2 = Object.assign({}, dummyRepoAccount);
// dummyRepoAccount2.isVoluntaryRepo = true;
// const expectedConversion2 = Object.assign({}, expectedConversion);
// expectedConversion2.isVoluntaryRepo = 1;
// expect(RepoAccountService.CreatCollateralResponse(dummyRepoAccount)).toEqual(expectedConversion);
// expect(RepoAccountService.CreatCollateralResponse(dummyRepoAccount2)).toEqual(expectedConversion2);
// });
// it('UpdateRepoAccountsFromCollateral Updates Account With One Collateral Without Mutating',() => {
// const updatedCollateral = {
// ...dummyBaseCollateral,
// collateralId: 1,
// repoId: 3,
// make: 'different make',
// };
// let newAccounts = RepoAccountService.CreateUpdatedRepoAccountsFromCollateral(dummyRepoAccounts, updatedCollateral);
// expect(newAccounts).not.toBe(dummyRepoAccounts);
// expect(dummyRepoAccountsCopy).toEqual(dummyRepoAccounts);
// expect(newAccounts['3'].collaterals.length).toBe(1);
// expect(newAccounts['3'].collaterals[0].make).toEqual('different make');
// expect(dummyRepoAccounts['3'].collaterals[0].make).toEqual('make');
// });
// it('UpdateRepoAccountsFromCollateral Updates Account With Two Collateral Without Mutating', () => {
// const updatedCollateral = {
// ...dummyBaseCollateral,
// collateralId: 5,
// repoId: 4,
// make: 'different make',
// };
// let newAccounts = RepoAccountService.CreateUpdatedRepoAccountsFromCollateral(dummyRepoAccounts, updatedCollateral);
// expect(newAccounts).not.toBe(dummyRepoAccounts);
// expect(dummyRepoAccountsCopy).toEqual(dummyRepoAccounts);
// expect(newAccounts['4'].collaterals.length).toBe(2);
// expect(newAccounts['4'].collaterals[1].make).toEqual('different make');
// expect(dummyRepoAccounts['4'].collaterals[1].make).toEqual('make');
// });
// it('UpdateRepoAccountsFromCollateral Does Not Update Repo That Doesn\'t Exist', () => {
// const updatedCollateral = {
// ...dummyBaseCollateral,
// collateralId: 1,
// repoId: 5,
// make: 'different make',
// };
// let newAccounts = RepoAccountService.CreateUpdatedRepoAccountsFromCollateral(dummyRepoAccounts, updatedCollateral);
// expect(newAccounts).toEqual(dummyRepoAccounts);
// expect(dummyRepoAccountsCopy).toEqual(dummyRepoAccounts);
// });
// it('UpdateRepoAccountsFromCollateral Updates Account With Collateral Array', () => {
// const updatedCollaterals = [{
// ...dummyBaseCollateral,
// collateralId: 2,
// repoId: 4,
// make: 'different make 1',
// }, {
// ...dummyBaseCollateral,
// collateralId: 5,
// repoId: 4,
// make: 'different make 2',
// }, {
// ...dummyBaseCollateral,
// collateralId: 9,
// repoId: 4,
// make: 'different make 3',
// }];
// let newAccounts = RepoAccountService.CreateUpdatedRepoAccountsFromCollateral(dummyRepoAccounts, updatedCollaterals);
// expect(newAccounts).not.toBe(dummyRepoAccounts);
// expect(newAccounts).not.toEqual(dummyRepoAccounts)
// expect(dummyRepoAccountsCopy).toEqual(dummyRepoAccounts);
// expect(newAccounts['4'].collaterals.length).toBe(3);
// expect(newAccounts['4'].collaterals[0].make).toEqual('different make 1');
// expect(newAccounts['4'].collaterals[1].make).toEqual('different make 2');
// expect(newAccounts['4'].collaterals[2].make).toEqual('different make 3');
// });
});
@@ -0,0 +1,221 @@
import moment, { Moment } from "moment";
import { isArray } from "util";
import DateCalculations from "../shared/calculations/DateCalculations";
import DateConversions from "../shared/conversions/DateConversions";
import StringFormatting from "../shared/formatting/StringFormatting";
import { ICollateral, IRefundStatus, IRepoAccount, IRepoAccountMap, IRepoCompanySelection } from "./service-types/RepoAccountTypes";
const cloneDeep = require("lodash.clonedeep");
export default class RepoAccountService {
public static GetDaysInStatus(repoAccount?: IRepoAccount): string | number {
if (repoAccount) {
const matchingRepo = repoAccount.repoStatusChanges.find(
(repoStatusChange) => repoStatusChange.statusTo === repoAccount.status
);
if (matchingRepo) {
return DateCalculations.DayDifference(moment(matchingRepo.changedDate), moment());
}
}
return "Missing";
}
public static GetMemberName(repoAccount?: IRepoAccount): string {
if (repoAccount) {
const member = repoAccount.borrowers.find((borrower) => borrower.ownershipType === 6);
return member ? StringFormatting.ToTitleCase(member.individualName) : "Missing";
} else {
return "Missing";
}
}
public static GetLatestStatusChangeDate(status: string, repoAccount?: IRepoAccount): Moment | undefined {
if (repoAccount) {
const foundStatus = repoAccount.repoStatusChanges.find((statusChange) => statusChange.statusTo === status);
if (foundStatus) {
return foundStatus.changedDate;
}
}
}
public static IsAccountClosed(repoAccount?: IRepoAccount): boolean {
if (repoAccount && repoAccount.dateClosed) {
return true;
}
return false;
}
public static GetRepoAccountByAccountNo(repoAccountMap: IRepoAccountMap, accountNo: string): IRepoAccount | undefined {
for (const repoId in repoAccountMap) {
if (repoAccountMap.hasOwnProperty(repoId)) {
const repoAccount = repoAccountMap[repoId];
if (repoAccount.accountNo === accountNo) {
return repoAccount;
}
}
}
}
public static GetRepoAccountByRepoId(repoAccountMap: IRepoAccountMap, repoId?: number): IRepoAccount | undefined {
if (repoId) {
return repoAccountMap[repoId];
}
}
public static GetFilteredRepoAccounts(repoAccountMap: IRepoAccountMap, filteredRepoIds: number[]): IRepoAccount[] {
if (!filteredRepoIds.length) {
return [];
}
const filteredRepoAccounts: IRepoAccount[] = [];
for (const repoId of filteredRepoIds) {
if (repoAccountMap[repoId]) {
filteredRepoAccounts.push(repoAccountMap[repoId]);
} else {
window.console.warn("The Filtered Repo ID did not exist in the RepoAccountMap. This should never occur.");
}
}
return filteredRepoAccounts;
}
public static CreateRepoAccountIdMap(repoAccounts: IRepoAccount[]): number[] {
return repoAccounts.map((repoAccount) => repoAccount.repoId);
}
public static CreateAmmendedRepoAccountMap(repoAccountMap: IRepoAccountMap, repo: IRepoAccount | IRepoAccount[]): IRepoAccountMap {
const copiedRepoAccountMap = cloneDeep(repoAccountMap) as IRepoAccountMap;
if (isArray(repo)) {
for (const repoAccount of repo) {
copiedRepoAccountMap[repoAccount.repoId] = repoAccount;
}
} else {
copiedRepoAccountMap[repo.repoId] = repo;
}
return copiedRepoAccountMap;
}
public static CreateUpdatedRepoAccountsFromCollateral(repoAccounts: IRepoAccountMap, collateral: ICollateral | ICollateral[]): IRepoAccountMap {
const copiedRepoAccounts = cloneDeep(repoAccounts) as IRepoAccountMap;
if (isArray(collateral)) {
for (const col of collateral) {
if (!this._mutateRepoAccountsFromSingleCollateral(copiedRepoAccounts, col)) {
window.console.warn("Failed to update collateral with id " + col.collateralId);
}
}
} else {
if (!this._mutateRepoAccountsFromSingleCollateral(copiedRepoAccounts, collateral)) {
window.console.warn("Failed to update collateral with id " + collateral.collateralId);
}
}
return copiedRepoAccounts;
}
public static CreateUpdatedRepoAccountsFromRefundStatus(repoAccounts: IRepoAccountMap, refundStatus: IRefundStatus): IRepoAccountMap {
const copiedRepoAccounts = cloneDeep(repoAccounts) as IRepoAccountMap;
if (copiedRepoAccounts[refundStatus.repoId]) {
copiedRepoAccounts[refundStatus.repoId].refundStatus = refundStatus;
} else {
window.console.warn("Failed to update Refund Status with RepoId " + refundStatus.repoId);
}
return copiedRepoAccounts;
}
public static ConvertResponseToCollateral(collateralResponse: any): void {
const collateral: ICollateral = collateralResponse;
collateral.retitledInLandmarkName = DateConversions.utcToMoment(collateralResponse.retitledInLandmarkName);
collateral.auctionAssignmentDate = DateConversions.utcToMoment(collateralResponse.auctionAssignmentDate);
for (const repoCompanySelection of collateral.repoCompanySelections) {
this.ConvertResponseToRepoCompanySelection(repoCompanySelection);
}
collateral.repoCompanySelections.sort((a, b) => -(a.dateTimeCreated.unix() - b.dateTimeCreated.unix()));
}
public static ConvertResponseToRepoCompanySelection(repoCompanySelectionResponse: any): void {
const repoCompanySelection: IRepoCompanySelection = repoCompanySelectionResponse;
repoCompanySelection.repoCompanyAssignmentDate = DateConversions.utcToMoment(repoCompanySelectionResponse.repoCompanyAssignmentDate);
repoCompanySelection.dateRepoed = DateConversions.utcToMoment(repoCompanySelectionResponse.dateRepoed);
repoCompanySelection.dateTimeCreated = DateConversions.utcToMoment(repoCompanySelectionResponse.dateTimeCreated)!;
}
public static ConvertResponseToRefundStatus(refundStatusResponse: any): void {
const refundStatus: IRefundStatus = refundStatusResponse;
refundStatus.refundsReceivedDate = DateConversions.utcToMoment(refundStatusResponse.refundsReceivedDate);
}
public static ConvertResponseToRepoAccounts (repoAccountResponses: any[]): void {
repoAccountResponses.map(repoAccountResponse => this.ConvertResponseToRepoAccount(repoAccountResponse));
}
public static ConvertResponseToRepoAccount (repoAccountResponse: any): void {
const repoAccount: IRepoAccount = repoAccountResponse;
repoAccount.dateFirstDelinquent = DateConversions.utcToMoment(repoAccountResponse.dateFirstDelinquent);
repoAccount.dateFirstIntellect = DateConversions.utcToMoment(repoAccountResponse.dateFirstIntellect);
repoAccount.o4RDate = DateConversions.utcToMoment(repoAccountResponse.o4RDate);
repoAccount.dueToPayDate = DateConversions.utcToMoment(repoAccountResponse.dueToPayDate);
repoAccount.lastPaymentDate = DateConversions.utcToMoment(repoAccountResponse.lastPaymentDate);
repoAccount.manualRedemptionDate = DateConversions.utcToMoment(repoAccountResponse.manualRedemptionDate);
repoAccount.redemptionExpiredDate = DateConversions.utcToMoment(repoAccountResponse.redemptionExpiredDate);
repoAccount.dateClosed = DateConversions.utcToMoment(repoAccountResponse.dateClosed);
repoAccount.writtenOffDate = DateConversions.utcToMoment(repoAccountResponse.writtenOffDate);
if (repoAccountResponse.repoStatusChanges) {
repoAccount.repoStatusChanges.map((repoStatusChange) => repoStatusChange.changedDate = DateConversions.utcToMoment(repoStatusChange.changedDate)!);
repoAccount.repoStatusChanges.sort((a, b) => -a.changedDate.diff(b.changedDate));
} else {
repoAccount.repoStatusChanges = [];
}
if( repoAccount.collaterals ) {
repoAccount.collaterals.map((collateral) => this.ConvertResponseToCollateral(collateral));
} else {
repoAccount.collaterals = [];
}
if( !repoAccount.borrowers ) {
repoAccount.borrowers = [];
}
if (repoAccount.refundStatus) {
this.ConvertResponseToRefundStatus(repoAccount.refundStatus);
}
}
public static CreateCollateralFromRepoCompanySelection(collateral: ICollateral, repoCompanySelection: IRepoCompanySelection | IRepoCompanySelection[]): ICollateral {
const copiedCollateral = cloneDeep(collateral) as ICollateral;
if (Array.isArray(repoCompanySelection)) {
for (const curSelection of repoCompanySelection) {
this._mutateCollateralFromSingleRepoCompanySelection(copiedCollateral, curSelection);
}
} else {
this._mutateCollateralFromSingleRepoCompanySelection(copiedCollateral, repoCompanySelection);
}
return copiedCollateral;
}
private static _mutateRepoAccountsFromSingleCollateral(repoAccounts: IRepoAccountMap, collateral: ICollateral): boolean {
if (repoAccounts[collateral.repoId]) {
const repoAccountToUpdate = repoAccounts[collateral.repoId];
const collateralIndex = repoAccountToUpdate.collaterals.findIndex((col) => col.collateralId === collateral.collateralId);
if (collateralIndex >= 0) {
repoAccountToUpdate.collaterals[collateralIndex] = collateral;
} else {
repoAccountToUpdate.collaterals.push(collateral);
}
return true;
}
return false;
}
public static _mutateCollateralFromSingleRepoCompanySelection(collateral: ICollateral, repoCompanySelection: IRepoCompanySelection): void {
const indexOfSelection = collateral.repoCompanySelections.findIndex((selection) => selection.id === repoCompanySelection.id);
if (indexOfSelection >= 0) {
collateral.repoCompanySelections[indexOfSelection] = repoCompanySelection;
} else {
collateral.repoCompanySelections.unshift(repoCompanySelection);
}
}
}
@@ -0,0 +1,33 @@
import { IReportUrlDisplayMap } from "../reducers/ReportingReducer";
import Configuration from "../shared/configuration/Configuration";
class ReportingService {
public static GetAllReportUrls(): IReportUrlDisplayMap[] {
const repoUrls = Configuration.Get.urls.repoApi;
return [
{ display: "Auction: Assigned Collateral Count", url: Configuration.PrefixSSRSApiURL(repoUrls.report_auction_count_of_assigned_collateral) },
{ display: "Auction: Average Days Assigned To Sold", url: Configuration.PrefixSSRSApiURL(repoUrls.report_auction_avg_days_to_sold) },
{ display: "Auction: Average Net of Floor", url: Configuration.PrefixSSRSApiURL(repoUrls.report_auction_avg_net_of_floor) },
{ display: "Auction: Assigned Balance", url: Configuration.PrefixSSRSApiURL(repoUrls.report_auction_assigned_balance) },
{ display: "Auction: Sale Price", url: Configuration.PrefixSSRSApiURL(repoUrls.report_auction_sale_price) },
{ display: "Auction: Total Auction Fees", url: Configuration.PrefixSSRSApiURL(repoUrls.report_auction_total_fees) },
{ display: "Repo Company: Assigned Collateral Count", url: Configuration.PrefixSSRSApiURL(repoUrls.report_repo_company_count_of_assigned_collateral) },
{ display: "Repo Company: Assigned Balance", url: Configuration.PrefixSSRSApiURL(repoUrls.report_repo_company_assigned_balance) },
{ display: "Repo Company: Repossessed Count", url: Configuration.PrefixSSRSApiURL(repoUrls.report_repo_company_repo_count) },
{ display: "Repo Company: Average Days Assigned to Repossessed", url: Configuration.PrefixSSRSApiURL(repoUrls.report_repo_company_avg_days_assigned_to_repo) },
{ display: "Landmark: Active Accounts", url: Configuration.PrefixSSRSApiURL(repoUrls.report_landmark_active_accounts) },
{ display: "Landmark: Average Days Delq When Added", url: Configuration.PrefixSSRSApiURL(repoUrls.report_landmark_avg_days_delq_when_added) },
{ display: "Landmark: Average Days Repo to Sold", url: Configuration.PrefixSSRSApiURL(repoUrls.report_landmark_avg_days_repo_to_sold) },
{ display: "Landmark: Average Surplus or Deficiency", url: Configuration.PrefixSSRSApiURL(repoUrls.report_landmark_avg_surplus_or_deficiency) },
{ display: "Landmark: Closed Accounts", url: Configuration.PrefixSSRSApiURL(repoUrls.report_landmark_closed_accounts) },
{ display: "Landmark: Count of Redemptions", url: Configuration.PrefixSSRSApiURL(repoUrls.report_landmark_count_of_redemptions) },
{ display: "Landmark: Count of Sales", url: Configuration.PrefixSSRSApiURL(repoUrls.report_landmark_count_of_sales) },
{ display: "Landmark: Loan Balance of all Repossessed Collateral", url: Configuration.PrefixSSRSApiURL(repoUrls.report_landmark_loan_balance_inventory) },
{ display: "Landmark: Total Redemption Balance", url: Configuration.PrefixSSRSApiURL(repoUrls.report_landmark_total_redemption_balance) }
];
}
}
export default ReportingService;
@@ -0,0 +1,22 @@
import {Moment} from "moment";
export interface ITemenosHistory {
Source: HistorySource;
Message: string;
Name: string;
UserId: number;
Created?: Moment;
Type: HistoryType;
}
export enum HistoryType {
Comment = 0,
Worfklow = 1,
Letter = 2
}
export enum HistorySource {
Case,
Account
}
@@ -0,0 +1,16 @@
import { IRepoAccount } from "./RepoAccountTypes";
interface IFactoidBase {
readonly cumulativeValue: string;
readonly fontAwesomeIcon: string;
readonly name: string;
readonly description: string;
}
export interface IFactoidResponse extends IFactoidBase {
records: IRepoAccount[];
}
export interface IFactoid extends IFactoidBase {
factoidAccountIds: number[];
}
@@ -0,0 +1,4 @@
export interface ILocationCoordinates {
longitude: number;
latitude: number;
}
@@ -0,0 +1,21 @@
import {Moment} from "moment";
export interface IProcessingReceipt {
accountNo: string;
accountId: string;
caseId: string;
queuedBy: string;
outcome: RepoProcessingResults;
message: string;
processed?: Moment;
}
export enum RepoProcessingResults {
Autoclosed,
Unconverted,
Created,
Updated,
Ineligible,
MissingRequirement,
Error
}
@@ -0,0 +1,115 @@
import { Moment } from "moment";
export interface IRepoCompanySelection {
id: number;
collateralId: number;
repoType?: number;
repoCompanyId?: number;
repoCompanyAssignmentDate?: Moment;
dateRepoed?: Moment;
dateTimeCreated: Moment;
}
export interface IRepoCompanySelectionPostResponse {
previousRepoCompanySelection?: IRepoCompanySelection;
newRepoCompanySelection: IRepoCompanySelection;
}
export interface ICollateral {
collateralId: number;
repoId: number;
vin: string;
make: string;
model: string;
year: number;
retitledInLandmarkName?: Moment;
auctionAssignmentId?: number;
auctionAssignmentDate?: Moment;
refCollateralId?: string;
bodyStyle?: string;
vehicleType?: number;
collateralTypeId?: number;
repoCompanySelections: IRepoCompanySelection[];
}
export interface IBorrower {
repoId: number;
individualId: string;
ownershipType: number;
individualName: string;
}
export interface IRepoStatusChange {
repoId: number;
statusFrom: string;
statusTo: string;
changedBy: string;
changedDate: Moment;
}
export interface IRefundStatus {
repoId: number;
warrantyRefundStatus?: string;
insuranceRefundStatus?: string;
premiumDefiRefundStatus?: string;
cpiRefundStatus?: string;
refundsReceivedDate?: Moment;
}
export interface ISixtyPlusCollector {
sixtyPlusCollectorId: number;
sixtyPlusCollectorName: string;
}
export interface IRepoAccount {
repoId: number;
accountNo: string;
status: string;
memberNo: number;
loanNo: number;
accountTypeCode: string;
origAccountTypeCode: string;
branch: number;
balance: number;
dueToPayDate?: Moment;
o4RDate?: Moment;
dateFirstDelinquent?: Moment;
delinquentAmount: number;
daysDelinquent: number;
paidSkipAmount?: number;
subStatus?: string;
requiredPaymentAmount: number;
currentDelinquentAmount?: number;
lstPmtAmt?: number;
origAmount: number;
lastPaymentDate?: Moment;
dateFirstIntellect?: Moment;
primaryIndividualId: string;
bankruptcy?: string;
manualRedemptionDate?: Moment;
borrowers: IBorrower[];
collaterals: ICollateral[];
repoStatusChanges: IRepoStatusChange[];
redemptionExpiredDate?: Moment;
refundStatus?: IRefundStatus;
dateClosed?: Moment;
referenceId?: string;
referenceCaseId?: string;
accountLastProcessed? : Moment;
writtenOffDate? : Moment;
sixtyPlusCollectorId?: number;
sixtyPlusCollector: ISixtyPlusCollector;
}
export interface IRepoAccountFilters {
alertMessage?: string;
status?: string;
auctionHouseId?: string;
repoCompanyId?: number;
repoIdList?: number[];
onlyOpenAccounts?: boolean;
}
export interface IRepoAccountMap {
[key: number]: IRepoAccount;
}