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 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.active);
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.active);
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gemcap-be-common",
3
- "version": "1.5.22",
3
+ "version": "1.5.24",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -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
- for (const loanTransaction of payment.loanTransactions) {
287
- await LoanTransaction_model_1.LoanTransaction.findByIdAndDelete(loanTransaction.transactionId);
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, dayjs_1.default)(product.deactivationDate).isBefore((0, dayjs_1.default)(combinedPayment.date)));
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
- for (const loanTransaction of payment.loanTransactions) {
327
- await LoanTransaction.findByIdAndDelete(loanTransaction.transactionId);
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 && dayjs(product.deactivationDate).isBefore(dayjs(combinedPayment.date)));
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.active).length > 0;
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.active).length > 0;
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);
@@ -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
- return [
423
- this.addHeaderNew(organization.subfolder), // Add the image element to the content
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 };
@@ -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
- return [
504
- this.addHeaderNew(organization.subfolder), // Add the image element to the content
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