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.
Files changed (303) hide show
  1. package/classes/bank-transaction-item.d.ts +17 -0
  2. package/classes/bank-transaction-item.js +64 -0
  3. package/classes/bank-transaction-item.ts +66 -0
  4. package/classes/bank-uploaded-transaction.d.ts +17 -0
  5. package/classes/bank-uploaded-transaction.js +35 -0
  6. package/classes/bank-uploaded-transaction.ts +35 -0
  7. package/classes/inventory-item.d.ts +41 -0
  8. package/classes/inventory-item.js +44 -0
  9. package/classes/inventory-item.ts +63 -0
  10. package/classes/payable-account-item.d.ts +22 -0
  11. package/classes/payable-account-item.js +27 -0
  12. package/classes/payable-account-item.ts +35 -0
  13. package/classes/quickbook-item.d.ts +37 -0
  14. package/classes/quickbook-item.js +51 -0
  15. package/classes/quickbook-item.ts +59 -0
  16. package/classes/receivable-item.d.ts +26 -0
  17. package/classes/receivable-item.js +28 -0
  18. package/classes/receivable-item.ts +38 -0
  19. package/constants/date-formats.contsants.d.ts +1 -0
  20. package/constants/date-formats.contsants.js +4 -0
  21. package/constants/date-formats.contsants.ts +1 -0
  22. package/db/brokers.db.d.ts +185 -0
  23. package/db/brokers.db.js +35 -2
  24. package/db/brokers.db.ts +34 -1
  25. package/db/collateral-adjustments.db.d.ts +34 -0
  26. package/db/collateral-adjustments.db.js +52 -0
  27. package/db/collateral-adjustments.db.ts +54 -0
  28. package/db/collaterals.db.d.ts +1 -1
  29. package/db/equipment.db.d.ts +40 -0
  30. package/db/equipment.db.js +55 -0
  31. package/db/equipment.db.ts +56 -0
  32. package/db/financial-spreading.db.ts +2 -1
  33. package/db/groups.d.ts +5 -0
  34. package/db/groups.js +57 -0
  35. package/db/groups.ts +52 -0
  36. package/db/inventories.d.ts +91 -0
  37. package/db/inventories.js +449 -0
  38. package/db/inventories.ts +481 -0
  39. package/db/inventory-availability.d.ts +3 -0
  40. package/db/inventory-availability.js +103 -0
  41. package/db/inventory-availability.ts +113 -0
  42. package/db/new-summary.d.ts +31 -0
  43. package/db/new-summary.js +1295 -0
  44. package/db/new-summary.ts +1509 -0
  45. package/db/payable-accounts.d.ts +30 -0
  46. package/db/payable-accounts.js +55 -0
  47. package/db/payable-accounts.ts +50 -0
  48. package/db/reserve.db.d.ts +34 -0
  49. package/db/reserve.db.js +52 -0
  50. package/db/reserve.db.ts +48 -0
  51. package/db/uploads.db.d.ts +2 -0
  52. package/db/uploads.db.js +29 -0
  53. package/db/uploads.db.ts +24 -0
  54. package/helpers/main.helper.d.ts +31 -0
  55. package/helpers/main.helper.js +63 -0
  56. package/helpers/main.helper.ts +63 -0
  57. package/models/AccountPayableItem.model.d.ts +6 -6
  58. package/models/AllocatedBankTransaction.model.d.ts +54 -0
  59. package/models/AllocatedBankTransaction.model.js +70 -0
  60. package/models/AllocatedBankTransaction.model.ts +94 -0
  61. package/models/AllocatedData.model.d.ts +33 -0
  62. package/models/AllocatedData.model.js +19 -0
  63. package/models/AllocatedData.model.ts +24 -0
  64. package/models/BBCDate.model.d.ts +3 -3
  65. package/models/BBCSheet.model.d.ts +3 -3
  66. package/models/Banks.model.d.ts +3 -3
  67. package/models/Borrower.model.d.ts +3 -3
  68. package/models/BorrowerData.model.d.ts +3 -3
  69. package/models/BorrowerDataInsurance.model.d.ts +3 -3
  70. package/models/BorrowerDataTerm.model.d.ts +3 -3
  71. package/models/BorrowerSummary.model.js +1 -1
  72. package/models/BorrowerSummary.model.ts +1 -1
  73. package/models/CalandarDay.model.d.ts +40 -0
  74. package/models/CalandarDay.model.js +47 -0
  75. package/models/CalandarDay.model.ts +61 -0
  76. package/models/CashAllocationProduct.model.d.ts +119 -0
  77. package/models/CashAllocationProduct.model.js +102 -0
  78. package/models/CashAllocationProduct.model.ts +112 -0
  79. package/models/CashAllocationReference.model.d.ts +37 -0
  80. package/models/CashAllocationReference.model.js +27 -0
  81. package/models/CashAllocationReference.model.ts +40 -0
  82. package/models/CollateralAdjustment.model.d.ts +51 -0
  83. package/models/CollateralAdjustment.model.js +61 -0
  84. package/models/CollateralAdjustment.model.ts +98 -0
  85. package/models/Company.model.d.ts +35 -0
  86. package/models/Company.model.js +18 -0
  87. package/models/Company.model.ts +29 -0
  88. package/models/CustomerAPGroup.model.d.ts +32 -0
  89. package/models/CustomerAPGroup.model.js +24 -0
  90. package/models/CustomerAPGroup.model.ts +31 -0
  91. package/models/Equipment.model.d.ts +53 -0
  92. package/models/Equipment.model.js +140 -0
  93. package/models/Equipment.model.ts +172 -0
  94. package/models/FinancialCompliance.model.d.ts +39 -0
  95. package/models/FinancialCompliance.model.js +64 -0
  96. package/models/FinancialCompliance.model.ts +78 -0
  97. package/models/FinancialComplianceBorrower.model.d.ts +58 -0
  98. package/models/FinancialComplianceBorrower.model.js +82 -0
  99. package/models/FinancialComplianceBorrower.model.ts +118 -0
  100. package/models/FinancialIndexes.model.d.ts +36 -0
  101. package/models/FinancialIndexes.model.js +27 -0
  102. package/models/FinancialIndexes.model.ts +37 -0
  103. package/models/Inventory.model.d.ts +18 -18
  104. package/models/InventoryAvailability.model.d.ts +21 -21
  105. package/models/InventoryAvailabilityItem.model.d.ts +6 -6
  106. package/models/InventoryItem.model.d.ts +24 -24
  107. package/models/InventoryManualEntry.model.d.ts +9 -9
  108. package/models/InventorySeasonalRates.model.d.ts +3 -3
  109. package/models/LoanBroker.model.d.ts +3 -3
  110. package/models/LoanCharges.model.d.ts +12 -12
  111. package/models/LoanProducts.model.d.ts +9 -9
  112. package/models/LoanStatementStatus.model.d.ts +35 -0
  113. package/models/LoanStatementStatus.model.js +34 -0
  114. package/models/LoanStatementStatus.model.ts +45 -0
  115. package/models/LoanStatementTransaction.model.d.ts +9 -9
  116. package/models/LoanTransactionFile.model.d.ts +41 -0
  117. package/models/LoanTransactionFile.model.js +44 -0
  118. package/models/LoanTransactionFile.model.ts +61 -0
  119. package/models/MappedGroup.model.d.ts +37 -0
  120. package/models/MappedGroup.model.js +33 -0
  121. package/models/MappedGroup.model.ts +46 -0
  122. package/models/MonthEndData.Model.d.ts +41 -0
  123. package/models/MonthEndData.Model.js +42 -0
  124. package/models/MonthEndData.Model.ts +53 -0
  125. package/models/OrganizationEmails.model.d.ts +44 -0
  126. package/models/OrganizationEmails.model.js +40 -0
  127. package/models/OrganizationEmails.model.ts +54 -0
  128. package/models/ProductBroker.model.d.ts +9 -9
  129. package/models/QuickbooksAccount.model.d.ts +39 -0
  130. package/models/QuickbooksAccount.model.js +43 -0
  131. package/models/QuickbooksAccount.model.ts +57 -0
  132. package/models/Receivable.model.d.ts +12 -12
  133. package/models/ReceivableAvailability.model.d.ts +54 -54
  134. package/models/ReceivableAvailabilityItem.model.d.ts +57 -57
  135. package/models/ReceivableItem.model.d.ts +6 -6
  136. package/models/Reserve.model.d.ts +51 -0
  137. package/models/Reserve.model.js +96 -0
  138. package/models/Reserve.model.ts +125 -0
  139. package/models/TermLoan.model.d.ts +3 -3
  140. package/models/TermLoanCalculated.model.d.ts +6 -6
  141. package/models/TransactionAttachedFile.Model.d.ts +35 -0
  142. package/models/TransactionAttachedFile.Model.js +37 -0
  143. package/models/TransactionAttachedFile.Model.ts +48 -0
  144. package/models/UploadedBankTransaction.model.d.ts +56 -0
  145. package/models/UploadedBankTransaction.model.js +78 -0
  146. package/models/UploadedBankTransaction.model.ts +110 -0
  147. package/models/UploadedData.model.d.ts +36 -0
  148. package/models/UploadedData.model.js +23 -0
  149. package/models/UploadedData.model.ts +35 -0
  150. package/models/UploadedFile.model.d.ts +40 -0
  151. package/models/UploadedFile.model.js +41 -0
  152. package/models/UploadedFile.model.ts +57 -0
  153. package/models/UploadedSheet.model.d.ts +46 -0
  154. package/models/UploadedSheet.model.js +27 -0
  155. package/models/UploadedSheet.model.ts +51 -0
  156. package/package.json +10 -1
  157. package/repositories/globals.repository.d.ts +8 -0
  158. package/repositories/globals.repository.js +24 -0
  159. package/repositories/globals.repository.ts +21 -0
  160. package/services/attached-files.service.d.ts +57 -0
  161. package/services/attached-files.service.js +103 -0
  162. package/services/attached-files.service.ts +123 -0
  163. package/services/availability.service.d.ts +77 -0
  164. package/services/availability.service.js +897 -0
  165. package/services/availability.service.ts +1034 -0
  166. package/services/bank-uploaded-transactions.service.d.ts +33 -0
  167. package/services/bank-uploaded-transactions.service.js +430 -0
  168. package/services/bank-uploaded-transactions.service.ts +475 -0
  169. package/services/banks.service.d.ts +36 -0
  170. package/services/banks.service.js +91 -0
  171. package/services/banks.service.ts +95 -0
  172. package/services/borrower-summary.service.d.ts +35 -0
  173. package/services/borrower-summary.service.js +310 -0
  174. package/services/borrower-summary.service.ts +334 -0
  175. package/services/borrowers.service.d.ts +103 -0
  176. package/services/borrowers.service.js +268 -0
  177. package/services/borrowers.service.ts +302 -0
  178. package/services/brokers.service.d.ts +212 -0
  179. package/services/brokers.service.js +160 -0
  180. package/services/brokers.service.ts +200 -0
  181. package/services/calendar.service.d.ts +53 -0
  182. package/services/calendar.service.js +108 -0
  183. package/services/calendar.service.ts +128 -0
  184. package/services/cash-allocation.service.d.ts +40 -0
  185. package/services/cash-allocation.service.js +92 -0
  186. package/services/cash-allocation.service.ts +105 -0
  187. package/services/collateral-adjustments.service.d.ts +38 -0
  188. package/services/collateral-adjustments.service.js +82 -0
  189. package/services/collateral-adjustments.service.ts +95 -0
  190. package/services/collaterals.service.d.ts +69 -0
  191. package/services/collaterals.service.js +279 -0
  192. package/services/collaterals.service.ts +319 -0
  193. package/services/companies.service.d.ts +5 -0
  194. package/services/companies.service.js +21 -0
  195. package/services/companies.service.ts +23 -0
  196. package/services/compliance-borrowers.service.d.ts +152 -0
  197. package/services/compliance-borrowers.service.js +569 -0
  198. package/services/compliance-borrowers.service.ts +617 -0
  199. package/services/equipment.service.d.ts +42 -0
  200. package/services/equipment.service.js +120 -0
  201. package/services/equipment.service.ts +149 -0
  202. package/services/file-manager.service.d.ts +44 -0
  203. package/services/file-manager.service.js +120 -0
  204. package/services/file-manager.service.ts +146 -0
  205. package/services/financial-compliance.service.d.ts +58 -0
  206. package/services/financial-compliance.service.js +281 -0
  207. package/services/financial-compliance.service.ts +309 -0
  208. package/services/financial-indexes.service.d.ts +20 -0
  209. package/services/financial-indexes.service.js +241 -0
  210. package/services/financial-indexes.service.ts +257 -0
  211. package/services/financial-spreading.service.d.ts +74 -0
  212. package/services/financial-spreading.service.js +450 -0
  213. package/services/financial-spreading.service.ts +517 -0
  214. package/services/globals.service.d.ts +5 -0
  215. package/services/globals.service.js +11 -0
  216. package/services/globals.service.ts +8 -0
  217. package/services/groups.service.d.ts +39 -0
  218. package/services/groups.service.js +65 -0
  219. package/services/groups.service.ts +64 -0
  220. package/services/inventory-availability.service.d.ts +13 -0
  221. package/services/inventory-availability.service.js +170 -0
  222. package/services/inventory-availability.service.ts +187 -0
  223. package/services/inventory.service.d.ts +118 -0
  224. package/services/inventory.service.js +239 -0
  225. package/services/inventory.service.ts +276 -0
  226. package/services/loan-charges.service.d.ts +83 -0
  227. package/services/loan-charges.service.js +343 -0
  228. package/services/loan-charges.service.ts +396 -0
  229. package/services/loan-payments.service.d.ts +94 -0
  230. package/services/loan-payments.service.js +485 -0
  231. package/services/loan-payments.service.ts +541 -0
  232. package/services/loan-products.service.d.ts +12 -0
  233. package/services/loan-products.service.js +55 -0
  234. package/services/loan-products.service.ts +58 -0
  235. package/services/loan-statement-balance.service.d.ts +16 -0
  236. package/services/loan-statement-balance.service.js +106 -0
  237. package/services/loan-statement-balance.service.ts +113 -0
  238. package/services/loan-statement-effects.service.d.ts +8 -0
  239. package/services/loan-statement-effects.service.js +42 -0
  240. package/services/loan-statement-effects.service.ts +41 -0
  241. package/services/loan-statement-status.service.d.ts +208 -0
  242. package/services/loan-statement-status.service.js +159 -0
  243. package/services/loan-statement-status.service.ts +177 -0
  244. package/services/loan-statement.service.d.ts +186 -0
  245. package/services/loan-statement.service.js +935 -0
  246. package/services/loan-statement.service.ts +1040 -0
  247. package/services/loan-transactions.service.d.ts +169 -0
  248. package/services/loan-transactions.service.js +941 -0
  249. package/services/loan-transactions.service.ts +1042 -0
  250. package/services/lock.service.d.ts +6 -0
  251. package/services/lock.service.js +45 -0
  252. package/services/lock.service.ts +45 -0
  253. package/services/manual-entry.service.d.ts +20 -0
  254. package/services/manual-entry.service.js +186 -0
  255. package/services/manual-entry.service.ts +201 -0
  256. package/services/month-end-data.service.d.ts +34 -0
  257. package/services/month-end-data.service.js +30 -0
  258. package/services/month-end-data.service.ts +35 -0
  259. package/services/nodemailer.service.d.ts +96 -0
  260. package/services/nodemailer.service.js +689 -0
  261. package/services/nodemailer.service.ts +774 -0
  262. package/services/organization-emails.service.d.ts +31 -0
  263. package/services/organization-emails.service.js +10 -0
  264. package/services/organization-emails.service.ts +7 -0
  265. package/services/organizations.service.d.ts +34 -0
  266. package/services/organizations.service.js +74 -0
  267. package/services/organizations.service.ts +84 -0
  268. package/services/pdf.service.d.ts +61 -0
  269. package/services/pdf.service.js +547 -0
  270. package/services/pdf.service.ts +642 -0
  271. package/services/quickbooks.service.d.ts +99 -0
  272. package/services/quickbooks.service.js +640 -0
  273. package/services/quickbooks.service.ts +734 -0
  274. package/services/reports/investor-summary.service.d.ts +28 -0
  275. package/services/reports/investor-summary.service.js +136 -0
  276. package/services/reports/investor-summary.service.ts +159 -0
  277. package/services/reports.service.d.ts +126 -0
  278. package/services/reports.service.js +584 -0
  279. package/services/reports.service.ts +702 -0
  280. package/services/reserve.service.d.ts +37 -0
  281. package/services/reserve.service.js +76 -0
  282. package/services/reserve.service.ts +79 -0
  283. package/services/sentry.service.d.ts +11 -0
  284. package/services/sentry.service.js +49 -0
  285. package/services/sentry.service.ts +33 -0
  286. package/services/signs.service.d.ts +69 -0
  287. package/services/signs.service.js +230 -0
  288. package/services/signs.service.ts +260 -0
  289. package/services/term-loan.service.d.ts +30 -0
  290. package/services/term-loan.service.js +614 -0
  291. package/services/term-loan.service.ts +696 -0
  292. package/services/uploads.service.d.ts +134 -0
  293. package/services/uploads.service.js +587 -0
  294. package/services/uploads.service.ts +643 -0
  295. package/services/user-logs.service.d.ts +23 -0
  296. package/services/user-logs.service.js +160 -0
  297. package/services/user-logs.service.ts +177 -0
  298. package/services/users.service.d.ts +4 -4
  299. package/services/yield.service.d.ts +46 -0
  300. package/services/yield.service.js +42 -12
  301. package/services/yield.service.ts +38 -8
  302. package/tsconfig.json +5 -5
  303. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,617 @@
