gemcap-be-common 1.2.140 → 1.3.0
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/classes/bank-transaction-item.d.ts +17 -0
- package/classes/bank-transaction-item.js +64 -0
- package/classes/bank-transaction-item.ts +66 -0
- package/classes/bank-uploaded-transaction.d.ts +17 -0
- package/classes/bank-uploaded-transaction.js +35 -0
- package/classes/bank-uploaded-transaction.ts +35 -0
- package/classes/inventory-item.d.ts +41 -0
- package/classes/inventory-item.js +44 -0
- package/classes/inventory-item.ts +63 -0
- package/classes/payable-account-item.d.ts +22 -0
- package/classes/payable-account-item.js +27 -0
- package/classes/payable-account-item.ts +35 -0
- package/classes/quickbook-item.d.ts +37 -0
- package/classes/quickbook-item.js +51 -0
- package/classes/quickbook-item.ts +59 -0
- package/classes/receivable-item.d.ts +26 -0
- package/classes/receivable-item.js +28 -0
- package/classes/receivable-item.ts +38 -0
- package/constants/date-formats.contsants.d.ts +1 -0
- package/constants/date-formats.contsants.js +4 -0
- package/constants/date-formats.contsants.ts +1 -0
- package/db/brokers.db.d.ts +185 -0
- package/db/brokers.db.js +35 -2
- package/db/brokers.db.ts +34 -1
- package/db/collateral-adjustments.db.d.ts +34 -0
- package/db/collateral-adjustments.db.js +52 -0
- package/db/collateral-adjustments.db.ts +54 -0
- package/db/collaterals.db.d.ts +1 -1
- package/db/equipment.db.d.ts +40 -0
- package/db/equipment.db.js +55 -0
- package/db/equipment.db.ts +56 -0
- package/db/financial-spreading.db.ts +2 -1
- package/db/groups.d.ts +5 -0
- package/db/groups.js +57 -0
- package/db/groups.ts +52 -0
- package/db/inventories.d.ts +91 -0
- package/db/inventories.js +449 -0
- package/db/inventories.ts +481 -0
- package/db/inventory-availability.d.ts +3 -0
- package/db/inventory-availability.js +103 -0
- package/db/inventory-availability.ts +113 -0
- package/db/new-summary.d.ts +31 -0
- package/db/new-summary.js +1295 -0
- package/db/new-summary.ts +1509 -0
- package/db/payable-accounts.d.ts +30 -0
- package/db/payable-accounts.js +55 -0
- package/db/payable-accounts.ts +50 -0
- package/db/reserve.db.d.ts +34 -0
- package/db/reserve.db.js +52 -0
- package/db/reserve.db.ts +48 -0
- package/db/uploads.db.d.ts +2 -0
- package/db/uploads.db.js +29 -0
- package/db/uploads.db.ts +24 -0
- package/helpers/main.helper.d.ts +31 -0
- package/helpers/main.helper.js +63 -0
- package/helpers/main.helper.ts +63 -0
- package/models/AccountPayableItem.model.d.ts +6 -6
- package/models/AllocatedBankTransaction.model.d.ts +54 -0
- package/models/AllocatedBankTransaction.model.js +70 -0
- package/models/AllocatedBankTransaction.model.ts +94 -0
- package/models/AllocatedData.model.d.ts +33 -0
- package/models/AllocatedData.model.js +19 -0
- package/models/AllocatedData.model.ts +24 -0
- package/models/BBCDate.model.d.ts +3 -3
- package/models/BBCSheet.model.d.ts +3 -3
- package/models/Banks.model.d.ts +3 -3
- package/models/Borrower.model.d.ts +3 -3
- package/models/BorrowerData.model.d.ts +3 -3
- package/models/BorrowerDataInsurance.model.d.ts +3 -3
- package/models/BorrowerDataTerm.model.d.ts +3 -3
- package/models/BorrowerSummary.model.js +1 -1
- package/models/BorrowerSummary.model.ts +1 -1
- package/models/CalandarDay.model.d.ts +40 -0
- package/models/CalandarDay.model.js +47 -0
- package/models/CalandarDay.model.ts +61 -0
- package/models/CashAllocationProduct.model.d.ts +119 -0
- package/models/CashAllocationProduct.model.js +102 -0
- package/models/CashAllocationProduct.model.ts +112 -0
- package/models/CashAllocationReference.model.d.ts +37 -0
- package/models/CashAllocationReference.model.js +27 -0
- package/models/CashAllocationReference.model.ts +40 -0
- package/models/CollateralAdjustment.model.d.ts +51 -0
- package/models/CollateralAdjustment.model.js +61 -0
- package/models/CollateralAdjustment.model.ts +98 -0
- package/models/Company.model.d.ts +35 -0
- package/models/Company.model.js +18 -0
- package/models/Company.model.ts +29 -0
- package/models/CustomerAPGroup.model.d.ts +32 -0
- package/models/CustomerAPGroup.model.js +24 -0
- package/models/CustomerAPGroup.model.ts +31 -0
- package/models/Equipment.model.d.ts +53 -0
- package/models/Equipment.model.js +140 -0
- package/models/Equipment.model.ts +172 -0
- package/models/FinancialCompliance.model.d.ts +39 -0
- package/models/FinancialCompliance.model.js +64 -0
- package/models/FinancialCompliance.model.ts +78 -0
- package/models/FinancialComplianceBorrower.model.d.ts +58 -0
- package/models/FinancialComplianceBorrower.model.js +82 -0
- package/models/FinancialComplianceBorrower.model.ts +118 -0
- package/models/FinancialIndexes.model.d.ts +36 -0
- package/models/FinancialIndexes.model.js +27 -0
- package/models/FinancialIndexes.model.ts +37 -0
- package/models/Inventory.model.d.ts +18 -18
- package/models/InventoryAvailability.model.d.ts +21 -21
- package/models/InventoryAvailabilityItem.model.d.ts +6 -6
- package/models/InventoryItem.model.d.ts +24 -24
- package/models/InventoryManualEntry.model.d.ts +9 -9
- package/models/InventorySeasonalRates.model.d.ts +3 -3
- package/models/LoanBroker.model.d.ts +3 -3
- package/models/LoanCharges.model.d.ts +12 -12
- package/models/LoanProducts.model.d.ts +9 -9
- package/models/LoanStatementStatus.model.d.ts +35 -0
- package/models/LoanStatementStatus.model.js +34 -0
- package/models/LoanStatementStatus.model.ts +45 -0
- package/models/LoanStatementTransaction.model.d.ts +9 -9
- package/models/LoanTransactionFile.model.d.ts +41 -0
- package/models/LoanTransactionFile.model.js +44 -0
- package/models/LoanTransactionFile.model.ts +61 -0
- package/models/MappedGroup.model.d.ts +37 -0
- package/models/MappedGroup.model.js +33 -0
- package/models/MappedGroup.model.ts +46 -0
- package/models/MonthEndData.Model.d.ts +41 -0
- package/models/MonthEndData.Model.js +42 -0
- package/models/MonthEndData.Model.ts +53 -0
- package/models/OrganizationEmails.model.d.ts +44 -0
- package/models/OrganizationEmails.model.js +40 -0
- package/models/OrganizationEmails.model.ts +54 -0
- package/models/ProductBroker.model.d.ts +9 -9
- package/models/QuickbooksAccount.model.d.ts +39 -0
- package/models/QuickbooksAccount.model.js +43 -0
- package/models/QuickbooksAccount.model.ts +57 -0
- package/models/Receivable.model.d.ts +12 -12
- package/models/ReceivableAvailability.model.d.ts +54 -54
- package/models/ReceivableAvailabilityItem.model.d.ts +57 -57
- package/models/ReceivableItem.model.d.ts +6 -6
- package/models/Reserve.model.d.ts +51 -0
- package/models/Reserve.model.js +96 -0
- package/models/Reserve.model.ts +125 -0
- package/models/TermLoan.model.d.ts +3 -3
- package/models/TermLoanCalculated.model.d.ts +6 -6
- package/models/TransactionAttachedFile.Model.d.ts +35 -0
- package/models/TransactionAttachedFile.Model.js +37 -0
- package/models/TransactionAttachedFile.Model.ts +48 -0
- package/models/UploadedBankTransaction.model.d.ts +56 -0
- package/models/UploadedBankTransaction.model.js +78 -0
- package/models/UploadedBankTransaction.model.ts +110 -0
- package/models/UploadedData.model.d.ts +36 -0
- package/models/UploadedData.model.js +23 -0
- package/models/UploadedData.model.ts +35 -0
- package/models/UploadedFile.model.d.ts +40 -0
- package/models/UploadedFile.model.js +41 -0
- package/models/UploadedFile.model.ts +57 -0
- package/models/UploadedSheet.model.d.ts +46 -0
- package/models/UploadedSheet.model.js +27 -0
- package/models/UploadedSheet.model.ts +51 -0
- package/package.json +10 -1
- package/repositories/globals.repository.d.ts +8 -0
- package/repositories/globals.repository.js +24 -0
- package/repositories/globals.repository.ts +21 -0
- package/services/attached-files.service.d.ts +57 -0
- package/services/attached-files.service.js +103 -0
- package/services/attached-files.service.ts +123 -0
- package/services/availability.service.d.ts +77 -0
- package/services/availability.service.js +897 -0
- package/services/availability.service.ts +1034 -0
- package/services/bank-uploaded-transactions.service.d.ts +33 -0
- package/services/bank-uploaded-transactions.service.js +430 -0
- package/services/bank-uploaded-transactions.service.ts +475 -0
- package/services/banks.service.d.ts +36 -0
- package/services/banks.service.js +91 -0
- package/services/banks.service.ts +95 -0
- package/services/borrower-summary.service.d.ts +35 -0
- package/services/borrower-summary.service.js +310 -0
- package/services/borrower-summary.service.ts +334 -0
- package/services/borrowers.service.d.ts +103 -0
- package/services/borrowers.service.js +268 -0
- package/services/borrowers.service.ts +302 -0
- package/services/brokers.service.d.ts +212 -0
- package/services/brokers.service.js +160 -0
- package/services/brokers.service.ts +200 -0
- package/services/calendar.service.d.ts +53 -0
- package/services/calendar.service.js +108 -0
- package/services/calendar.service.ts +128 -0
- package/services/cash-allocation.service.d.ts +40 -0
- package/services/cash-allocation.service.js +92 -0
- package/services/cash-allocation.service.ts +105 -0
- package/services/collateral-adjustments.service.d.ts +38 -0
- package/services/collateral-adjustments.service.js +82 -0
- package/services/collateral-adjustments.service.ts +95 -0
- package/services/collaterals.service.d.ts +69 -0
- package/services/collaterals.service.js +279 -0
- package/services/collaterals.service.ts +319 -0
- package/services/companies.service.d.ts +5 -0
- package/services/companies.service.js +21 -0
- package/services/companies.service.ts +23 -0
- package/services/compliance-borrowers.service.d.ts +152 -0
- package/services/compliance-borrowers.service.js +569 -0
- package/services/compliance-borrowers.service.ts +617 -0
- package/services/equipment.service.d.ts +42 -0
- package/services/equipment.service.js +120 -0
- package/services/equipment.service.ts +149 -0
- package/services/file-manager.service.d.ts +44 -0
- package/services/file-manager.service.js +120 -0
- package/services/file-manager.service.ts +146 -0
- package/services/financial-compliance.service.d.ts +58 -0
- package/services/financial-compliance.service.js +281 -0
- package/services/financial-compliance.service.ts +309 -0
- package/services/financial-indexes.service.d.ts +20 -0
- package/services/financial-indexes.service.js +241 -0
- package/services/financial-indexes.service.ts +257 -0
- package/services/financial-spreading.service.d.ts +74 -0
- package/services/financial-spreading.service.js +450 -0
- package/services/financial-spreading.service.ts +517 -0
- package/services/globals.service.d.ts +5 -0
- package/services/globals.service.js +11 -0
- package/services/globals.service.ts +8 -0
- package/services/groups.service.d.ts +39 -0
- package/services/groups.service.js +65 -0
- package/services/groups.service.ts +64 -0
- package/services/inventory-availability.service.d.ts +13 -0
- package/services/inventory-availability.service.js +170 -0
- package/services/inventory-availability.service.ts +187 -0
- package/services/inventory.service.d.ts +118 -0
- package/services/inventory.service.js +239 -0
- package/services/inventory.service.ts +276 -0
- package/services/loan-charges.service.d.ts +83 -0
- package/services/loan-charges.service.js +343 -0
- package/services/loan-charges.service.ts +396 -0
- package/services/loan-payments.service.d.ts +94 -0
- package/services/loan-payments.service.js +485 -0
- package/services/loan-payments.service.ts +541 -0
- package/services/loan-products.service.d.ts +12 -0
- package/services/loan-products.service.js +55 -0
- package/services/loan-products.service.ts +58 -0
- package/services/loan-statement-balance.service.d.ts +16 -0
- package/services/loan-statement-balance.service.js +106 -0
- package/services/loan-statement-balance.service.ts +113 -0
- package/services/loan-statement-effects.service.d.ts +8 -0
- package/services/loan-statement-effects.service.js +42 -0
- package/services/loan-statement-effects.service.ts +41 -0
- package/services/loan-statement-status.service.d.ts +208 -0
- package/services/loan-statement-status.service.js +159 -0
- package/services/loan-statement-status.service.ts +177 -0
- package/services/loan-statement.service.d.ts +186 -0
- package/services/loan-statement.service.js +935 -0
- package/services/loan-statement.service.ts +1040 -0
- package/services/loan-transactions.service.d.ts +169 -0
- package/services/loan-transactions.service.js +941 -0
- package/services/loan-transactions.service.ts +1042 -0
- package/services/lock.service.d.ts +6 -0
- package/services/lock.service.js +45 -0
- package/services/lock.service.ts +45 -0
- package/services/manual-entry.service.d.ts +20 -0
- package/services/manual-entry.service.js +186 -0
- package/services/manual-entry.service.ts +201 -0
- package/services/month-end-data.service.d.ts +34 -0
- package/services/month-end-data.service.js +30 -0
- package/services/month-end-data.service.ts +35 -0
- package/services/nodemailer.service.d.ts +96 -0
- package/services/nodemailer.service.js +689 -0
- package/services/nodemailer.service.ts +774 -0
- package/services/organization-emails.service.d.ts +31 -0
- package/services/organization-emails.service.js +10 -0
- package/services/organization-emails.service.ts +7 -0
- package/services/organizations.service.d.ts +34 -0
- package/services/organizations.service.js +74 -0
- package/services/organizations.service.ts +84 -0
- package/services/pdf.service.d.ts +61 -0
- package/services/pdf.service.js +547 -0
- package/services/pdf.service.ts +642 -0
- package/services/quickbooks.service.d.ts +99 -0
- package/services/quickbooks.service.js +640 -0
- package/services/quickbooks.service.ts +734 -0
- package/services/reports/investor-summary.service.d.ts +28 -0
- package/services/reports/investor-summary.service.js +136 -0
- package/services/reports/investor-summary.service.ts +159 -0
- package/services/reports.service.d.ts +126 -0
- package/services/reports.service.js +584 -0
- package/services/reports.service.ts +702 -0
- package/services/reserve.service.d.ts +37 -0
- package/services/reserve.service.js +76 -0
- package/services/reserve.service.ts +79 -0
- package/services/sentry.service.d.ts +11 -0
- package/services/sentry.service.js +49 -0
- package/services/sentry.service.ts +33 -0
- package/services/signs.service.d.ts +69 -0
- package/services/signs.service.js +230 -0
- package/services/signs.service.ts +260 -0
- package/services/term-loan.service.d.ts +30 -0
- package/services/term-loan.service.js +614 -0
- package/services/term-loan.service.ts +696 -0
- package/services/uploads.service.d.ts +134 -0
- package/services/uploads.service.js +587 -0
- package/services/uploads.service.ts +643 -0
- package/services/user-logs.service.d.ts +23 -0
- package/services/user-logs.service.js +160 -0
- package/services/user-logs.service.ts +177 -0
- package/services/users.service.d.ts +4 -4
- package/services/yield.service.d.ts +46 -0
- package/services/yield.service.js +42 -12
- package/services/yield.service.ts +38 -8
- package/tsconfig.json +5 -5
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,689 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.NodemailerService = exports.ESenderType = void 0;
|
|
30
|
+
const fs = __importStar(require("fs"));
|
|
31
|
+
const path_1 = __importDefault(require("path"));
|
|
32
|
+
const dayjs_1 = __importDefault(require("dayjs"));
|
|
33
|
+
const nodemailer_1 = __importDefault(require("nodemailer"));
|
|
34
|
+
const loan_types_enum_1 = require("../enums/loan-types.enum");
|
|
35
|
+
const Organization_model_1 = require("../models/Organization.model");
|
|
36
|
+
const FinancialCompliance_model_1 = __importDefault(require("../models/FinancialCompliance.model"));
|
|
37
|
+
const OrganizationEmails_model_1 = require("../models/OrganizationEmails.model");
|
|
38
|
+
var ESenderType;
|
|
39
|
+
(function (ESenderType) {
|
|
40
|
+
ESenderType[ESenderType["REGULAR"] = 0] = "REGULAR";
|
|
41
|
+
ESenderType[ESenderType["FINANCIAL"] = 1] = "FINANCIAL";
|
|
42
|
+
ESenderType[ESenderType["FINANCIAL_ONLY"] = 2] = "FINANCIAL_ONLY";
|
|
43
|
+
ESenderType[ESenderType["GOAT"] = 3] = "GOAT";
|
|
44
|
+
})(ESenderType || (exports.ESenderType = ESenderType = {}));
|
|
45
|
+
const getSenderSignatureFileName = (senderType) => {
|
|
46
|
+
switch (senderType) {
|
|
47
|
+
case ESenderType.REGULAR:
|
|
48
|
+
return 'signature.html';
|
|
49
|
+
case ESenderType.FINANCIAL:
|
|
50
|
+
return 'signature-financial.html';
|
|
51
|
+
case ESenderType.FINANCIAL_ONLY:
|
|
52
|
+
return 'signature-financial-only.html';
|
|
53
|
+
case ESenderType.GOAT:
|
|
54
|
+
return 'signature-goat.html';
|
|
55
|
+
default:
|
|
56
|
+
return 'signature.html';
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
class NodemailerService {
|
|
60
|
+
borrowerService;
|
|
61
|
+
getComplianceBorrowersService;
|
|
62
|
+
fileManagerService;
|
|
63
|
+
financialComplianceService;
|
|
64
|
+
loanChargesService;
|
|
65
|
+
organizationEmailsService;
|
|
66
|
+
organizationsService;
|
|
67
|
+
sentryService;
|
|
68
|
+
config;
|
|
69
|
+
senders;
|
|
70
|
+
transporter;
|
|
71
|
+
constructor(config, borrowerService, getComplianceBorrowersService, fileManagerService, financialComplianceService, loanChargesService, organizationEmailsService, organizationsService, sentryService) {
|
|
72
|
+
this.borrowerService = borrowerService;
|
|
73
|
+
this.getComplianceBorrowersService = getComplianceBorrowersService;
|
|
74
|
+
this.fileManagerService = fileManagerService;
|
|
75
|
+
this.financialComplianceService = financialComplianceService;
|
|
76
|
+
this.loanChargesService = loanChargesService;
|
|
77
|
+
this.organizationEmailsService = organizationEmailsService;
|
|
78
|
+
this.organizationsService = organizationsService;
|
|
79
|
+
this.sentryService = sentryService;
|
|
80
|
+
this.config = config;
|
|
81
|
+
this.senders = {
|
|
82
|
+
[ESenderType.REGULAR]: {
|
|
83
|
+
senderName: this.config.appTitle,
|
|
84
|
+
senderEmail: this.config.sender,
|
|
85
|
+
},
|
|
86
|
+
[ESenderType.FINANCIAL]: {
|
|
87
|
+
senderName: `${this.config.appTitle} Finance Department`,
|
|
88
|
+
senderEmail: this.config.senderFinancial,
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
this.transporter = nodemailer_1.default.createTransport(this.config.mailerConfig);
|
|
92
|
+
}
|
|
93
|
+
getSender(senderType) {
|
|
94
|
+
switch (senderType) {
|
|
95
|
+
case ESenderType.REGULAR:
|
|
96
|
+
return `${this.senders[senderType].senderName} <${this.senders[senderType].senderEmail}>`;
|
|
97
|
+
case ESenderType.FINANCIAL:
|
|
98
|
+
return `${this.senders[senderType].senderName} <${this.senders[senderType].senderEmail}>`;
|
|
99
|
+
default:
|
|
100
|
+
return `"${this.config.appTitle}>" <${this.config.sender}>`;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
;
|
|
104
|
+
async senderHandler(err, info) {
|
|
105
|
+
if (err) {
|
|
106
|
+
this.sentryService.catchErrorBySentry(null, err);
|
|
107
|
+
throw err;
|
|
108
|
+
}
|
|
109
|
+
console.log(info.envelope);
|
|
110
|
+
console.log(info.messageId);
|
|
111
|
+
console.log('Message sent: %s', info.messageId);
|
|
112
|
+
console.log('Preview URL: %s', nodemailer_1.default.getTestMessageUrl(info));
|
|
113
|
+
}
|
|
114
|
+
async getSignatureAsync(senderType, organizationSubfolder) {
|
|
115
|
+
const signaturePath = path_1.default.resolve(__dirname, '../public/emails', organizationSubfolder ? organizationSubfolder : '', getSenderSignatureFileName(senderType));
|
|
116
|
+
return await fs.promises.readFile(signaturePath, 'utf8');
|
|
117
|
+
}
|
|
118
|
+
async collectItemsAndNotify(borrowerId) {
|
|
119
|
+
const complianceBorrowersService = this.getComplianceBorrowersService();
|
|
120
|
+
const borrower = await complianceBorrowersService.getFullComplianceBorrowerById(borrowerId);
|
|
121
|
+
if (!borrower.isEmailingActive) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
let hasPastDueItems = false;
|
|
125
|
+
let allInReview = true;
|
|
126
|
+
const fullItems = borrower.items.reduce((accI, item) => {
|
|
127
|
+
return [...accI, ...item.instances.reduce((accIns, instance) => {
|
|
128
|
+
if (instance.status === 'ACCEPTED') {
|
|
129
|
+
return accIns;
|
|
130
|
+
}
|
|
131
|
+
const currentDate = (0, dayjs_1.default)();
|
|
132
|
+
const dueDate = (0, dayjs_1.default)(instance.nextDate);
|
|
133
|
+
const dateToNotify = (0, dayjs_1.default)(instance.nextDate).subtract(item.item.notificationDays, 'day');
|
|
134
|
+
const diff = currentDate.diff(dueDate);
|
|
135
|
+
const addresses = [
|
|
136
|
+
...borrower.mainEmails.reduce((acc, address) => address.isActive === true ? [...acc, address.email] : acc, []),
|
|
137
|
+
...item.emailAddresses.reduce((acc, address) => address.isActive === true ? [...acc, address.email] : acc, [])
|
|
138
|
+
];
|
|
139
|
+
if (diff > 0) {
|
|
140
|
+
hasPastDueItems = instance.status !== 'IN_REVIEW';
|
|
141
|
+
allInReview = allInReview && instance.status === 'IN_REVIEW';
|
|
142
|
+
return [...accIns, {
|
|
143
|
+
itemName: item.item.name,
|
|
144
|
+
dateDue: instance.nextDate,
|
|
145
|
+
status: instance.status === 'IN_REVIEW' ? 'In review' : 'Past due',
|
|
146
|
+
addresses,
|
|
147
|
+
}];
|
|
148
|
+
}
|
|
149
|
+
const notificationDiff = currentDate.diff(dateToNotify);
|
|
150
|
+
if (notificationDiff > 0 && instance.status !== 'IN_REVIEW') {
|
|
151
|
+
allInReview = allInReview && false;
|
|
152
|
+
return [...accIns, {
|
|
153
|
+
itemName: item.item.name,
|
|
154
|
+
dateDue: instance.nextDate,
|
|
155
|
+
status: 'Waiting for submission',
|
|
156
|
+
addresses,
|
|
157
|
+
}];
|
|
158
|
+
}
|
|
159
|
+
return accIns;
|
|
160
|
+
}, [])];
|
|
161
|
+
}, []);
|
|
162
|
+
if (!allInReview && fullItems.length) {
|
|
163
|
+
const uniqEmails = new Set();
|
|
164
|
+
fullItems.forEach((item) => item.addresses.forEach((address) => uniqEmails.add(address)));
|
|
165
|
+
await Promise.all(Array.from(uniqEmails).map(async (emailAddress) => {
|
|
166
|
+
const email = {
|
|
167
|
+
recipientName: borrower.borrower.name,
|
|
168
|
+
complianceBorrowerId: String(borrower._id),
|
|
169
|
+
addresses: [emailAddress],
|
|
170
|
+
subject: 'Reminder',
|
|
171
|
+
text: '',
|
|
172
|
+
hasPastDueItems,
|
|
173
|
+
items: fullItems.filter((item) => item.addresses.includes(emailAddress)),
|
|
174
|
+
};
|
|
175
|
+
await this.sendEmailNotification(email, borrower.borrower._id.toString());
|
|
176
|
+
}));
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
async sendEmailNotification(email, borrowerId) {
|
|
180
|
+
const organizations = await this.organizationsService.getOrganizationForBorrower(borrowerId);
|
|
181
|
+
const senderEmail = await this.organizationEmailsService.getEmail(organizations._id.toString(), OrganizationEmails_model_1.OrganizationEmailsType.SENDER);
|
|
182
|
+
const hiddenRecipientEmail = await this.organizationEmailsService.getEmail(organizations._id.toString(), OrganizationEmails_model_1.OrganizationEmailsType.HIDDEN_RECIPIENT);
|
|
183
|
+
fs.readFile(path_1.default.resolve(__dirname, '../public/emails', organizations.subfolder, 'notification.html'), 'utf8', async (error, data) => {
|
|
184
|
+
if (error) {
|
|
185
|
+
console.error({ error });
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
const signature = await this.getSignatureAsync(ESenderType.REGULAR, organizations.subfolder);
|
|
189
|
+
const tableRows = email.items.reduce((acc, item) => {
|
|
190
|
+
return `${acc}
|
|
191
|
+
<tr>
|
|
192
|
+
<td style="border: 1px solid black">${item.itemName}</td>
|
|
193
|
+
<td style="border: 1px solid black">${item.dateDue.toLocaleDateString()}</td>
|
|
194
|
+
<td style="border: 1px solid black">${item.status}</td>
|
|
195
|
+
</tr>`;
|
|
196
|
+
}, '');
|
|
197
|
+
const tableHtml = `
|
|
198
|
+
<table style="width:100%; border: 1px solid black; border-spacing: 0" >
|
|
199
|
+
<tr>
|
|
200
|
+
<th style="border: 2px solid black">Compliance Item</th>
|
|
201
|
+
<th style="border: 2px solid black">Date Due</th>
|
|
202
|
+
<th style="border: 2px solid black">Status</th>
|
|
203
|
+
</tr>
|
|
204
|
+
${tableRows}
|
|
205
|
+
</table>`;
|
|
206
|
+
const hasPastDueItemsWarning = email.hasPastDueItems
|
|
207
|
+
? `<p><span style="color: #ff0000;"><strong>You have past due items which is a breach of the obligations under the loan agreement. Failure to submit the above documents may cause a delay in funding and an event of default. If you cannot submit the documents please contact us urgently.</strong></span></p>`
|
|
208
|
+
: '';
|
|
209
|
+
const replacedData = data
|
|
210
|
+
.replace('${recipientName}', email.recipientName)
|
|
211
|
+
.replace('${items}', tableHtml)
|
|
212
|
+
.replace('${hasPastDueItems}', hasPastDueItemsWarning)
|
|
213
|
+
.replace('${signature}', signature);
|
|
214
|
+
try {
|
|
215
|
+
this.transporter.sendMail({
|
|
216
|
+
from: `${senderEmail.title} <${senderEmail.address}>`,
|
|
217
|
+
to: email.addresses,
|
|
218
|
+
bcc: `${hiddenRecipientEmail.title} <${hiddenRecipientEmail.address}>`,
|
|
219
|
+
subject: email.subject,
|
|
220
|
+
text: 'non-html',
|
|
221
|
+
html: replacedData,
|
|
222
|
+
}, async (err, info) => {
|
|
223
|
+
await this.senderHandler(err, info);
|
|
224
|
+
const complianceBorrowersService = this.getComplianceBorrowersService();
|
|
225
|
+
await complianceBorrowersService.updateLastEmailSent(email.complianceBorrowerId, new Date());
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
catch (e) {
|
|
229
|
+
this.sentryService.catchErrorBySentry(null, e);
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
async sendPasswordEmail(user, password) {
|
|
234
|
+
fs.readFile(path_1.default.resolve(__dirname, '../public/emails', 'password-reset.html'), 'utf8', async (error, data) => {
|
|
235
|
+
if (error) {
|
|
236
|
+
console.error({ error });
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
const signature = await this.getSignatureAsync(ESenderType.REGULAR);
|
|
240
|
+
const replacedData = data
|
|
241
|
+
.replace('${username}', user.username)
|
|
242
|
+
.replace('${password}', password.toString())
|
|
243
|
+
.replace('${signature}', signature);
|
|
244
|
+
try {
|
|
245
|
+
this.transporter.sendMail({
|
|
246
|
+
from: this.getSender(ESenderType.REGULAR),
|
|
247
|
+
to: user.email,
|
|
248
|
+
bcc: this.config.hiddenRecipient,
|
|
249
|
+
subject: `Welcome to ${this.config.appTitle}`,
|
|
250
|
+
text: 'non-html',
|
|
251
|
+
html: replacedData,
|
|
252
|
+
}, async (err, info) => {
|
|
253
|
+
await this.senderHandler(err, info);
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
catch (e) {
|
|
257
|
+
this.sentryService.catchErrorBySentry(null, e);
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
async sendDailyUpdates() {
|
|
262
|
+
fs.readFile(path_1.default.resolve(__dirname, '../public/emails', 'daily-updates.html'), 'utf8', async (error, data) => {
|
|
263
|
+
if (error) {
|
|
264
|
+
console.error({ error });
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
const signature = await this.getSignatureAsync(ESenderType.REGULAR);
|
|
268
|
+
const borrowerWithFiles = await this.fileManagerService.getFilesNewerThanDate((0, dayjs_1.default)().startOf('day').toDate());
|
|
269
|
+
if (!borrowerWithFiles.length) {
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
const borrowerTables = borrowerWithFiles.reduce((allBorrowers, borrower) => {
|
|
273
|
+
const tableRows = borrower.files.reduce((borrowerAcc, file) => {
|
|
274
|
+
return `
|
|
275
|
+
${borrowerAcc}
|
|
276
|
+
<tr>
|
|
277
|
+
<td style="border: 1px solid black">${file.name}</td>
|
|
278
|
+
<td style="border: 1px solid black">${file.uploadedAt.toLocaleDateString()}</td>
|
|
279
|
+
</tr>`;
|
|
280
|
+
}, '');
|
|
281
|
+
const borrowerLink = `https://analytics.traxabl.com/compliance/borrowers/${borrower._id}`;
|
|
282
|
+
return `
|
|
283
|
+
${allBorrowers}
|
|
284
|
+
<br>
|
|
285
|
+
<a href="${borrowerLink}">${borrower.borrower.name}</a>
|
|
286
|
+
<table style="width:100%; border: 1px solid black; border-spacing: 0">
|
|
287
|
+
<tr>
|
|
288
|
+
<th style="border: 2px solid black">File name</th>
|
|
289
|
+
<th style="border: 2px solid black">Uploaded at</th>
|
|
290
|
+
</tr>
|
|
291
|
+
${tableRows}
|
|
292
|
+
</table>`;
|
|
293
|
+
}, '');
|
|
294
|
+
const financialSettings = await FinancialCompliance_model_1.default.findOne({});
|
|
295
|
+
const financialEmails = financialSettings.financialEmails
|
|
296
|
+
.reduce((acc, email) => email.isActive ? [...acc, email.email] : acc, []);
|
|
297
|
+
const replacedData = data
|
|
298
|
+
.replace('${borrowerTables}', borrowerTables)
|
|
299
|
+
.replace('${signature}', signature);
|
|
300
|
+
try {
|
|
301
|
+
this.transporter.sendMail({
|
|
302
|
+
from: this.getSender(ESenderType.REGULAR),
|
|
303
|
+
to: financialEmails,
|
|
304
|
+
bcc: [],
|
|
305
|
+
subject: `${this.config.appTitle} / Daily uploads`,
|
|
306
|
+
text: 'non-html',
|
|
307
|
+
html: replacedData,
|
|
308
|
+
}, async (err, info) => {
|
|
309
|
+
await this.senderHandler(err, info);
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
catch (e) {
|
|
313
|
+
this.sentryService.catchErrorBySentry(null, e);
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
async sendSimpleNotificationMail(email) {
|
|
318
|
+
this.transporter.sendMail({
|
|
319
|
+
from: this.getSender(ESenderType.REGULAR),
|
|
320
|
+
to: email.addresses,
|
|
321
|
+
bcc: this.config.hiddenRecipient,
|
|
322
|
+
subject: email.subject,
|
|
323
|
+
text: email.text,
|
|
324
|
+
html: `<b>${email.text}</b>`,
|
|
325
|
+
}, async (err, info) => {
|
|
326
|
+
await this.senderHandler(err, info);
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
async sendFinancialExternal(email, organizationId, stopFunding = false) {
|
|
330
|
+
const organization = await Organization_model_1.Organization.findById(organizationId).lean();
|
|
331
|
+
const senderEmail = await this.organizationEmailsService.getEmail(organizationId, OrganizationEmails_model_1.OrganizationEmailsType.SENDER);
|
|
332
|
+
const financialEmail = await this.organizationEmailsService.getEmail(organizationId, OrganizationEmails_model_1.OrganizationEmailsType.FINANCIAL);
|
|
333
|
+
fs.readFile(path_1.default.resolve(__dirname, '../public/emails', organization.subfolder, stopFunding ? 'financial-external-on-stop.html' : 'financial-external-until-stop_date.html'), 'utf8', async (error, data) => {
|
|
334
|
+
if (error) {
|
|
335
|
+
console.error({ error });
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
const financialSettings = await this.financialComplianceService.getFinancialComplianceSettings();
|
|
339
|
+
const financialEmails = financialSettings.financialEmails
|
|
340
|
+
.reduce((acc, email) => email.isActive ? [...acc, email.email] : acc, []);
|
|
341
|
+
const signature = await this.getSignatureAsync(ESenderType.FINANCIAL, organization.subfolder);
|
|
342
|
+
const borrower = email.customData;
|
|
343
|
+
const replyText = `I confirm that we have sufficient availability and request to add the statement balance of ${new Intl.NumberFormat('us-US').format(borrower.balanceOutstanding)} to the loan.`;
|
|
344
|
+
const mailTo = [senderEmail.address, financialEmail.address];
|
|
345
|
+
const replyLink = `<a href="mailto:${mailTo.join(',')}?subject=Re:%20Email%20Answer&body=${replyText.replace(' ', '%20')}">by reply to this email</a>`;
|
|
346
|
+
const replacedData = data
|
|
347
|
+
.replaceAll('${BORROWER_NAME}', borrower.borrower.title)
|
|
348
|
+
.replaceAll('${REMINDER_COUNTER}', (borrower.reminderCounter + 1).toString())
|
|
349
|
+
.replaceAll('${ORIGINAL_BALANCE}', new Intl.NumberFormat('us-US').format(borrower.amountOwed))
|
|
350
|
+
.replaceAll('${AMOUNT_OUTSTANDING}', new Intl.NumberFormat('us-US').format(borrower.balanceOutstanding))
|
|
351
|
+
.replaceAll('${DUE_DATE}', (0, dayjs_1.default)(borrower.dueDate).format('M/D/YYYY'))
|
|
352
|
+
.replaceAll('${REPLY_LINK}', replyLink)
|
|
353
|
+
.replaceAll('${signature}', signature);
|
|
354
|
+
return this.transporter.sendMail({
|
|
355
|
+
from: `${senderEmail.title} <${senderEmail.address}>`,
|
|
356
|
+
to: email.addresses,
|
|
357
|
+
bcc: financialEmails,
|
|
358
|
+
subject: email.subject,
|
|
359
|
+
text: 'non-html',
|
|
360
|
+
html: replacedData,
|
|
361
|
+
}, async (err, info) => {
|
|
362
|
+
await this.senderHandler(err, info);
|
|
363
|
+
await this.financialComplianceService.updateLastReminder(String(borrower._id));
|
|
364
|
+
});
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
async sendFinancialInternal(email, stopFunding = false) {
|
|
368
|
+
fs.readFile(path_1.default.resolve(__dirname, '../public/emails', 'financial-internal.html'), 'utf8', async (error, data) => {
|
|
369
|
+
if (error) {
|
|
370
|
+
console.error({ error });
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
const signature = await this.getSignatureAsync(ESenderType.FINANCIAL);
|
|
374
|
+
const text = stopFunding
|
|
375
|
+
? `<p style="color: #ff0000;"><b>The table below sets out the status of borrowers who have failed to paid their interest statement.</b></p>`
|
|
376
|
+
: `<p><b>The following Borrowers have not paid in, or requested to add their statement to the loan:</b></p>`;
|
|
377
|
+
const borrowerTables = email.borrowers.reduce((allBorrowers, borrower) => {
|
|
378
|
+
return `
|
|
379
|
+
${allBorrowers}
|
|
380
|
+
<tr>
|
|
381
|
+
<td style="border: 1px solid black; text-align: center">${borrower.borrower.name}</td>
|
|
382
|
+
<td style="border: 1px solid black; text-align: right">${new Intl.NumberFormat('us-US').format(borrower.amountOwed)}</td>
|
|
383
|
+
<td style="border: 1px solid black; text-align: right">${new Intl.NumberFormat('us-US').format(borrower.amountReceived)}</td>
|
|
384
|
+
<td style="border: 1px solid black; text-align: right">${new Intl.NumberFormat('us-US').format(borrower.balanceOutstanding)}</td>
|
|
385
|
+
<td style="border: 1px solid black; text-align: center">${(0, dayjs_1.default)(new Date(borrower.lastReminderSentAt)).format('M/D/YYYY')}</td>
|
|
386
|
+
</tr>`;
|
|
387
|
+
}, '');
|
|
388
|
+
const borrowersTable = `
|
|
389
|
+
<br>
|
|
390
|
+
<table style="width:100%; border: 1px solid black; border-spacing: 0">
|
|
391
|
+
<tr>
|
|
392
|
+
<th style="border: 2px solid black; text-align: center">Borrower Name</th>
|
|
393
|
+
<th style="border: 2px solid black; text-align: right">Original Amount</th>
|
|
394
|
+
<th style="border: 2px solid black; text-align: right">Amount Paid</th>
|
|
395
|
+
<th style="border: 2px solid black; text-align: right">Amount Due</th>
|
|
396
|
+
<th style="border: 2px solid black; text-align: center">Last notification</th>
|
|
397
|
+
</tr>
|
|
398
|
+
${borrowerTables}
|
|
399
|
+
</table>`;
|
|
400
|
+
const replacedData = data
|
|
401
|
+
.replace('${text}', text)
|
|
402
|
+
.replace('${borrowerTable}', borrowersTable)
|
|
403
|
+
.replace('${signature}', signature);
|
|
404
|
+
try {
|
|
405
|
+
this.transporter.sendMail({
|
|
406
|
+
from: this.getSender(ESenderType.FINANCIAL),
|
|
407
|
+
to: email.addresses,
|
|
408
|
+
bcc: this.config.hiddenRecipient,
|
|
409
|
+
subject: email.subject,
|
|
410
|
+
text: 'non-html',
|
|
411
|
+
html: replacedData,
|
|
412
|
+
}, async (err, info) => {
|
|
413
|
+
await this.senderHandler(err, info);
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
catch (e) {
|
|
417
|
+
this.sentryService.catchErrorBySentry(null, e);
|
|
418
|
+
}
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
async getEmailStatementParams(borrowerId) {
|
|
422
|
+
const financialSettings = await this.financialComplianceService.getFinancialComplianceSettings();
|
|
423
|
+
const financialEmails = financialSettings.financialEmails
|
|
424
|
+
.reduce((acc, email) => email.isActive ? [...acc, email.email] : acc, []);
|
|
425
|
+
const borrower = await this.borrowerService.getBorrowerById(borrowerId);
|
|
426
|
+
const organization = await this.organizationsService.getOrganizationForBorrower(borrowerId);
|
|
427
|
+
const products = await this.loanChargesService.getLoanProducts(borrower._id.toString());
|
|
428
|
+
const borrowerHasRevolver = products.filter((product) => product.type === loan_types_enum_1.ELoanTypes.REVOLVER && product.active).length > 0;
|
|
429
|
+
const textPath = path_1.default.resolve(__dirname, '../public/emails', organization.subfolder, borrowerHasRevolver ? 'interest-statement.html' : 'interest-statement-only-term.html');
|
|
430
|
+
const text = await fs.promises.readFile(textPath, 'utf8');
|
|
431
|
+
const signature = await this.getSignatureAsync(ESenderType.FINANCIAL, organization.subfolder);
|
|
432
|
+
const borrowerRepresentation = borrower
|
|
433
|
+
? borrower.title
|
|
434
|
+
: borrower.code;
|
|
435
|
+
const complianceBorrowersService = this.getComplianceBorrowersService();
|
|
436
|
+
const borrowerEmails = await complianceBorrowersService.getBorrowerEmailsGrouped(String(borrower._id));
|
|
437
|
+
const mappedEmails = [
|
|
438
|
+
...borrowerEmails.mainEmails.map((email) => email.email),
|
|
439
|
+
...borrowerEmails.financialEmails.map((email) => email.email),
|
|
440
|
+
];
|
|
441
|
+
const replacedText = text
|
|
442
|
+
.replaceAll('${BORROWER_NAME}', borrowerRepresentation)
|
|
443
|
+
.replaceAll('${MONTH}', (0, dayjs_1.default)().subtract(1, 'month').format('MMMM'))
|
|
444
|
+
.replaceAll('${signature}', signature);
|
|
445
|
+
return { financialEmails, mappedEmails, replacedText };
|
|
446
|
+
}
|
|
447
|
+
async sendEmailWithAttach(borrowerCode, files) {
|
|
448
|
+
try {
|
|
449
|
+
const attachments = files.map((file) => ({
|
|
450
|
+
filename: file.originalname,
|
|
451
|
+
path: path_1.default.resolve(__dirname, '../uploads', file.filename),
|
|
452
|
+
}));
|
|
453
|
+
const { financialEmails, mappedEmails, replacedText } = await this.getEmailStatementParams(borrowerCode);
|
|
454
|
+
this.transporter.sendMail({
|
|
455
|
+
from: this.getSender(ESenderType.FINANCIAL),
|
|
456
|
+
to: mappedEmails,
|
|
457
|
+
bcc: financialEmails,
|
|
458
|
+
subject: `${borrowerCode} INTEREST STATEMENT`,
|
|
459
|
+
text: 'non-html',
|
|
460
|
+
html: replacedText,
|
|
461
|
+
attachments,
|
|
462
|
+
}, async (err, info) => {
|
|
463
|
+
await this.senderHandler(err, info);
|
|
464
|
+
await Promise.all(attachments.map(async (file) => {
|
|
465
|
+
fs.unlink(file.path, (err) => {
|
|
466
|
+
if (err) {
|
|
467
|
+
console.error(err);
|
|
468
|
+
}
|
|
469
|
+
else {
|
|
470
|
+
console.log('deleted');
|
|
471
|
+
}
|
|
472
|
+
});
|
|
473
|
+
}));
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
catch (e) {
|
|
477
|
+
this.sentryService.catchErrorBySentry(null, e);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
async sendEmailWithStatement(borrowerId, statement) {
|
|
481
|
+
try {
|
|
482
|
+
const borrower = await this.borrowerService.getBorrowerById(borrowerId);
|
|
483
|
+
if (!borrower) {
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
const organization = await this.organizationsService.getOrganizationForBorrower(borrowerId);
|
|
487
|
+
const sender = await this.organizationEmailsService.getEmail(organization._id.toString(), OrganizationEmails_model_1.OrganizationEmailsType.FINANCIAL);
|
|
488
|
+
const attachments = [statement];
|
|
489
|
+
const { financialEmails, mappedEmails, replacedText } = await this.getEmailStatementParams(borrowerId);
|
|
490
|
+
this.transporter.sendMail({
|
|
491
|
+
from: `${sender.title} <${sender.address}>`,
|
|
492
|
+
to: mappedEmails,
|
|
493
|
+
bcc: financialEmails,
|
|
494
|
+
subject: `${borrower.code} INTEREST STATEMENT`,
|
|
495
|
+
text: 'non-html',
|
|
496
|
+
html: replacedText,
|
|
497
|
+
attachments,
|
|
498
|
+
}, async (err, info) => {
|
|
499
|
+
await this.senderHandler(err, info);
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
catch (e) {
|
|
503
|
+
this.sentryService.catchErrorBySentry(null, e);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
async sendEmailWithSimpleAttachments(email, attachments) {
|
|
507
|
+
const textPath = path_1.default.resolve(__dirname, '../public/emails', 'simple-mail.html');
|
|
508
|
+
const text = await fs.promises.readFile(textPath, 'utf8');
|
|
509
|
+
const signature = await this.getSignatureAsync(ESenderType.GOAT);
|
|
510
|
+
const replacedData = text
|
|
511
|
+
.replace('${emailText}', '<p>Here’s your file:</p>')
|
|
512
|
+
.replace('${signature}', signature);
|
|
513
|
+
try {
|
|
514
|
+
this.transporter.sendMail({
|
|
515
|
+
from: this.getSender(ESenderType.REGULAR),
|
|
516
|
+
to: email.addresses,
|
|
517
|
+
bcc: this.config.hiddenRecipient,
|
|
518
|
+
subject: email.subject,
|
|
519
|
+
text: email.subject,
|
|
520
|
+
html: replacedData,
|
|
521
|
+
attachments,
|
|
522
|
+
}, async (err, info) => {
|
|
523
|
+
await this.senderHandler(err, info);
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
catch (e) {
|
|
527
|
+
this.sentryService.catchErrorBySentry(null, e);
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
async sendLoanUploadReport(email, attachments, borrowerId) {
|
|
531
|
+
const organization = await this.organizationsService.getOrganizationForBorrower(borrowerId);
|
|
532
|
+
const textPath = path_1.default.resolve(__dirname, '../public/emails', organization.subfolder, 'loan-upload.html');
|
|
533
|
+
const text = await fs.promises.readFile(textPath, 'utf8');
|
|
534
|
+
const signature = await this.getSignatureAsync(ESenderType.GOAT, organization.subfolder);
|
|
535
|
+
const senderEmail = await this.organizationEmailsService.getEmail(organization._id.toString(), OrganizationEmails_model_1.OrganizationEmailsType.FINANCIAL);
|
|
536
|
+
const replacedData = text
|
|
537
|
+
.replace('${emailText}', `<p>${email.text}</p>`)
|
|
538
|
+
.replace('${signature}', signature);
|
|
539
|
+
try {
|
|
540
|
+
this.transporter.sendMail({
|
|
541
|
+
from: `${senderEmail.title} <${senderEmail.address}>`,
|
|
542
|
+
to: email.addresses,
|
|
543
|
+
subject: email.subject,
|
|
544
|
+
cc: `${senderEmail.title} <${senderEmail.address}>`,
|
|
545
|
+
text: email.subject,
|
|
546
|
+
html: replacedData,
|
|
547
|
+
attachments,
|
|
548
|
+
}, async (err, info) => {
|
|
549
|
+
await this.senderHandler(err, info);
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
catch (e) {
|
|
553
|
+
this.sentryService.catchErrorBySentry(null, e);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
async sendPlaidReminder(email) {
|
|
557
|
+
const textPath = path_1.default.resolve(__dirname, '../public/emails', 'plaid-reminder.html');
|
|
558
|
+
const text = await fs.promises.readFile(textPath, 'utf8');
|
|
559
|
+
const signature = await this.getSignatureAsync(ESenderType.FINANCIAL);
|
|
560
|
+
const replacedData = text
|
|
561
|
+
.replace('${signature}', signature);
|
|
562
|
+
try {
|
|
563
|
+
this.transporter.sendMail({
|
|
564
|
+
from: this.getSender(ESenderType.REGULAR),
|
|
565
|
+
to: email.addresses,
|
|
566
|
+
subject: `🔴 ${email.subject}`,
|
|
567
|
+
cc: this.getSender(ESenderType.REGULAR),
|
|
568
|
+
text: email.subject,
|
|
569
|
+
html: replacedData,
|
|
570
|
+
headers: {
|
|
571
|
+
'priority': 'high',
|
|
572
|
+
},
|
|
573
|
+
attachments: [{
|
|
574
|
+
filename: 'plaid-reminder-instruction.png',
|
|
575
|
+
path: process.cwd() + '/public/images/plaid-reminder-instruction.png',
|
|
576
|
+
cid: 'plaid-instruction',
|
|
577
|
+
}],
|
|
578
|
+
}, async (err, info) => {
|
|
579
|
+
await this.senderHandler(err, info);
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
|
+
catch (e) {
|
|
583
|
+
this.sentryService.catchErrorBySentry(null, e);
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
async sendEmailFTP(email, attachments, success) {
|
|
587
|
+
const textPath = path_1.default.resolve(__dirname, '../public/emails', 'simple-mail.html');
|
|
588
|
+
const text = await fs.promises.readFile(textPath, 'utf8');
|
|
589
|
+
const signature = await this.getSignatureAsync(ESenderType.GOAT);
|
|
590
|
+
const emailText = success ? 'the attached file was uploaded to the FTP site' : 'the attached file was NOT uploaded to the FTP site';
|
|
591
|
+
const replacedData = text
|
|
592
|
+
.replace('${emailText}', `<p>${emailText}</p>`)
|
|
593
|
+
.replace('${signature}', signature);
|
|
594
|
+
try {
|
|
595
|
+
this.transporter.sendMail({
|
|
596
|
+
from: this.getSender(ESenderType.FINANCIAL),
|
|
597
|
+
to: this.config.hiddenRecipient,
|
|
598
|
+
subject: email.subject,
|
|
599
|
+
text: emailText,
|
|
600
|
+
html: replacedData,
|
|
601
|
+
attachments,
|
|
602
|
+
}, async (err, info) => {
|
|
603
|
+
await this.senderHandler(err, info);
|
|
604
|
+
});
|
|
605
|
+
}
|
|
606
|
+
catch (e) {
|
|
607
|
+
this.sentryService.catchErrorBySentry(null, e);
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
async sendBrokerEmail(email, attachments, replacements) {
|
|
611
|
+
const textPath = path_1.default.resolve(__dirname, '../public/emails', 'broker-report.html');
|
|
612
|
+
const text = await fs.promises.readFile(textPath, 'utf8');
|
|
613
|
+
const signature = await this.getSignatureAsync(ESenderType.FINANCIAL_ONLY);
|
|
614
|
+
const replacedData = text
|
|
615
|
+
.replace('${BORROWER_NAME}', replacements.broker)
|
|
616
|
+
.replace('${MONTH}', replacements.month)
|
|
617
|
+
.replace('${signature}', signature);
|
|
618
|
+
try {
|
|
619
|
+
this.transporter.sendMail({
|
|
620
|
+
from: this.getSender(ESenderType.FINANCIAL),
|
|
621
|
+
to: [...this.config.hiddenRecipient, ...email.addresses],
|
|
622
|
+
cc: this.getSender(ESenderType.FINANCIAL),
|
|
623
|
+
subject: email.subject,
|
|
624
|
+
text: replacedData,
|
|
625
|
+
html: replacedData,
|
|
626
|
+
attachments,
|
|
627
|
+
}, async (err, info) => {
|
|
628
|
+
await this.senderHandler(err, info);
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
catch (e) {
|
|
632
|
+
this.sentryService.catchErrorBySentry(null, e);
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
async sendProspectForm(email, replacements) {
|
|
636
|
+
const textPath = path_1.default.resolve(__dirname, '../public/emails', 'prospect-form.html');
|
|
637
|
+
const text = await fs.promises.readFile(textPath, 'utf8');
|
|
638
|
+
const signature = await this.getSignatureAsync(ESenderType.FINANCIAL_ONLY);
|
|
639
|
+
const replacedData = text
|
|
640
|
+
.replaceAll('${LINK}', replacements.link)
|
|
641
|
+
.replaceAll('${CONTACT_NAME}', replacements.contactName)
|
|
642
|
+
.replace('${signature}', signature);
|
|
643
|
+
try {
|
|
644
|
+
this.transporter.sendMail({
|
|
645
|
+
from: this.getSender(ESenderType.FINANCIAL),
|
|
646
|
+
to: [...this.config.hiddenRecipient, ...email.addresses],
|
|
647
|
+
cc: this.getSender(ESenderType.FINANCIAL),
|
|
648
|
+
subject: email.subject,
|
|
649
|
+
text: replacedData,
|
|
650
|
+
html: replacedData,
|
|
651
|
+
}, async (err, info) => {
|
|
652
|
+
await this.senderHandler(err, info);
|
|
653
|
+
});
|
|
654
|
+
}
|
|
655
|
+
catch (e) {
|
|
656
|
+
this.sentryService.catchErrorBySentry(null, e);
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
async sendProspectReminder(email, replacements) {
|
|
660
|
+
const textPath = path_1.default.resolve(__dirname, '../public/emails', 'prospect-form-reminder.html');
|
|
661
|
+
const text = await fs.promises.readFile(textPath, 'utf8');
|
|
662
|
+
const signature = await this.getSignatureAsync(ESenderType.FINANCIAL_ONLY);
|
|
663
|
+
const fileInfo = replacements.requiredGroups.length > 0
|
|
664
|
+
? ` and upload missing documents under the following sections: ${replacements.requiredGroups.join(', ')}`
|
|
665
|
+
: '';
|
|
666
|
+
const replacedData = text
|
|
667
|
+
.replaceAll('${LINK}', replacements.link)
|
|
668
|
+
.replaceAll('${CONTACT_NAME}', replacements.contactName)
|
|
669
|
+
.replace('${HAS_EMPTY_FIELDS}', replacements.hasEmptyFields ? ' and complete all sections of the form' : '')
|
|
670
|
+
.replace('${FILE_INFO}', fileInfo)
|
|
671
|
+
.replace('${signature}', signature);
|
|
672
|
+
try {
|
|
673
|
+
this.transporter.sendMail({
|
|
674
|
+
from: this.getSender(ESenderType.FINANCIAL),
|
|
675
|
+
to: [...this.config.hiddenRecipient, ...email.addresses],
|
|
676
|
+
cc: this.getSender(ESenderType.FINANCIAL),
|
|
677
|
+
subject: email.subject,
|
|
678
|
+
text: replacedData,
|
|
679
|
+
html: replacedData,
|
|
680
|
+
}, async (err, info) => {
|
|
681
|
+
await this.senderHandler(err, info);
|
|
682
|
+
});
|
|
683
|
+
}
|
|
684
|
+
catch (e) {
|
|
685
|
+
this.sentryService.catchErrorBySentry(null, e);
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
exports.NodemailerService = NodemailerService;
|