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,475 @@
1
+ import mongoose from 'mongoose';
2
+ import { Decimal } from 'decimal.js';
3
+ import _ from 'lodash';
4
+ import dayjs from 'dayjs';
5
+
6
+ import {
7
+ ELoanTransactionTypes,
8
+ ILoanTransaction,
9
+ ILoanTransactionDoc,
10
+ ILoanTransactionWithId,
11
+ LoanTransaction,
12
+ } from '../models/LoanTransaction.model';
13
+ import { Bank } from '../models/Banks.model';
14
+
15
+ import {
16
+ ISplitTransaction,
17
+ IUploadedBankTransaction,
18
+ IUploadedBankTransactionWithInfo,
19
+ UploadedBankTransaction,
20
+ } from '../models/UploadedBankTransaction.model';
21
+ import { getUUID } from '../helpers/main.helper';
22
+ import { CashAllocationReference } from '../models/CashAllocationReference.model';
23
+ import { CashAllocationProduct, ICashAllocationProduct } from '../models/CashAllocationProduct.model';
24
+ import {
25
+ AllocatedBankTransaction,
26
+ IAllocatedBankTransaction,
27
+ PreSplitUploadedBankTransactionWithInfo,
28
+ } from '../models/AllocatedBankTransaction.model';
29
+ import { AllocatedData } from '../models/AllocatedData.model';
30
+ import { MAIN_DATE_FORMAT } from '../constants/date-formats.contsants';
31
+ import { LoanTransactionsService } from './loan-transactions.service';
32
+ import { CashAllocationService } from './cash-allocation.service';
33
+ import { LoanStatementStatusService } from './loan-statement-status.service';
34
+
35
+ const useExternalUploader = false; // TODO keep only external upload
36
+
37
+ const createCashAllocationReferencesOnUpload = false;
38
+
39
+ export class BankUploadedTransactionsService {
40
+
41
+ constructor(
42
+ private readonly cashAllocationService: CashAllocationService,
43
+ private readonly loanStatementStatusService: LoanStatementStatusService,
44
+ private readonly getLoanTransactionsService: () => LoanTransactionsService,
45
+ ) {
46
+ }
47
+
48
+ async uploadTransactions(transactions: IUploadedBankTransaction[]) {
49
+ if (useExternalUploader) {
50
+ const taskId = getUUID();
51
+ // await this.queueService.sendTaskToQueue({
52
+ // data: { transactions, taskId },
53
+ // pattern: 'bank_uploaded_transactions#CREATE',
54
+ // }, 'goat_upload');
55
+ return taskId;
56
+ } else {
57
+ const mappedTransactions = transactions.reduce((acc, transaction) => {
58
+ const normalizedTransaction: IUploadedBankTransaction = {
59
+ ...transaction,
60
+ reference: transaction.reference.trim(),
61
+ isConverted: false,
62
+ };
63
+ return [...acc, normalizedTransaction];
64
+ }, <IUploadedBankTransaction[]>[]);
65
+ await Promise.all(mappedTransactions.map(async (transaction) => {
66
+ const newTransactions = new UploadedBankTransaction(transaction);
67
+ await newTransactions.save();
68
+ }));
69
+ if (createCashAllocationReferencesOnUpload) {
70
+ await this.cashAllocationService.createCashAllocation(mappedTransactions);
71
+ }
72
+ return null;
73
+ }
74
+ }
75
+
76
+ async getAllocatedBankTransactions(startDate: Date, endDate: Date) {
77
+ return AllocatedBankTransaction.aggregate<IAllocatedBankTransaction>([
78
+ {
79
+ $match: {
80
+ $and: [
81
+ { 'date': { $gte: startDate } },
82
+ { 'date': { $lte: endDate } },
83
+ ],
84
+ },
85
+ },
86
+ {
87
+ $sort: { order: 1, date: 1 },
88
+ },
89
+ ]);
90
+ }
91
+
92
+ async deleteAllocatedBankTransaction(transactionIds: string[]): Promise<void> {
93
+ await AllocatedBankTransaction.deleteMany({ uploadedBankTransactionId: { $in: transactionIds.map((id) => new mongoose.Types.ObjectId(id)) } });
94
+ }
95
+
96
+ async getMappedUploadedBankTransactions(startDate: Date, endDate: Date) {
97
+ const bankTransactions = await this.getUploadedBankTransactions(startDate, endDate);
98
+
99
+ const cashAllocationReferences = await CashAllocationReference.find().lean();
100
+ const cashAllocationProducts = await CashAllocationProduct.find().lean();
101
+ const cashAllocationProductsMap = new Map<string, ICashAllocationProduct>();
102
+ cashAllocationProducts.forEach((product) => {
103
+ cashAllocationProductsMap.set(product._id.toString(), product);
104
+ });
105
+
106
+ const transactionHasMatch = (bankTransaction: IUploadedBankTransaction): boolean => {
107
+ if (bankTransaction.splitTransactions.length > 0) {
108
+ const totalSplit = bankTransaction.splitTransactions.reduce((acc, split) => new Decimal(split.amount).add(acc).toNumber(), 0);
109
+ if (totalSplit === bankTransaction.amount) {
110
+ return true;
111
+ }
112
+ }
113
+ const foundCashAllocationReference = cashAllocationReferences.find((cashAllocationReference) => bankTransaction.reference.toLowerCase().includes(cashAllocationReference.reference.toLowerCase()));
114
+ if (!foundCashAllocationReference || !foundCashAllocationReference.cashAllocationProductId) {
115
+ return false;
116
+ }
117
+ return !!cashAllocationProductsMap.get(foundCashAllocationReference.cashAllocationProductId.toString());
118
+ };
119
+
120
+ const transactionCanSplit = (bankTransaction: IUploadedBankTransaction): boolean => {
121
+ const foundCashAllocationReference = cashAllocationReferences.find((cashAllocationReference) => bankTransaction.reference.toLowerCase().includes(cashAllocationReference.reference.toLowerCase()));
122
+ if (!foundCashAllocationReference || !foundCashAllocationReference.cashAllocationProductId) {
123
+ return false;
124
+ }
125
+ const foundProduct = cashAllocationProductsMap.get(foundCashAllocationReference.cashAllocationProductId.toString());
126
+ return foundProduct.isCommonSplit;
127
+ };
128
+
129
+ return bankTransactions.map((bankTransaction) => {
130
+ return <IUploadedBankTransactionWithInfo>{
131
+ ...bankTransaction,
132
+ hasMatch: transactionHasMatch(bankTransaction),
133
+ canSplit: transactionCanSplit(bankTransaction),
134
+ };
135
+ });
136
+ }
137
+
138
+ async getUploadedBankTransactions(startDate: Date, endDate: Date) {
139
+ return UploadedBankTransaction.aggregate<IUploadedBankTransaction>([
140
+ {
141
+ $match: {
142
+ $and: [
143
+ { 'date': { $gte: startDate } },
144
+ { 'date': { $lte: endDate } },
145
+ ],
146
+ },
147
+ },
148
+ {
149
+ $sort: { date: 1 },
150
+ },
151
+ ]);
152
+ }
153
+
154
+ async getAllocatedTransactions(date: Date) {
155
+ const startDate = dayjs(date).utcOffset(0).startOf('day');
156
+ const endDate = startDate.endOf('day');
157
+ return AllocatedBankTransaction.aggregate<IAllocatedBankTransaction>([
158
+ {
159
+ $match: {
160
+ $and: [
161
+ { 'date': { $gte: startDate.toDate() } },
162
+ { 'date': { $lte: endDate.toDate() } },
163
+ ],
164
+ },
165
+ },
166
+ {
167
+ $sort: { date: 1, order: 1 },
168
+ },
169
+ ]);
170
+ }
171
+
172
+ async getPreAllocatedTransactions(date: Date) {
173
+ const startDate = dayjs(date).utcOffset(0).startOf('day');
174
+ const endDate = startDate.endOf('day');
175
+ const pureUploadedBankTransactions = await this.getMappedUploadedBankTransactions(startDate.toDate(), endDate.toDate());
176
+
177
+ const { references, products } = await this.cashAllocationService.getAllCashAllocations();
178
+
179
+ const populateAllocatedBankTransaction = (allocatedBankTransaction: IAllocatedBankTransaction, cashAllocation: ICashAllocationProduct) => {
180
+ const updatedAllocatedBankTransaction = _.cloneDeep(allocatedBankTransaction);
181
+ if (cashAllocation) {
182
+ const keysToUpdate = ['class', 'location', 'DRMemo', 'CRMemo'];
183
+ keysToUpdate.forEach((key) => {
184
+ updatedAllocatedBankTransaction[key] = cashAllocation[key];
185
+ });
186
+ updatedAllocatedBankTransaction.cashAllocationProductId = cashAllocation._id;
187
+ }
188
+ return updatedAllocatedBankTransaction;
189
+ };
190
+
191
+ let order = 0;
192
+
193
+ const uploadedBankTransactions = pureUploadedBankTransactions
194
+ .reduce((acc, tr) => {
195
+ if (tr.splitTransactions.length > 0) {
196
+ const restTransaction: PreSplitUploadedBankTransactionWithInfo = {
197
+ ...tr,
198
+ order,
199
+ splitTransactionId: null,
200
+ splitMemo: '',
201
+ };
202
+ order = order + 1;
203
+ const splitTransactions = tr.splitTransactions.map((splitTr) => {
204
+ const foundRef = references.find((i) => i._id.toString() === splitTr.referenceId.toString());
205
+ const transaction: PreSplitUploadedBankTransactionWithInfo = {
206
+ _id: tr._id,
207
+ order,
208
+ accountNumber: tr.accountNumber,
209
+ amount: splitTr.amount,
210
+ date: tr.date,
211
+ detail1: '',
212
+ detail2: '',
213
+ detail3: '',
214
+ hasMatch: true,
215
+ canSplit: false,
216
+ isConverted: tr.isConverted,
217
+ reference: foundRef ? foundRef.reference : tr.reference,
218
+ splitTransactions: [],
219
+ transactionType: tr.transactionType,
220
+ splitTransactionId: splitTr._id,
221
+ splitMemo: splitTr.memo,
222
+ };
223
+ restTransaction.amount = new Decimal(restTransaction.amount).sub(transaction.amount).toNumber();
224
+ return transaction;
225
+ });
226
+ if (restTransaction.amount !== 0) {
227
+ return [...acc, ...splitTransactions, restTransaction];
228
+ }
229
+ return [...acc, ...splitTransactions];
230
+ }
231
+ order = order + 1;
232
+ return [...acc, { ...tr, splitTransactionId: null, splitMemo: '', order }];
233
+ }, <PreSplitUploadedBankTransactionWithInfo[]>[]);
234
+
235
+ const allocatedBankTransactions = uploadedBankTransactions
236
+ .reduce((acc, tr) => {
237
+ const allocatedBankTransaction: IAllocatedBankTransaction = {
238
+ order: tr.order,
239
+ uploadedBankTransactionId: tr._id,
240
+ accountNumber: tr.accountNumber,
241
+ amount: tr.amount,
242
+ date: tr.date,
243
+ reference: tr.reference,
244
+ cashAllocationReferenceId: null,
245
+ cashAllocationProductId: null,
246
+ accounts: null,
247
+ class: '',
248
+ location: '',
249
+ memo: tr.splitMemo,
250
+ splitTransactionId: tr.splitTransactionId,
251
+ };
252
+ const foundCashAllocationReferences = references
253
+ .filter((reference) => tr.reference.toLowerCase().includes(reference.reference.toLowerCase()));
254
+ if (!foundCashAllocationReferences.length) {
255
+ return acc;
256
+ }
257
+ const useOnlyOneReference = true;
258
+ const reducedFoundCashAllocationReferences = useOnlyOneReference ? foundCashAllocationReferences.slice(0, 1) : foundCashAllocationReferences;
259
+ return [
260
+ ...acc,
261
+ ...reducedFoundCashAllocationReferences.map((foundCashAllocationReference) => {
262
+ const foundCashAllocationProduct = products
263
+ .find((product) => product._id.toString() === foundCashAllocationReference.cashAllocationProductId.toString());
264
+ if (!foundCashAllocationProduct) {
265
+ return null;
266
+ }
267
+ return foundCashAllocationProduct
268
+ ? populateAllocatedBankTransaction({
269
+ ...allocatedBankTransaction,
270
+ cashAllocationReferenceId: foundCashAllocationReference._id,
271
+ accounts: foundCashAllocationProduct.accounts,
272
+ memo: (tr.splitMemo && tr.splitMemo.trim() !== '')
273
+ ? tr.splitMemo
274
+ : (tr.amount > 0 ? foundCashAllocationProduct.DRMemo : foundCashAllocationProduct.CRMemo),
275
+ }, foundCashAllocationProduct)
276
+ : allocatedBankTransaction;
277
+ })];
278
+ }, <IAllocatedBankTransaction[]>[])
279
+ .filter((tr) => !!tr);
280
+ return { allocatedBankTransactions, uploadedBankTransactions };
281
+ }
282
+
283
+ async resetAllocatedBankTransactions(date: Date) {
284
+ const { allocatedBankTransactions } = await this.getPreAllocatedTransactions(date);
285
+ const uniqueTransactionsIds = new Set(allocatedBankTransactions.map((tr) => tr.uploadedBankTransactionId.toString()));
286
+
287
+ await this.deleteAllocatedBankTransaction(Array.from(uniqueTransactionsIds));
288
+ await Promise.all(allocatedBankTransactions.map(async (transaction) => {
289
+ const newTransaction = new AllocatedBankTransaction(transaction);
290
+ await newTransaction.save();
291
+ }));
292
+ await this.updateLockStatus(date, false);
293
+ }
294
+
295
+ async createAllocatedBankTransactions(date: Date) {
296
+ const cashAllocations = await this.getAllocatedTransactions(date);
297
+ const allocatedData = await AllocatedData.findOne({ date: dayjs(date).format(MAIN_DATE_FORMAT) });
298
+ if (cashAllocations.length > 0 && (allocatedData && allocatedData.isLocked)) {
299
+ return;
300
+ }
301
+ await this.resetAllocatedBankTransactions(date);
302
+ }
303
+
304
+ async convertBankTransactions(startDate: Date, userId: string) {
305
+ const allocatedTransactions = await this.getAllocatedTransactions(startDate);
306
+ const transactionIds = allocatedTransactions.map((transaction) => transaction.uploadedBankTransactionId.toString());
307
+ const transactions = await UploadedBankTransaction.find({ _id: { $in: transactionIds } });
308
+ const cashAllocations = await this.cashAllocationService.getAllCashAllocations();
309
+ const banks = await Bank.find().lean();
310
+ const loanTransactionsMap = transactions.reduce((acc, transaction) => {
311
+ return {
312
+ ...acc,
313
+ [transaction._id.toString()]: [] as mongoose.Types.ObjectId[],
314
+ };
315
+ }, <{ [transactionId: string]: mongoose.Types.ObjectId[] }>{});
316
+ const productIds = new Set<string>();
317
+ await Promise.all(allocatedTransactions.map(async (transactionToConvert) => {
318
+ const transaction = transactions.find((tr) => tr._id.toString() === transactionToConvert.uploadedBankTransactionId.toString());
319
+ if (transaction.isConverted) {
320
+ return;
321
+ }
322
+ const splitTransaction = transactionToConvert.splitTransactionId
323
+ ? transaction.splitTransactions.find((tr) => tr._id.toString() === transactionToConvert.splitTransactionId.toString())
324
+ : null;
325
+
326
+ const foundCashAllocationProduct = cashAllocations.products.find((c) => c._id.toString() === transactionToConvert.cashAllocationProductId.toString());
327
+ if (!foundCashAllocationProduct || !foundCashAllocationProduct.productId) {
328
+ return;
329
+ }
330
+ const foundBank = banks.find((b) => b.bankAccountNumber === transaction.accountNumber);
331
+ const getLoanTransaction = (): ILoanTransaction => ({
332
+ amount: transactionToConvert.amount,
333
+ bankId: foundBank ? new mongoose.Types.ObjectId(String(foundBank._id)) : null,
334
+ customerId: null,
335
+ date: new Date(transaction.date),
336
+ description: '',
337
+ effectiveDate: null,
338
+ productId: foundCashAllocationProduct.productId,
339
+ reference: splitTransaction ? splitTransaction.memo : transactionToConvert.reference,
340
+ transactionType: transaction.amount > 0 ? ELoanTransactionTypes.COLLECTION : ELoanTransactionTypes.DISBURSEMENT,
341
+ balance: 0,
342
+ floatedBalance: 0,
343
+ });
344
+ const loanTransactionsService = this.getLoanTransactionsService();
345
+ const normalizedTransaction = await loanTransactionsService.normalizeLoanTransaction(getLoanTransaction() as ILoanTransactionDoc, userId);
346
+ const createdLoanTransaction = await loanTransactionsService.createLoanTransaction(normalizedTransaction as Partial<ILoanTransactionWithId>);
347
+ loanTransactionsMap[String(transaction._id)] = [...loanTransactionsMap[String(transaction._id)], new mongoose.Types.ObjectId(String(createdLoanTransaction._id))];
348
+ productIds.add(String(foundCashAllocationProduct.productId));
349
+ }));
350
+
351
+ await Promise.all(transactions.map(async (transaction) => {
352
+ await transaction.updateOne({
353
+ isConverted: true,
354
+ loanTransactionIds: loanTransactionsMap[String(transaction._id)],
355
+ });
356
+ }));
357
+ this.recalculateProducts(Array.from(productIds));
358
+ }
359
+
360
+ recalculateProducts(productIds: string[]) {
361
+ // TODO rework in something better
362
+ setTimeout(async () => {
363
+ await Promise.all(productIds.map(async (productId) => {
364
+ console.log({ productId });
365
+ const loanTransactionsService = this.getLoanTransactionsService();
366
+ await loanTransactionsService.recalculateProduct(productId);
367
+ }));
368
+ }, 2_000);
369
+ }
370
+
371
+ async preSplitBankTransactions(transactionId: string, splitTransaction: ISplitTransaction[]) {
372
+ const mappedSplitTransactions: ISplitTransaction[] = splitTransaction.map((transaction) => {
373
+ const { _id, ...transactionRest } = transaction;
374
+ return _id.toString().includes('new_') ? transactionRest : transaction;
375
+ });
376
+ await UploadedBankTransaction.updateOne({ _id: new mongoose.Types.ObjectId(transactionId) }, { splitTransactions: mappedSplitTransactions });
377
+ }
378
+
379
+ async deleteBankTransaction(transactionIds: string[]) {
380
+ await UploadedBankTransaction.deleteMany({ _id: { $in: transactionIds }, isConverted: false });
381
+ }
382
+
383
+ async revertAllBankTransactions(startDate: Date, endDate: Date, userId: string) {
384
+ const transactions = await this.getUploadedBankTransactions(startDate, endDate);
385
+ const transactionIds = transactions.map((t) => t._id.toString());
386
+ await this.revertBankTransactions(transactionIds, userId);
387
+ }
388
+
389
+ async revertBankTransactions(transactionIds: string[], userId: string) {
390
+ const foundTransaction = await UploadedBankTransaction.find({ _id: { $in: transactionIds }, isConverted: true });
391
+ const productIds = new Set<string>();
392
+ await Promise.all(foundTransaction.map(async (transaction) => {
393
+ try {
394
+ await Promise.all(transaction.loanTransactionIds.map(async (loanTransactionId) => {
395
+ const loanTransaction = await LoanTransaction.findById(loanTransactionId);
396
+ const loanTransactionsService = this.getLoanTransactionsService();
397
+ const isLocked = await loanTransactionsService.checkLockStatus(loanTransaction);
398
+ if (isLocked) {
399
+ throw new Error('period is locked');
400
+ }
401
+ const validationError = await this.loanStatementStatusService.validateDate(loanTransaction.productId.toString(), new Date(transaction.date));
402
+ if (validationError) {
403
+ throw new Error('validation error');
404
+ }
405
+ await loanTransactionsService.deleteLoanTransaction(loanTransactionId.toString(), false, userId);
406
+ productIds.add(loanTransaction.productId.toString());
407
+ }));
408
+ transaction.loanTransactionIds = [];
409
+ transaction.isConverted = false;
410
+ await transaction.save();
411
+
412
+ this.recalculateProducts(Array.from(productIds));
413
+ } catch (error) {
414
+ console.log(error);
415
+ }
416
+ }));
417
+ }
418
+
419
+ async getUniqueDates() {
420
+ const uniqueDates = await UploadedBankTransaction.aggregate([
421
+ {
422
+ $group: {
423
+ _id: { $dateToString: { format: '%Y-%m-%d', date: '$date' } },
424
+ },
425
+ },
426
+ {
427
+ $sort: { _id: 1 },
428
+ },
429
+ ]);
430
+ return uniqueDates.map(d => d._id);
431
+ }
432
+
433
+ async saveAllocatedBankTransactions(date: Date, transactions: IAllocatedBankTransaction[]) {
434
+ const startDate = dayjs(date).utcOffset(0).startOf('day');
435
+ const endDate = startDate.endOf('day');
436
+ const existingAllocatedTransactions = await this.getAllocatedBankTransactions(startDate.toDate(), endDate.toDate());
437
+ const existingTransactionIds = existingAllocatedTransactions.map((t) => t._id.toString());
438
+ const transactionIds = transactions.map((t) => t._id.toString());
439
+ const transactionIdsToDelete = existingTransactionIds.reduce((acc, id) => {
440
+ if (transactionIds.includes(id)) {
441
+ return acc;
442
+ }
443
+ return [...acc, id];
444
+ }, <string[]>[]);
445
+
446
+ await Promise.all(transactions.map(async (transaction, order) => {
447
+ const { _id, ...rest } = transaction;
448
+ if (_id.toString().includes('new_')) {
449
+ const newTransaction = new AllocatedBankTransaction({ ...rest, order });
450
+ await newTransaction.save();
451
+ } else {
452
+ await AllocatedBankTransaction.updateOne({ _id }, { ...rest, order });
453
+ }
454
+ }));
455
+
456
+ await AllocatedBankTransaction.deleteMany({ _id: { $in: transactionIdsToDelete } });
457
+ await this.updateLockStatus(date, true);
458
+ }
459
+
460
+ async createAllocatedBankTransaction(transaction: IAllocatedBankTransaction) {
461
+ const { _id, ...rest } = transaction;
462
+ const startDate = dayjs(transaction.date).utcOffset(0).startOf('day');
463
+ const endDate = startDate.endOf('day');
464
+ const existingAllocatedTransactions = await this.getAllocatedBankTransactions(startDate.toDate(), endDate.toDate());
465
+ const order = existingAllocatedTransactions.length > 0 ? existingAllocatedTransactions[existingAllocatedTransactions.length - 1].order + 1 : 0;
466
+ const newTransaction = new AllocatedBankTransaction({ ...rest, order });
467
+ await newTransaction.save();
468
+ await this.updateLockStatus(transaction.date, true);
469
+ }
470
+
471
+ async updateLockStatus(date: Date, isLocked: boolean) {
472
+ const normalizedDate = dayjs(date).utcOffset(0).startOf('day');
473
+ await AllocatedData.updateOne({ date: normalizedDate.format(MAIN_DATE_FORMAT) }, { isLocked }, { upsert: true });
474
+ }
475
+ }
@@ -0,0 +1,36 @@
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 { IBankView, IBankWithId } from '../models/Banks.model';
27
+ export declare class BanksService {
28
+ getBanks(): Promise<IBankView[]>;
29
+ createBank(bank: IBankView): Promise<void>;
30
+ editBank(bank: IBankView): Promise<void>;
31
+ findBankByNumber(bankAccountNumber: string): Promise<import("mongoose").FlattenMaps<import("../models/Banks.model").IBankDoc> & {
32
+ _id: import("mongoose").Types.ObjectId;
33
+ }>;
34
+ findBankByAccountCode(accountCode: string): Promise<IBankWithId>;
35
+ updateBanks(banks: IBankView[]): Promise<void>;
36
+ }
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BanksService = void 0;
4
+ const Banks_model_1 = require("../models/Banks.model");
5
+ const QuickbooksAccount_model_1 = require("../models/QuickbooksAccount.model");
6
+ const fieldsToUnset = ['order', '__v', 'createdAt', 'updatedAt'];
7
+ class BanksService {
8
+ async getBanks() {
9
+ return Banks_model_1.Bank.aggregate([
10
+ {
11
+ $sort: {
12
+ 'order': 1,
13
+ },
14
+ }, {
15
+ $unset: fieldsToUnset,
16
+ }, {
17
+ $addFields: {
18
+ valid: true,
19
+ },
20
+ },
21
+ ]);
22
+ }
23
+ async createBank(bank) {
24
+ const newBank = new Banks_model_1.Bank(bank);
25
+ await newBank.save();
26
+ }
27
+ async editBank(bank) {
28
+ await Banks_model_1.Bank.findByIdAndUpdate(bank._id, bank);
29
+ }
30
+ async findBankByNumber(bankAccountNumber) {
31
+ return Banks_model_1.Bank.findOne({ bankAccountNumber }).lean();
32
+ }
33
+ async findBankByAccountCode(accountCode) {
34
+ const account = await QuickbooksAccount_model_1.QuickbooksAccount.findOne({ accountCode }).lean();
35
+ if (!account) {
36
+ return null;
37
+ }
38
+ const banks = await Banks_model_1.Bank.aggregate([
39
+ {
40
+ '$match': {
41
+ '$expr': {
42
+ '$gt': [
43
+ {
44
+ '$size': {
45
+ '$filter': {
46
+ 'input': {
47
+ '$objectToArray': '$ledgerAccountCodes',
48
+ },
49
+ 'as': 'entry',
50
+ 'cond': {
51
+ '$eq': [
52
+ '$$entry.v', account._id,
53
+ ],
54
+ },
55
+ },
56
+ },
57
+ }, 0,
58
+ ],
59
+ },
60
+ },
61
+ }, {
62
+ '$sort': {
63
+ 'bankAccountNumber': 1,
64
+ },
65
+ }, {
66
+ '$limit': 1,
67
+ },
68
+ ]);
69
+ if (banks.length > 0) {
70
+ return banks[0];
71
+ }
72
+ return null;
73
+ }
74
+ async updateBanks(banks) {
75
+ const existingBanks = await Banks_model_1.Bank.find().lean();
76
+ const existingBankIds = existingBanks.map((bank) => bank._id.toString());
77
+ const updatedBankIds = banks.map((bank) => bank._id.toString());
78
+ const idsToRemove = existingBankIds.filter((id) => !updatedBankIds.includes(id));
79
+ await Promise.all(banks.map(async (bank) => {
80
+ const { _id, ...rest } = bank;
81
+ if (_id.toString().includes('new_')) {
82
+ await this.createBank({ _id: null, ...rest });
83
+ }
84
+ else {
85
+ await this.editBank(bank);
86
+ }
87
+ }));
88
+ await Banks_model_1.Bank.updateMany({ _id: { $in: idsToRemove } }, { isDeleted: true });
89
+ }
90
+ }
91
+ exports.BanksService = BanksService;