1
+ import dayjs, { ManipulateType } from 'dayjs';
2
+ import _ from 'lodash';
3
+ import mongoose from 'mongoose';
4
+
5
+ import { IBorrowerItemDocument, IEmailRecipient } from '../models/ComplianceItem.model';
6
+ import { IGroupedEmailsUpdate } from '../interfaces/email-addresses.interface';
7
+ import { EItemProgressStatus } from '../enums/item-progress-status.enum';
8
+ import {
9
+ BorrowerCompliance,
10
+ IComplianceBorrowerDocument,
11
+ IComplianceBorrowerDocumentFull,
12
+ } from '../models/BorrowerCompliance.model';
13
+ import { BorrowerModel } from '../models/Borrower.model';
14
+ import { IUser } from '../models/User.model';
15
+
16
+ import FinancialComplianceBorrower from '../models/FinancialComplianceBorrower.model';
17
+ import { FileManagerService } from './file-manager.service';
18
+ import { UploadsService } from './uploads.service';
19
+
20
+ type FrequencyType = { [key: string]: { value: number, unit: ManipulateType } };
21
+
22
+ const frequencies: FrequencyType = {
23
+ ONCE: { value: 1, unit: 'day' },
24
+ MONTHLY: { value: 1, unit: 'month' },
25
+ ANNUAL: { value: 1, unit: 'year' },
26
+ WEEKLY: { value: 1, unit: 'week' },
27
+ QUARTERLY: { value: 3, unit: 'month' },
28
+ TWICE_MONTHLY: { value: 15, unit: 'day' },
29
+ END_OF_MONTH: { value: 15, unit: 'day' },
30
+ };
31
+
32
+ const dueDifference = (date) => {
33
+ const currentDate = dayjs().startOf('day');
34
+ const nextDate = dayjs(new Date(date)).startOf('day');
35
+ return currentDate.diff(nextDate, 'day');
36
+ };
37
+
38
+ export class ComplianceBorrowersService {
39
+
40
+ constructor(
41
+ private readonly _fileManagerService: FileManagerService,
42
+ private readonly _uploadsService: UploadsService,
43
+ ) {
44
+ }
45
+
46
+ isComplianceBorrowerAllowed(userAccess, requestedBorrowerId): boolean {
47
+ const allowedBorrower = userAccess.complianceBorrowersAccess.some((b) => b.borrower === requestedBorrowerId);
48
+ if (!allowedBorrower) {
49
+ throw new Error('Non allowed compliance borrower');
50
+ }
51
+ return true;
52
+ }
53
+
54
+ calculateInstanceStatuses(instance, item) {
55
+ let progress: { text: string, status: string };
56
+ let score: { value: number, tooltip: string } = null;
57
+ if (instance.submittedDate) {
58
+ progress = { text: 'submitted', status: 'SUBMITTED' };
59
+ }
60
+ const diff = dueDifference(instance.nextDate);
61
+ if (diff !== 0) {
62
+ const progressText = `${diff > 0 ? 'overdue' : 'due'} ${Math.abs(diff)} ${Math.abs(diff) > 1 ? 'days' : 'day'}`;
63
+ progress = { text: progressText, status: diff > 0 ? EItemProgressStatus.OVERDUE : EItemProgressStatus.DUE };
64
+ }
65
+ if (diff > 0) {
66
+ score = {
67
+ value: item.item.importanceScore * item.item.multiplier * diff,
68
+ tooltip: `${item.item.importanceScore} (importance) x ${item.item.multiplier} (multiplier) x ${diff} (days)`,
69
+ };
70
+ }
71
+ if (instance.status === 'IN_REVIEW') {
72
+ progress = { text: 'in review', status: EItemProgressStatus.IN_REVIEW };
73
+ }
74
+ if (instance.status === 'ACCEPTED') {
75
+ progress = null;
76
+ }
77
+ return { progress, score };
78
+ }
79
+
80
+ async getFullComplianceBorrowerById(complianceBorrowerId): Promise<any> {
81
+ if (!complianceBorrowerId) {
82
+ return null;
83
+ }
84
+ const ourBorrower = await BorrowerCompliance
85
+ .findById(complianceBorrowerId)
86
+ .populate('borrower plaidAccessToken')
87
+ .populate({
88
+ path: 'items',
89
+ populate: { path: 'item', model: 'complianceItems' },
90
+ })
91
+ .populate({
92
+ path: 'items',
93
+ populate: { path: 'instances.files.uploadedBy', model: 'users' },
94
+ })
95
+ .transform((borrower) => ({ ...borrower, plaidAccessToken: borrower?.plaidAccessToken ?? false }))
96
+ .lean() as IComplianceBorrowerDocumentFull;
97
+ if (!ourBorrower.borrower) {
98
+ return Promise.resolve({ ...ourBorrower });
99
+ }
100
+ const financeBorrower = await FinancialComplianceBorrower.findOne({ borrower: ourBorrower.borrower?._id });
101
+ if (financeBorrower) {
102
+ const currentDate = dayjs();
103
+ const stopFundingDate = dayjs(financeBorrower.stopFundingDate);
104
+ if (financeBorrower.balanceOutstanding > 0 && currentDate.diff(stopFundingDate) > 0) {
105
+ ourBorrower.fundingStatus = 'NOT_PAID';
106
+ }
107
+ }
108
+ if (!ourBorrower) {
109
+ return Promise.resolve(null);
110
+ }
111
+
112
+ const items = { items: [], ...ourBorrower }.items.map((item) => {
113
+ return {
114
+ ...item,
115
+ instances: item.instances.reduce((acc, instance) => {
116
+ try {
117
+ const statuses = this.calculateInstanceStatuses(instance, item);
118
+ const files = instance.files.map((file) => {
119
+ const uploadedByUser = file.uploadedBy ? file.uploadedBy['firstName'] : null;
120
+ return { ...file, uploadedByUser };
121
+ });
122
+ return [...acc, { ...instance, ...statuses, itemId: item._id, files }];
123
+ } catch (e) {
124
+ console.error({ e });
125
+ return acc;
126
+ }
127
+ }, []),
128
+ };
129
+ });
130
+ return Promise.resolve({ ...ourBorrower, items });
131
+ }
132
+
133
+ async getAllBorrowersShortened(userAccess) {
134
+ type BorrowerComplianceShort = Pick<IComplianceBorrowerDocument, 'borrower' | 'fundingStatus' | 'items'>;
135
+
136
+ const allComplianceBorrower: BorrowerComplianceShort[] = await BorrowerCompliance
137
+ .find(userAccess.allBorrowers ? { isVisible: true } : {
138
+ 'borrower': { $in: userAccess.borrowersAccess.map((b) => b.borrower) },
139
+ isVisible: true,
140
+ })
141
+ .populate('borrower')
142
+ .populate({
143
+ path: 'items',
144
+ populate: { path: 'item', model: 'complianceItems' },
145
+ })
146
+ .collation({ locale: 'en' })
147
+ .lean();
148
+ const borrowers = await Promise.all(allComplianceBorrower.map(async (borrower) => {
149
+ if (!borrower.borrower) {
150
+ return borrower;
151
+ }
152
+ if (!borrower.borrower.active) {
153
+ return;
154
+ }
155
+ const financeBorrower = await FinancialComplianceBorrower.findOne({ borrower: borrower.borrower._id });
156
+ if (financeBorrower) {
157
+ const currentDate = dayjs();
158
+ const stopFundingDate = dayjs(financeBorrower.stopFundingDate);
159
+ if (financeBorrower.balanceOutstanding > 0 && currentDate.diff(stopFundingDate) > 0) {
160
+ borrower.fundingStatus = 'NOT_PAID';
161
+ }
162
+ }
163
+
164
+ const items = borrower.items.map((item) => {
165
+ return {
166
+ ...item,
167
+ instances: item.instances.reduce((acc, instance) => {
168
+ try {
169
+ const statuses = this.calculateInstanceStatuses(instance, item);
170
+ return [...acc, { ...instance, ...statuses }];
171
+ } catch (e) {
172
+ return acc;
173
+ }
174
+ }, []),
175
+ };
176
+ });
177
+
178
+ return { ...borrower, items };
179
+ }));
180
+ return borrowers
181
+ .filter((borrower) => !!borrower)
182
+ .sort((a, b) => a.borrower.code > b.borrower.code ? 1 : -1);
183
+ }
184
+
185
+ async generateInstances(complianceBorrowerId) {
186
+ const complianceBorrower = await this.getFullComplianceBorrowerById(complianceBorrowerId);
187
+
188
+ const getLatestInstanceDate = (item: IBorrowerItemDocument) => {
189
+ if (!item.instances || !item.instances.length) {
190
+ return null;
191
+ }
192
+
193
+ return item.instances
194
+ .reduce((a, b) => (new Date(a.nextDate).getTime() > new Date(b.nextDate).getTime() ? a : b))
195
+ .nextDate;
196
+ };
197
+
198
+ for (let [index, item] of complianceBorrower.items.entries()) {
199
+ const { frequency, startDate } = item;
200
+ if (frequency && startDate) {
201
+
202
+ const currentDatePlusNotification = dayjs(new Date())
203
+ .set('hour', 0)
204
+ .set('minute', 0)
205
+ .set('second', 0)
206
+ .add(item.item.notificationDays, 'day')
207
+ .toDate();
208
+
209
+ const emptyInstance = {
210
+ submittedDate: null,
211
+ status: 'NEW',
212
+ files: [],
213
+ };
214
+ let newInstance;
215
+ let newInstances;
216
+ let nextDate;
217
+ switch (frequency) {
218
+ case 'ONCE':
219
+ newInstance = { nextDate: dayjs(item.startDate).toDate(), ...emptyInstance };
220
+ if (!item.instances.length && currentDatePlusNotification >= newInstance.nextDate) {
221
+ await BorrowerCompliance.findByIdAndUpdate(complianceBorrowerId, { $push: { ['items.' + index + '.instances']: newInstance } });
222
+ }
223
+ break;
224
+ case 'END_OF_MONTH':
225
+ newInstances = [];
226
+ do {
227
+ const latestDate = newInstances.length ? newInstances[newInstances.length - 1].nextDate : getLatestInstanceDate(item);
228
+ let nextDateJs = !latestDate
229
+ ? dayjs(item.startDate)
230
+ : dayjs(latestDate)
231
+ .add(1, 'day');
232
+ nextDate = nextDateJs
233
+ .endOf('month')
234
+ .set('hour', 0)
235
+ .set('minute', 0)
236
+ .set('second', 0).toDate();
237
+ const newInstance = { nextDate, ...emptyInstance };
238
+ if (currentDatePlusNotification >= nextDate) {
239
+ newInstances.push(newInstance);
240
+ }
241
+ } while (currentDatePlusNotification >= nextDate);
242
+ if (newInstances.length) {
243
+ await BorrowerCompliance.findByIdAndUpdate(complianceBorrowerId, { $push: { ['items.' + index + '.instances']: newInstances } });
244
+ }
245
+ break;
246
+ default:
247
+ const { value, unit } = frequencies[frequency];
248
+ newInstances = [];
249
+ do {
250
+ const latestDate = newInstances.length ? newInstances[newInstances.length - 1].nextDate : getLatestInstanceDate(item);
251
+ nextDate = !latestDate
252
+ ? item.startDate
253
+ : dayjs(latestDate)
254
+ .add(value, unit)
255
+ .set('hour', 0)
256
+ .set('minute', 0)
257
+ .set('second', 0).toDate();
258
+ const newInstance = { nextDate, ...emptyInstance };
259
+ if (currentDatePlusNotification >= nextDate) {
260
+ newInstances.push(newInstance);
261
+ }
262
+ } while (currentDatePlusNotification >= nextDate);
263
+ if (newInstances.length) {
264
+ await BorrowerCompliance.findByIdAndUpdate(complianceBorrowerId, { $push: { ['items.' + index + '.instances']: newInstances } });
265
+ }
266
+ break;
267
+ }
268
+ }
269
+ }
270
+ return await this.getFullComplianceBorrowerById(complianceBorrowerId);
271
+ }
272
+
273
+ async calculateAndUpdateFundingStatus(complianceBorrowerId: string) {
274
+ const complianceBorrower = await this.getFullComplianceBorrowerById(complianceBorrowerId);
275
+ const fundingStatus = this.calculateFundingStatus(complianceBorrower);
276
+ await this.updateFundingStatus(complianceBorrowerId, fundingStatus);
277
+ }
278
+
279
+ calculateFundingStatus(complianceBorrower: IComplianceBorrowerDocumentFull): string {
280
+ let hasErrors = false;
281
+ let hasWarnings = false;
282
+ complianceBorrower.items.forEach((item) => {
283
+ item.instances.forEach((instance) => {
284
+ if (instance.status !== 'ACCEPTED') {
285
+ const { progress } = this.calculateInstanceStatuses(instance, item);
286
+ switch (progress?.status) {
287
+ case EItemProgressStatus.IN_REVIEW:
288
+ hasWarnings = true;
289
+ break;
290
+ case EItemProgressStatus.OVERDUE:
291
+ hasErrors = true;
292
+ break;
293
+ }
294
+ }
295
+ });
296
+ });
297
+ let fundingStatus = 'COMPLIANT';
298
+ if (hasWarnings) {
299
+ fundingStatus = 'PENDING';
300
+ }
301
+ if (hasErrors) {
302
+ fundingStatus = 'OVERDUE';
303
+ }
304
+ if (complianceBorrower.fundingStatus === 'NOT_PAID') {
305
+ fundingStatus = 'NOT_PAID';
306
+ }
307
+ return fundingStatus;
308
+ }
309
+
310
+ async updateComplianceBorrower(complianceBorrower: IComplianceBorrowerDocumentFull) {
311
+ try {
312
+ const { _id } = complianceBorrower;
313
+ const fundingStatus = this.calculateFundingStatus(complianceBorrower);
314
+ return await BorrowerCompliance.findByIdAndUpdate(_id, { ...complianceBorrower, fundingStatus });
315
+ } catch (e) {
316
+ console.error(e);
317
+ return null;
318
+ }
319
+ }
320
+
321
+ async updateFundingStatus(complianceBorrowerId: string, fundingStatus: string) {
322
+ try {
323
+ return await BorrowerCompliance
324
+ .findByIdAndUpdate(complianceBorrowerId, { fundingStatus });
325
+ } catch (e) {
326
+ console.error(e);
327
+ return null;
328
+ }
329
+ }
330
+
331
+ async updateLastEmailSent(complianceBorrowerId: string, lastEmailSentAt: Date) {
332
+ try {
333
+ return await BorrowerCompliance
334
+ .findByIdAndUpdate(complianceBorrowerId, { lastEmailSentAt });
335
+ } catch (e) {
336
+ console.error(e);
337
+ return null;
338
+ }
339
+ }
340
+
341
+ async getAllBorrowersIds(onlyActive = true) {
342
+ try {
343
+ const mainFilter = { isVisible: true };
344
+ const filter = onlyActive ? { 'borrower.active': true, ...mainFilter } : { ...mainFilter };
345
+ const complianceBorrowers = await BorrowerCompliance.aggregate([
346
+ {
347
+ $lookup: {
348
+ from: 'borrowers',
349
+ localField: 'borrower',
350
+ foreignField: '_id',
351
+ as: 'borrower',
352
+ },
353
+ }, {
354
+ $unwind: {
355
+ path: '$borrower',
356
+ },
357
+ }, {
358
+ $match: filter,
359
+ },
360
+ ]);
361
+ return complianceBorrowers.map((complianceBorrower) => complianceBorrower._id.toString());
362
+ } catch (e) {
363
+ console.error(e);
364
+ return null;
365
+ }
366
+ }
367
+
368
+ async getBorrowerListByItemId(complianceItemId: string) {
369
+ return BorrowerCompliance
370
+ .find({
371
+ 'items': {
372
+ $elemMatch: {
373
+ item: complianceItemId,
374
+ },
375
+ },
376
+ })
377
+ .populate('borrower');
378
+ }
379
+
380
+ async deleteInstanceById(complianceBorrowerId: string, complianceInstanceId: string) {
381
+ await BorrowerCompliance
382
+ .findOneAndUpdate(
383
+ { _id: complianceBorrowerId },
384
+ { '$pull': { 'items.$[].instances': { _id: complianceInstanceId } } },
385
+ );
386
+ }
387
+
388
+ async getBorrowerByInstanceId(complianceInstanceId: string) {
389
+ return BorrowerCompliance
390
+ .findOne({
391
+ 'items.instances': {
392
+ $elemMatch: {
393
+ _id: complianceInstanceId,
394
+ },
395
+ },
396
+ });
397
+ }
398
+
399
+ async markInstanceFilesAsOld(complianceInstanceId: string) {
400
+ const items = await this._fileManagerService.findItemByInstanceId(complianceInstanceId);
401
+ if (items.length > 0) {
402
+ const itemId = items.pop().items._id;
403
+ return BorrowerCompliance
404
+ .findOneAndUpdate(
405
+ {
406
+ 'items.instances': {
407
+ $elemMatch: {
408
+ _id: complianceInstanceId,
409
+ },
410
+ },
411
+ },
412
+ { $set: { 'items.$[item].instances.$[instance].files.$[].isFileNew': false } },
413
+ {
414
+ arrayFilters: [
415
+ { 'item._id': itemId },
416
+ { 'instance._id': new mongoose.Types.ObjectId(complianceInstanceId) },
417
+ ],
418
+ },
419
+ );
420
+ }
421
+ }
422
+
423
+ async getBorrowerWithPlaidToken() {
424
+ return BorrowerCompliance
425
+ .find({ plaidAccessToken: { $exists: true } })
426
+ .select('+plaidAccessToken');
427
+ }
428
+
429
+ async getBorrowerEmails(userAccess) {
430
+ const allComplianceBorrower: IComplianceBorrowerDocument[] = await BorrowerCompliance
431
+ .find(userAccess.allBorrowers ? {} : { 'borrower': { $in: userAccess.borrowersAccess.map((b) => b.borrower) } })
432
+ .populate('borrower items.item')
433
+ .collation({ locale: 'en' })
434
+ .sort({ 'borrower.name': 1 });
435
+ return allComplianceBorrower.map((b) => {
436
+ const items = b.items.map((item) => {
437
+ return {
438
+ value: item.item?.id ?? null,
439
+ title: item.item?.name ?? null,
440
+ };
441
+ });
442
+ const uniqEmails = _.uniq((b.items.reduce((acc, item) => [...acc, ...item.emailAddresses], [])).map((email) => email.email));
443
+ const groupedEmails = b.items.reduce((acc, item) => {
444
+ if (item.emailAddresses.length) {
445
+ acc[item.item?.id ?? null] = item.emailAddresses;
446
+ }
447
+ return acc;
448
+ }, {});
449
+ if (!b.borrower) {
450
+ return;
451
+ }
452
+ return {
453
+ borrower: { _id: b.id, name: b.borrower?.name ?? '', borrowerId: b.borrower?.id ?? '' },
454
+ email: b.email,
455
+ mainEmails: b.mainEmails ?? [],
456
+ financialEmails: b.financialEmails ?? [],
457
+ isEmailingActive: b.isEmailingActive,
458
+ isDailyTransactionsEmailingActive: b.isDailyTransactionsEmailingActive,
459
+ uniqEmails,
460
+ groupedEmails,
461
+ items,
462
+ };
463
+ });
464
+ }
465
+
466
+ async getOneBorrowerEmails(userAccess, borrowerId) {
467
+ const borrower: IComplianceBorrowerDocument = await BorrowerCompliance
468
+ .findOne({ _id: borrowerId })
469
+ .populate('borrower items.item')
470
+ .collation({ locale: 'en' })
471
+ .sort({ 'borrower.name': 1 });
472
+ const items = borrower.items.map((item) => {
473
+ return {
474
+ value: item.item?.id ?? null,
475
+ title: item.item?.name ?? null,
476
+ };
477
+ });
478
+ const uniqEmails = _.uniq((borrower.items.reduce((acc, item) => [...acc, ...item.emailAddresses], [])).map((email) => email.email));
479
+ const groupedEmails = borrower.items.reduce((acc, item) => {
480
+ if (item.emailAddresses.length) {
481
+ acc[item.item?.id ?? null] = item.emailAddresses;
482
+ }
483
+ return acc;
484
+ }, {});
485
+ if (!borrower.borrower) {
486
+ return;
487
+ }
488
+ return {
489
+ borrower: { _id: borrower.id, name: borrower.borrower?.name ?? '', borrowerId: borrower.borrower?.id ?? '' },
490
+ email: borrower.email,
491
+ mainEmails: borrower.mainEmails ?? [],
492
+ financialEmails: borrower.financialEmails ?? [],
493
+ isEmailingActive: borrower.isEmailingActive,
494
+ isDailyTransactionsEmailingActive: borrower.isDailyTransactionsEmailingActive,
495
+ uniqEmails,
496
+ groupedEmails,
497
+ items,
498
+ };
499
+ }
500
+
501
+ async getBorrowerEmailsGrouped(borrowerId: string): Promise<{
502
+ mainEmails: IEmailRecipient[],
503
+ financialEmails: IEmailRecipient[]
504
+ }> {
505
+ const borrower = await BorrowerCompliance.findOne({ borrower: borrowerId });
506
+ if (borrower) {
507
+ return {
508
+ mainEmails: borrower.mainEmails,
509
+ financialEmails: borrower.financialEmails,
510
+ };
511
+ }
512
+ }
513
+
514
+ async updateBorrowerEmailAddresses(emailUpdate: IGroupedEmailsUpdate) {
515
+ const filter = { _id: emailUpdate._id };
516
+ const update = {
517
+ $set: {
518
+ isEmailingActive: emailUpdate.isEmailingActive,
519
+ isDailyTransactionsEmailingActive: emailUpdate.isDailyTransactionsEmailingActive,
520
+ mainEmails: emailUpdate.mainEmails,
521
+ financialEmails: emailUpdate.financialEmails,
522
+ 'items.$[].emailAddresses': [],
523
+ },
524
+ };
525
+ await BorrowerCompliance.updateOne(filter, update);
526
+ await Promise.all(Object.entries(emailUpdate.groupedEmails).map(async ([id, emails]) => {
527
+ const itemUpdate = {
528
+ $set: {
529
+ 'items.$[item].emailAddresses': emails,
530
+ },
531
+ };
532
+ const arrayFilter = {
533
+ arrayFilters: [
534
+ { 'item.item': id },
535
+ ],
536
+ };
537
+ await BorrowerCompliance.updateOne(filter, itemUpdate, arrayFilter);
538
+ }));
539
+ return BorrowerCompliance.findOne(filter);
540
+ }
541
+
542
+ async toggleComplianceBorrowerVisibility(borrowerId: string, isVisible: boolean) {
543
+ const foundBorrower = await BorrowerCompliance.findOne({ borrower: borrowerId });
544
+ if (!!foundBorrower) {
545
+ await BorrowerCompliance.findByIdAndUpdate(foundBorrower._id, { isVisible });
546
+ }
547
+ }
548
+
549
+ async createComplianceBorrower(borrowerId: string, isVisible = true) {
550
+ const foundBorrower = await BorrowerCompliance.findOne({ borrower: borrowerId });
551
+ if (!!foundBorrower) {
552
+ await BorrowerCompliance.findByIdAndUpdate(foundBorrower._id, { isVisible });
553
+ } else {
554
+ const newComplianceBorrower = new BorrowerCompliance({ borrower: borrowerId, isVisible });
555
+ await newComplianceBorrower.save();
556
+ }
557
+ }
558
+
559
+ async removeIncorrectBorrowers() {
560
+ const allComplianceBorrowers = await BorrowerCompliance.find({});
561
+ let n = 0;
562
+ for (const borrower of allComplianceBorrowers) {
563
+ if ((borrower['isDeleted'] === true) || borrower['isDeleted'] === undefined) {
564
+ try {
565
+ await BorrowerCompliance.findByIdAndDelete(borrower._id);
566
+ n += 1;
567
+ } catch (e) {
568
+ console.error(e);
569
+ }
570
+ }
571
+ await BorrowerCompliance.findByIdAndUpdate(borrower._id, { isVisible: true });
572
+ }
573
+
574
+ const allBorrowers = await BorrowerModel.find({});
575
+ for (const borrower of allBorrowers) {
576
+ const complianceBorrower = await BorrowerCompliance.findOne({ borrower: borrower._id });
577
+ if (!complianceBorrower) {
578
+ await this.createComplianceBorrower(borrower._id.toString(), false);
579
+ }
580
+ }
581
+ }
582
+
583
+ async getBorrowerListReport(user: IUser) {
584
+ const userFilter = user.allBorrowers
585
+ ? { isVisible: true }
586
+ : { 'borrower': { $in: user.borrowersAccess.map((b) => b.borrower) }, isVisible: true };
587
+ const borrowers = await BorrowerCompliance
588
+ .find(userFilter)
589
+ .populate('borrower')
590
+ .populate('items.item')
591
+ ;
592
+ const finalList = [
593
+ ['borrower', 'due date', 'item', 'status'],
594
+ ];
595
+ borrowers
596
+ .sort((a, b) => a.borrower.name.localeCompare(b.borrower.name))
597
+ .forEach((borrower) => {
598
+ borrower.items
599
+ .filter((borrowerItem) => !!borrowerItem.item)
600
+ .sort((a, b) => a.item.name.localeCompare(b.item.name))
601
+ .forEach((item) => {
602
+ item.instances.forEach((instance) => {
603
+ if (instance.status !== 'ACCEPTED') {
604
+ finalList.push([
605
+ borrower.borrower.name.trim(),
606
+ instance.nextDate,
607
+ item.item.name.trim(),
608
+ instance.status,
609
+ ]);
610
+ }
611
+ });
612
+ });
613
+ });
614
+ return await this._uploadsService.convertDataToFile([{ list: finalList }]);
615
+ }
616
+
617
+ }
@@ -0,0 +1,42 @@
1
+ /// <reference types="mongoose/types/aggregate" />
2
+ /// <reference types="mongoose/types/callback" />
3
+ /// <reference types="mongoose/types/collection" />
4
+ /// <reference types="mongoose/types/connection" />
5
+ /// <reference types="mongoose/types/cursor" />
6
+ /// <reference types="mongoose/types/document" />
7
+ /// <reference types="mongoose/types/error" />
8
+ /// <reference types="mongoose/types/expressions" />
9
+ /// <reference types="mongoose/types/helpers" />
10
+ /// <reference types="mongoose/types/middlewares" />
11
+ /// <reference types="mongoose/types/indexes" />
12
+ /// <reference types="mongoose/types/models" />
13
+ /// <reference types="mongoose/types/mongooseoptions" />
14
+ /// <reference types="mongoose/types/pipelinestage" />
15
+ /// <reference types="mongoose/types/populate" />
16
+ /// <reference types="mongoose/types/query" />
17
+ /// <reference types="mongoose/types/schemaoptions" />
18
+ /// <reference types="mongoose/types/schematypes" />
19
+ /// <reference types="mongoose/types/session" />
20
+ /// <reference types="mongoose/types/types" />
21
+ /// <reference types="mongoose/types/utility" />
22
+ /// <reference types="mongoose/types/validation" />
23
+ /// <reference types="mongoose/types/virtuals" />
24
+ /// <reference types="mongoose" />
25
+ /// <reference types="mongoose/types/inferschematype" />
26
+ import { IEquipment, IEquipmentItem, IEquipmentSummary } from '../models/Equipment.model';
27
+ import { LockService } from './lock.service';
28
+ export declare class EquipmentService {
29
+ private readonly lockService;
30
+ constructor(lockService: LockService);
31
+ getEquipmentDates(borrowerId: string): Promise<string[]>;
32
+ getEquipmentForDate(borrowerId: string, date: Date): Promise<IEquipment>;
33
+ getLatestEquipmentForDate(borrowerId: string, date: Date): Promise<IEquipment>;
34
+ getEquipmentSummaryForProduct(borrowerId: string, date: Date, productId: string): Promise<IEquipmentSummary>;
35
+ getEquipmentForBBC(bbcDateId: string): Promise<IEquipment>;
36
+ saveAndReturnEquipment(borrowerId: string, date: Date, items: IEquipmentItem[]): Promise<import("mongoose").FlattenMaps<import("../models/Equipment.model").IEquipmentDoc> & {
37
+ _id: import("mongoose").Types.ObjectId;
38
+ }>;
39
+ deleteEquipment(borrowerId: string, date: Date): Promise<void>;
40
+ getLastCopyEquipmentItems(borrowerId: string, date: Date): Promise<IEquipmentItem[]>;
41
+ private calculateSummary;
42
+ }