gemcap-be-common 1.5.22 → 1.5.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/db/new-summary.js +2 -1
- package/db/new-summary.ts +2 -1
- package/package.json +1 -1
- package/services/loan-payments.service.js +4 -4
- package/services/loan-payments.service.ts +4 -4
- package/services/nodemailer.service.js +2 -1
- package/services/nodemailer.service.ts +2 -1
- package/services/pdf.service.js +28 -27
- package/services/pdf.service.ts +36 -33
- package/tsconfig.tsbuildinfo +1 -1
package/db/new-summary.js
CHANGED
|
@@ -28,6 +28,7 @@ const ProspectIndustry_model_1 = require("../models/ProspectIndustry.model");
|
|
|
28
28
|
const financial_spreading_service_1 = require("../services/financial-spreading.service");
|
|
29
29
|
const MonthEndData_Model_1 = require("../models/MonthEndData.Model");
|
|
30
30
|
const Yield_model_1 = require("../models/Yield.model");
|
|
31
|
+
const date_helper_1 = require("../helpers/date.helper");
|
|
31
32
|
const styles = {
|
|
32
33
|
blackOnWhiteWithTopBorder: {
|
|
33
34
|
fill: {
|
|
@@ -561,7 +562,7 @@ class NewSummaryExcel {
|
|
|
561
562
|
});
|
|
562
563
|
// TERM LOAN
|
|
563
564
|
const getTermLoanSection = async () => {
|
|
564
|
-
const termProduct = [...productsMap.values()].find((product) => product.borrowerId.toString() === borrowerId && product.type === loan_types_enum_1.ELoanTypes.TERM && product.
|
|
565
|
+
const termProduct = [...productsMap.values()].find((product) => product.borrowerId.toString() === borrowerId && product.type === loan_types_enum_1.ELoanTypes.TERM && (0, date_helper_1.isProductActive)(product.startDate, product.deactivationDate, new Date()));
|
|
565
566
|
if (!termProduct || !availability) {
|
|
566
567
|
return [emptyRow];
|
|
567
568
|
}
|
package/db/new-summary.ts
CHANGED
|
@@ -44,6 +44,7 @@ import { SignsService } from '../services/signs.service';
|
|
|
44
44
|
import { MonthEndDataService } from '../services/month-end-data.service';
|
|
45
45
|
import { EMonthEndDataType } from '../models/MonthEndData.Model';
|
|
46
46
|
import { ETotalType, YIELD_TOTALS_MAP } from '../models/Yield.model';
|
|
47
|
+
import { isProductActive } from '../helpers/date.helper';
|
|
47
48
|
|
|
48
49
|
type DataSheet = {
|
|
49
50
|
[p: string]: IExcelJsCell[][]
|
|
@@ -661,7 +662,7 @@ export class NewSummaryExcel {
|
|
|
661
662
|
|
|
662
663
|
// TERM LOAN
|
|
663
664
|
const getTermLoanSection = async (): Promise<IExcelJsCell[][]> => {
|
|
664
|
-
const termProduct = [...productsMap.values()].find((product) => product.borrowerId.toString() === borrowerId && product.type === ELoanTypes.TERM && product.
|
|
665
|
+
const termProduct = [...productsMap.values()].find((product) => product.borrowerId.toString() === borrowerId && product.type === ELoanTypes.TERM && isProductActive(product.startDate, product.deactivationDate, new Date()));
|
|
665
666
|
if (!termProduct || !availability) {
|
|
666
667
|
return [emptyRow];
|
|
667
668
|
}
|
package/package.json
CHANGED
|
@@ -283,9 +283,9 @@ class LoanPaymentsService {
|
|
|
283
283
|
for (const [index, payment] of payments.entries()) {
|
|
284
284
|
try {
|
|
285
285
|
console.log(`updating payment (for ${product.name}) ${index + 1}/${payments.length}`, (0, dayjs_1.default)(payment.date).format('DD-MM-YYYY'), payment.amount);
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
}
|
|
286
|
+
await LoanTransaction_model_1.LoanTransaction.deleteMany({
|
|
287
|
+
_id: { $in: payment.loanTransactions.map(t => t.transactionId) }
|
|
288
|
+
});
|
|
289
289
|
await LoanPayment_model_1.LoanPaymentModel.findByIdAndUpdate(payment._id, { paid: [], loanTransactions: [] });
|
|
290
290
|
await this.updateLoanPayment(payment, userId);
|
|
291
291
|
}
|
|
@@ -334,7 +334,7 @@ class LoanPaymentsService {
|
|
|
334
334
|
const data = await loanStatementService.getBorrowerComplianceData(combinedPayment.borrowerId, new Date());
|
|
335
335
|
let totalSumToCover = combinedPayment.payment;
|
|
336
336
|
const products = await this.loanChargesService.getLoanProducts(combinedPayment.borrowerId);
|
|
337
|
-
const revolverProduct = products.find((product) => product.type === loan_types_enum_1.ELoanTypes.REVOLVER && (0,
|
|
337
|
+
const revolverProduct = products.find((product) => product.type === loan_types_enum_1.ELoanTypes.REVOLVER && (0, date_helper_1.isProductActive)(product.startDate, product.deactivationDate, combinedPayment.date));
|
|
338
338
|
for (const p of combinedPayment.products) {
|
|
339
339
|
await this.loanProductsService.savePaymentOrder(p.productId, p.paymentOrder);
|
|
340
340
|
const desiredProductSum = data.productTotals[p.productId];
|
|
@@ -323,9 +323,9 @@ export class LoanPaymentsService {
|
|
|
323
323
|
for (const [index, payment] of payments.entries()) {
|
|
324
324
|
try {
|
|
325
325
|
console.log(`updating payment (for ${product.name}) ${index + 1}/${payments.length}`, dayjs(payment.date).format('DD-MM-YYYY'), payment.amount);
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
}
|
|
326
|
+
await LoanTransaction.deleteMany({
|
|
327
|
+
_id: { $in: payment.loanTransactions.map(t => t.transactionId) }
|
|
328
|
+
});
|
|
329
329
|
await LoanPaymentModel.findByIdAndUpdate(payment._id, { paid: [], loanTransactions: [] });
|
|
330
330
|
await this.updateLoanPayment(payment as Partial<ILoanPaymentWithId>, userId);
|
|
331
331
|
} catch (e) {
|
|
@@ -375,7 +375,7 @@ export class LoanPaymentsService {
|
|
|
375
375
|
const data = await loanStatementService.getBorrowerComplianceData(combinedPayment.borrowerId, new Date());
|
|
376
376
|
let totalSumToCover = combinedPayment.payment;
|
|
377
377
|
const products = await this.loanChargesService.getLoanProducts(combinedPayment.borrowerId);
|
|
378
|
-
const revolverProduct = products.find((product) => product.type === ELoanTypes.REVOLVER &&
|
|
378
|
+
const revolverProduct = products.find((product) => product.type === ELoanTypes.REVOLVER && isProductActive(product.startDate, product.deactivationDate, combinedPayment.date));
|
|
379
379
|
|
|
380
380
|
for (const p of combinedPayment.products) {
|
|
381
381
|
await this.loanProductsService.savePaymentOrder(p.productId, p.paymentOrder);
|
|
@@ -35,6 +35,7 @@ const loan_types_enum_1 = require("../enums/loan-types.enum");
|
|
|
35
35
|
const Organization_model_1 = require("../models/Organization.model");
|
|
36
36
|
const FinancialCompliance_model_1 = __importDefault(require("../models/FinancialCompliance.model"));
|
|
37
37
|
const OrganizationEmails_model_1 = require("../models/OrganizationEmails.model");
|
|
38
|
+
const date_helper_1 = require("../helpers/date.helper");
|
|
38
39
|
var ESenderType;
|
|
39
40
|
(function (ESenderType) {
|
|
40
41
|
ESenderType[ESenderType["REGULAR"] = 0] = "REGULAR";
|
|
@@ -406,7 +407,7 @@ class NodemailerService {
|
|
|
406
407
|
const borrower = await this.borrowerService.getBorrowerById(borrowerId);
|
|
407
408
|
const organization = await this.organizationsService.getOrganizationForBorrower(borrowerId);
|
|
408
409
|
const products = await this.loanChargesService.getLoanProducts(borrower._id.toString());
|
|
409
|
-
const borrowerHasRevolver = products.filter((product) => product.type === loan_types_enum_1.ELoanTypes.REVOLVER && product.
|
|
410
|
+
const borrowerHasRevolver = products.filter((product) => product.type === loan_types_enum_1.ELoanTypes.REVOLVER && (0, date_helper_1.isProductActive)(product.startDate, product.deactivationDate, new Date())).length > 0;
|
|
410
411
|
const textPath = path_1.default.resolve(__dirname, '../public/emails', organization.subfolder, borrowerHasRevolver ? 'interest-statement.html' : 'interest-statement-only-term.html');
|
|
411
412
|
const text = await fs.promises.readFile(textPath, 'utf8');
|
|
412
413
|
const signature = await this.getSignatureAsync(ESenderType.FINANCIAL, organization.subfolder);
|
|
@@ -21,6 +21,7 @@ import { LoanChargesService } from './loan-charges.service';
|
|
|
21
21
|
import { OrganizationEmailsService } from './organization-emails.service';
|
|
22
22
|
import { OrganizationsService } from './organizations.service';
|
|
23
23
|
import { SentryService } from './sentry.service';
|
|
24
|
+
import { isProductActive } from '../helpers/date.helper';
|
|
24
25
|
|
|
25
26
|
export enum ESenderType {
|
|
26
27
|
REGULAR,
|
|
@@ -472,7 +473,7 @@ export class NodemailerService {
|
|
|
472
473
|
const borrower = await this.borrowerService.getBorrowerById(borrowerId);
|
|
473
474
|
const organization = await this.organizationsService.getOrganizationForBorrower(borrowerId);
|
|
474
475
|
const products = await this.loanChargesService.getLoanProducts(borrower._id.toString());
|
|
475
|
-
const borrowerHasRevolver = products.filter((product) => product.type === ELoanTypes.REVOLVER && product.
|
|
476
|
+
const borrowerHasRevolver = products.filter((product) => product.type === ELoanTypes.REVOLVER && isProductActive(product.startDate, product.deactivationDate, new Date())).length > 0;
|
|
476
477
|
const textPath = path.resolve(__dirname, '../public/emails', organization.subfolder, borrowerHasRevolver ? 'interest-statement.html' : 'interest-statement-only-term.html');
|
|
477
478
|
const text = await fs.promises.readFile(textPath, 'utf8');
|
|
478
479
|
const signature = await this.getSignatureAsync(ESenderType.FINANCIAL, organization.subfolder);
|
package/services/pdf.service.js
CHANGED
|
@@ -419,8 +419,8 @@ class PdfService {
|
|
|
419
419
|
const warningText = product.type === loan_types_enum_1.ELoanTypes.REVOLVER
|
|
420
420
|
? `AMOUNT WILL BE ADDED TO THE LOAN ON 1ST. ${organization.name.toUpperCase()} RESERVES THE RIGHT TO STOP FUNDING IF THERE IS INSUFFICIENT AVAILABILITY TO ADD IT TO THE LOAN.`
|
|
421
421
|
: `PAYABLE BY 7TH. ${organization.name.toUpperCase()} RESERVES THE RIGHT TO STOP FUNDING IF THE STATEMENT IS NOT PAID.`;
|
|
422
|
-
|
|
423
|
-
this.addHeaderNew(organization.subfolder),
|
|
422
|
+
const baseContent = [
|
|
423
|
+
this.addHeaderNew(organization.subfolder),
|
|
424
424
|
emptyString,
|
|
425
425
|
...preparedStatementHeader,
|
|
426
426
|
emptyString,
|
|
@@ -439,6 +439,32 @@ class PdfService {
|
|
|
439
439
|
preparedTransactions,
|
|
440
440
|
productForPeriod.length === index + 1 ? emptyString : pageBreaker,
|
|
441
441
|
];
|
|
442
|
+
if (product.type === loan_types_enum_1.ELoanTypes.TERM) {
|
|
443
|
+
const { termLoanTableData, monthlyPrincipal, dueDate, } = await this.getTermLoan(product._id.toString(), new Date(start));
|
|
444
|
+
if (monthlyPrincipal !== null) {
|
|
445
|
+
totalStatementValue = new decimal_js_1.default(totalStatementValue).add(monthlyPrincipal).toNumber();
|
|
446
|
+
principalData.push([
|
|
447
|
+
{ text: `Principal (${product.name})` },
|
|
448
|
+
{ text: (0, numbers_helper_1.formatNumbers)(monthlyPrincipal), alignment: 'right' },
|
|
449
|
+
{ text: '' },
|
|
450
|
+
]);
|
|
451
|
+
paymentDueDate = dueDate;
|
|
452
|
+
productTotals[product._id.toString()] = new decimal_js_1.default(productTotals[product._id.toString()]).add(monthlyPrincipal).toNumber();
|
|
453
|
+
}
|
|
454
|
+
return [
|
|
455
|
+
...baseContent,
|
|
456
|
+
pageBreaker,
|
|
457
|
+
this.addHeaderNew(organization.subfolder),
|
|
458
|
+
emptyString,
|
|
459
|
+
{ text: `Term loan schedule: `, fontSize: 15, bold: true },
|
|
460
|
+
emptyString,
|
|
461
|
+
{
|
|
462
|
+
table: { widths: ['*', '*', '*', '*', '*', '*', '*', '*', '*'], body: termLoanTableData },
|
|
463
|
+
layout: 'lightHorizontalLines',
|
|
464
|
+
},
|
|
465
|
+
];
|
|
466
|
+
}
|
|
467
|
+
return baseContent;
|
|
442
468
|
}));
|
|
443
469
|
let totalStatementValue = 0;
|
|
444
470
|
const preparedTotal = Object.entries(totalGroupedData).map(([chargeType, amount]) => {
|
|
@@ -458,31 +484,6 @@ class PdfService {
|
|
|
458
484
|
: [];
|
|
459
485
|
const principalData = [];
|
|
460
486
|
let paymentDueDate = null;
|
|
461
|
-
const termLoanProducts = productForPeriod.filter((product) => product.type === loan_types_enum_1.ELoanTypes.TERM);
|
|
462
|
-
await Promise.all(termLoanProducts.map(async (product) => {
|
|
463
|
-
const { termLoanTableData, monthlyPrincipal, dueDate, } = await this.getTermLoan(product._id.toString(), new Date(start));
|
|
464
|
-
if (monthlyPrincipal !== null) {
|
|
465
|
-
totalStatementValue = new decimal_js_1.default(totalStatementValue).add(monthlyPrincipal).toNumber();
|
|
466
|
-
principalData.push([
|
|
467
|
-
{ text: 'Principal' },
|
|
468
|
-
{ text: (0, numbers_helper_1.formatNumbers)(monthlyPrincipal), alignment: 'right' },
|
|
469
|
-
{ text: '' },
|
|
470
|
-
]);
|
|
471
|
-
paymentDueDate = dueDate;
|
|
472
|
-
productTotals[product._id.toString()] = new decimal_js_1.default(productTotals[product._id.toString()]).add(monthlyPrincipal).toNumber();
|
|
473
|
-
}
|
|
474
|
-
docContent.push([
|
|
475
|
-
pageBreaker,
|
|
476
|
-
this.addHeaderNew(organization.subfolder),
|
|
477
|
-
emptyString,
|
|
478
|
-
{ text: `Term loan schedule: `, fontSize: 15, bold: true },
|
|
479
|
-
emptyString,
|
|
480
|
-
{
|
|
481
|
-
table: { widths: ['*', '*', '*', '*', '*', '*', '*', '*', '*'], body: termLoanTableData },
|
|
482
|
-
layout: 'lightHorizontalLines',
|
|
483
|
-
},
|
|
484
|
-
]);
|
|
485
|
-
}));
|
|
486
487
|
const totalOwed = new decimal_js_1.default(totalStatementValue).add(totalOverDueStatementBalance).toNumber();
|
|
487
488
|
if (getOnlyTotal) {
|
|
488
489
|
return { total: totalOwed, dueDate: paymentDueDate, productTotals };
|
package/services/pdf.service.ts
CHANGED
|
@@ -500,8 +500,8 @@ export class PdfService {
|
|
|
500
500
|
? `AMOUNT WILL BE ADDED TO THE LOAN ON 1ST. ${organization.name.toUpperCase()} RESERVES THE RIGHT TO STOP FUNDING IF THERE IS INSUFFICIENT AVAILABILITY TO ADD IT TO THE LOAN.`
|
|
501
501
|
: `PAYABLE BY 7TH. ${organization.name.toUpperCase()} RESERVES THE RIGHT TO STOP FUNDING IF THE STATEMENT IS NOT PAID.`;
|
|
502
502
|
|
|
503
|
-
|
|
504
|
-
this.addHeaderNew(organization.subfolder),
|
|
503
|
+
const baseContent = [
|
|
504
|
+
this.addHeaderNew(organization.subfolder),
|
|
505
505
|
emptyString,
|
|
506
506
|
...preparedStatementHeader,
|
|
507
507
|
emptyString,
|
|
@@ -520,6 +520,40 @@ export class PdfService {
|
|
|
520
520
|
preparedTransactions,
|
|
521
521
|
productForPeriod.length === index + 1 ? emptyString : pageBreaker,
|
|
522
522
|
];
|
|
523
|
+
|
|
524
|
+
if (product.type === ELoanTypes.TERM) {
|
|
525
|
+
const {
|
|
526
|
+
termLoanTableData,
|
|
527
|
+
monthlyPrincipal,
|
|
528
|
+
dueDate,
|
|
529
|
+
} = await this.getTermLoan(product._id.toString(), new Date(start));
|
|
530
|
+
|
|
531
|
+
if (monthlyPrincipal !== null) {
|
|
532
|
+
totalStatementValue = new Decimal(totalStatementValue).add(monthlyPrincipal).toNumber();
|
|
533
|
+
principalData.push([
|
|
534
|
+
{ text: `Principal (${product.name})` },
|
|
535
|
+
{ text: formatNumbers(monthlyPrincipal), alignment: 'right' },
|
|
536
|
+
{ text: '' },
|
|
537
|
+
]);
|
|
538
|
+
paymentDueDate = dueDate;
|
|
539
|
+
productTotals[product._id.toString()] = new Decimal(productTotals[product._id.toString()]).add(monthlyPrincipal).toNumber();
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
return [
|
|
543
|
+
...baseContent,
|
|
544
|
+
pageBreaker,
|
|
545
|
+
this.addHeaderNew(organization.subfolder),
|
|
546
|
+
emptyString,
|
|
547
|
+
<any>{ text: `Term loan schedule: `, fontSize: 15, bold: true },
|
|
548
|
+
emptyString,
|
|
549
|
+
{
|
|
550
|
+
table: { widths: ['*', '*', '*', '*', '*', '*', '*', '*', '*'], body: termLoanTableData },
|
|
551
|
+
layout: 'lightHorizontalLines',
|
|
552
|
+
},
|
|
553
|
+
];
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
return baseContent;
|
|
523
557
|
}));
|
|
524
558
|
|
|
525
559
|
let totalStatementValue = 0;
|
|
@@ -541,37 +575,6 @@ export class PdfService {
|
|
|
541
575
|
|
|
542
576
|
const principalData = [];
|
|
543
577
|
let paymentDueDate: Date = null;
|
|
544
|
-
const termLoanProducts = productForPeriod.filter((product) => product.type === ELoanTypes.TERM);
|
|
545
|
-
await Promise.all(termLoanProducts.map(async (product) => {
|
|
546
|
-
const {
|
|
547
|
-
termLoanTableData,
|
|
548
|
-
monthlyPrincipal,
|
|
549
|
-
dueDate,
|
|
550
|
-
} = await this.getTermLoan(product._id.toString(), new Date(start));
|
|
551
|
-
|
|
552
|
-
if (monthlyPrincipal !== null) {
|
|
553
|
-
totalStatementValue = new Decimal(totalStatementValue).add(monthlyPrincipal).toNumber();
|
|
554
|
-
principalData.push([
|
|
555
|
-
{ text: 'Principal' },
|
|
556
|
-
{ text: formatNumbers(monthlyPrincipal), alignment: 'right' },
|
|
557
|
-
{ text: '' },
|
|
558
|
-
]);
|
|
559
|
-
paymentDueDate = dueDate;
|
|
560
|
-
productTotals[product._id.toString()] = new Decimal(productTotals[product._id.toString()]).add(monthlyPrincipal).toNumber();
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
docContent.push([
|
|
564
|
-
pageBreaker,
|
|
565
|
-
this.addHeaderNew(organization.subfolder),
|
|
566
|
-
emptyString,
|
|
567
|
-
<any>{ text: `Term loan schedule: `, fontSize: 15, bold: true },
|
|
568
|
-
emptyString,
|
|
569
|
-
{
|
|
570
|
-
table: { widths: ['*', '*', '*', '*', '*', '*', '*', '*', '*'], body: termLoanTableData },
|
|
571
|
-
layout: 'lightHorizontalLines',
|
|
572
|
-
},
|
|
573
|
-
]);
|
|
574
|
-
}));
|
|
575
578
|
|
|
576
579
|
const totalOwed = new Decimal(totalStatementValue).add(totalOverDueStatementBalance).toNumber();
|
|
577
580
|
|