@tomei/finance 0.3.0 → 0.3.2

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 (178) hide show
  1. package/dist/account/account.d.ts +22 -27
  2. package/dist/account/account.js +89 -77
  3. package/dist/account/account.js.map +1 -1
  4. package/dist/account/account.repository.d.ts +3 -14
  5. package/dist/account/account.repository.js +4 -39
  6. package/dist/account/account.repository.js.map +1 -1
  7. package/dist/account/interfaces/account-attr.interface.d.ts +15 -7
  8. package/dist/account-system-entity/account-system-entity.d.ts +2 -2
  9. package/dist/account-system-entity/account-system-entity.js +1 -1
  10. package/dist/account-system-entity/post-history.repository.d.ts +2 -2
  11. package/dist/account-system-entity/post-history.repository.js +1 -1
  12. package/dist/customer/customer.d.ts +3 -3
  13. package/dist/customer/customer.js +1 -2
  14. package/dist/customer/customer.js.map +1 -1
  15. package/dist/customer/finance-customer.repository.d.ts +2 -2
  16. package/dist/customer/finance-customer.repository.js +1 -1
  17. package/dist/customer/interfaces/finance-customer.repository.interface.d.ts +2 -2
  18. package/dist/document/document-item.d.ts +2 -1
  19. package/dist/document/document-item.js +2 -2
  20. package/dist/document/document-item.js.map +1 -1
  21. package/dist/document/document-item.repository.d.ts +3 -15
  22. package/dist/document/document-item.repository.js +4 -43
  23. package/dist/document/document-item.repository.js.map +1 -1
  24. package/dist/document/document.d.ts +20 -23
  25. package/dist/document/document.js +85 -54
  26. package/dist/document/document.js.map +1 -1
  27. package/dist/document/document.repository.d.ts +3 -14
  28. package/dist/document/document.repository.js +4 -39
  29. package/dist/document/document.repository.js.map +1 -1
  30. package/dist/document/interfaces/document-item.repository.interface.d.ts +2 -2
  31. package/dist/enum/index.d.ts +2 -1
  32. package/dist/enum/index.js +3 -1
  33. package/dist/enum/index.js.map +1 -1
  34. package/dist/enum/payment-status.enum.d.ts +4 -0
  35. package/dist/enum/payment-status.enum.js +9 -0
  36. package/dist/enum/payment-status.enum.js.map +1 -0
  37. package/dist/enum/transaction-type.enum.d.ts +2 -2
  38. package/dist/enum/transaction-type.enum.js +2 -2
  39. package/dist/enum/transaction-type.enum.js.map +1 -1
  40. package/dist/finance-company/finance-company.d.ts +15 -10
  41. package/dist/finance-company/finance-company.js +473 -30
  42. package/dist/finance-company/finance-company.js.map +1 -1
  43. package/dist/finance-company/finance-company.repository.d.ts +2 -2
  44. package/dist/finance-company/finance-company.repository.js +1 -1
  45. package/dist/index.d.ts +11 -8
  46. package/dist/index.js +14 -8
  47. package/dist/index.js.map +1 -1
  48. package/dist/interfaces/account-system.interface.d.ts +2 -2
  49. package/dist/journal-entry/journal-entry.d.ts +13 -17
  50. package/dist/journal-entry/journal-entry.js +83 -35
  51. package/dist/journal-entry/journal-entry.js.map +1 -1
  52. package/dist/journal-entry/journal-entry.repository.d.ts +3 -13
  53. package/dist/journal-entry/journal-entry.repository.js +5 -38
  54. package/dist/journal-entry/journal-entry.repository.js.map +1 -1
  55. package/dist/ledger-transaction/interfaces/ledger-transaction-attr.interface.d.ts +0 -4
  56. package/dist/ledger-transaction/ledger-transaction.d.ts +6 -5
  57. package/dist/ledger-transaction/ledger-transaction.js +6 -9
  58. package/dist/ledger-transaction/ledger-transaction.js.map +1 -1
  59. package/dist/ledger-transaction/ledger-transaction.repository.d.ts +3 -8
  60. package/dist/ledger-transaction/ledger-transaction.repository.js +5 -32
  61. package/dist/ledger-transaction/ledger-transaction.repository.js.map +1 -1
  62. package/dist/models/account.entity.d.ts +7 -3
  63. package/dist/models/account.entity.js +69 -34
  64. package/dist/models/account.entity.js.map +1 -1
  65. package/dist/models/finance-company.entity.d.ts +0 -4
  66. package/dist/models/finance-company.entity.js +0 -20
  67. package/dist/models/finance-company.entity.js.map +1 -1
  68. package/dist/models/payment-item.entity.d.ts +1 -0
  69. package/dist/models/payment-item.entity.js +7 -0
  70. package/dist/models/payment-item.entity.js.map +1 -1
  71. package/dist/models/payment-method-type.entity.d.ts +13 -0
  72. package/dist/models/payment-method-type.entity.js +86 -0
  73. package/dist/models/payment-method-type.entity.js.map +1 -0
  74. package/dist/models/payment-method.entity.d.ts +7 -0
  75. package/dist/models/payment-method.entity.js +46 -0
  76. package/dist/models/payment-method.entity.js.map +1 -0
  77. package/dist/models/payment.entity.d.ts +15 -10
  78. package/dist/models/payment.entity.js +92 -34
  79. package/dist/models/payment.entity.js.map +1 -1
  80. package/dist/payment/interfaces/payment-attr.interface.d.ts +11 -8
  81. package/dist/payment/interfaces/payment-attr.interface.js.map +1 -1
  82. package/dist/payment/interfaces/payment-item-attr.interface.d.ts +1 -0
  83. package/dist/payment/interfaces/payment-item-attr.interface.js.map +1 -1
  84. package/dist/payment/payment-item.repository.d.ts +3 -15
  85. package/dist/payment/payment-item.repository.js +4 -43
  86. package/dist/payment/payment-item.repository.js.map +1 -1
  87. package/dist/payment/payment.d.ts +44 -48
  88. package/dist/payment/payment.js +122 -133
  89. package/dist/payment/payment.js.map +1 -1
  90. package/dist/payment/payment.repository.d.ts +3 -14
  91. package/dist/payment/payment.repository.js +4 -39
  92. package/dist/payment/payment.repository.js.map +1 -1
  93. package/dist/payment-item/interfaces/payment-item-attr.interface.d.ts +8 -0
  94. package/dist/payment-item/interfaces/payment-item-attr.interface.js +7 -0
  95. package/dist/payment-item/interfaces/payment-item-attr.interface.js.map +1 -0
  96. package/{src/payment/interfaces/payment-item.repository.interface.ts → dist/payment-item/interfaces/payment-item.repository.interface.d.ts} +0 -1
  97. package/dist/payment-item/interfaces/payment-item.repository.interface.js +3 -0
  98. package/dist/payment-item/interfaces/payment-item.repository.interface.js.map +1 -0
  99. package/dist/payment-item/payment-item.d.ts +19 -0
  100. package/dist/payment-item/payment-item.js +42 -0
  101. package/dist/payment-item/payment-item.js.map +1 -0
  102. package/dist/payment-item/payment-item.repository.d.ts +5 -0
  103. package/dist/payment-item/payment-item.repository.js +12 -0
  104. package/dist/payment-item/payment-item.repository.js.map +1 -0
  105. package/dist/payment-method/interfaces/payment-method-attr.interface.d.ts +4 -0
  106. package/dist/payment-method/interfaces/payment-method-attr.interface.js +3 -0
  107. package/dist/payment-method/interfaces/payment-method-attr.interface.js.map +1 -0
  108. package/dist/payment-method/payment-method.d.ts +17 -0
  109. package/dist/payment-method/payment-method.js +83 -0
  110. package/dist/payment-method/payment-method.js.map +1 -0
  111. package/dist/payment-method/payment-method.repository.d.ts +5 -0
  112. package/dist/payment-method/payment-method.repository.js +12 -0
  113. package/dist/payment-method/payment-method.repository.js.map +1 -0
  114. package/dist/payment-method-type/interfaces/payment-method-type-attr.interface.d.ts +8 -0
  115. package/dist/payment-method-type/interfaces/payment-method-type-attr.interface.js +3 -0
  116. package/dist/payment-method-type/interfaces/payment-method-type-attr.interface.js.map +1 -0
  117. package/dist/payment-method-type/payment-method-type.d.ts +15 -0
  118. package/dist/payment-method-type/payment-method-type.js +55 -0
  119. package/dist/payment-method-type/payment-method-type.js.map +1 -0
  120. package/dist/payment-method-type/payment-method-type.repository.d.ts +5 -0
  121. package/dist/payment-method-type/payment-method-type.repository.js +12 -0
  122. package/dist/payment-method-type/payment-method-type.repository.js.map +1 -0
  123. package/dist/tsconfig.tsbuildinfo +1 -1
  124. package/migrations/finance-account-migration.js +30 -16
  125. package/migrations/finance-company-migration.js +0 -14
  126. package/migrations/finance-payment-item-migration.js +4 -0
  127. package/migrations/finance-payment-method-migration.js +21 -0
  128. package/migrations/finance-payment-method-type-migration.js +55 -0
  129. package/migrations/finance-payment-migration.js +42 -25
  130. package/package.json +4 -4
  131. package/src/account/account.repository.ts +5 -38
  132. package/src/account/account.ts +115 -98
  133. package/src/account/interfaces/account-attr.interface.ts +15 -7
  134. package/src/account-system-entity/account-system-entity.ts +4 -4
  135. package/src/account-system-entity/post-history.repository.ts +3 -3
  136. package/src/customer/customer.ts +3 -3
  137. package/src/customer/finance-customer.repository.ts +2 -2
  138. package/src/customer/interfaces/finance-customer.repository.interface.ts +2 -2
  139. package/src/document/document-item.repository.ts +5 -43
  140. package/src/document/document-item.ts +5 -1
  141. package/src/document/document.repository.ts +5 -35
  142. package/src/document/document.ts +127 -74
  143. package/src/document/interfaces/document-item.repository.interface.ts +2 -2
  144. package/src/enum/index.ts +2 -0
  145. package/src/enum/payment-status.enum.ts +4 -0
  146. package/src/enum/transaction-type.enum.ts +2 -2
  147. package/src/finance-company/finance-company.repository.ts +3 -3
  148. package/src/finance-company/finance-company.ts +685 -48
  149. package/src/index.ts +13 -7
  150. package/src/interfaces/account-system.interface.ts +2 -2
  151. package/src/journal-entry/journal-entry.repository.ts +5 -34
  152. package/src/journal-entry/journal-entry.ts +163 -63
  153. package/src/ledger-transaction/interfaces/ledger-transaction-attr.interface.ts +0 -5
  154. package/src/ledger-transaction/ledger-transaction.repository.ts +5 -24
  155. package/src/ledger-transaction/ledger-transaction.ts +8 -12
  156. package/src/models/account.entity.ts +67 -32
  157. package/src/models/finance-company.entity.ts +0 -16
  158. package/src/models/payment-item.entity.ts +6 -0
  159. package/src/models/payment-method-type.entity.ts +70 -0
  160. package/src/models/payment-method.entity.ts +28 -0
  161. package/src/models/payment.entity.ts +86 -31
  162. package/src/payment/interfaces/payment-attr.interface.ts +11 -8
  163. package/src/payment/payment.repository.ts +5 -35
  164. package/src/payment/payment.ts +183 -181
  165. package/src/{payment → payment-item}/interfaces/payment-item-attr.interface.ts +1 -0
  166. package/src/payment-item/payment-item.repository.ts +11 -0
  167. package/src/payment-item/payment-item.ts +54 -0
  168. package/src/payment-method/interfaces/payment-method-attr.interface.ts +4 -0
  169. package/src/payment-method/payment-method.repository.ts +11 -0
  170. package/src/payment-method/payment-method.ts +95 -0
  171. package/src/payment-method-type/interfaces/payment-method-type-attr.interface.ts +8 -0
  172. package/src/payment-method-type/payment-method-type.repository.ts +11 -0
  173. package/src/payment-method-type/payment-method-type.ts +58 -0
  174. package/src/account/interfaces/account.repository.interface.ts +0 -4
  175. package/src/document/interfaces/document.repository.interface.ts +0 -4
  176. package/src/journal-entry/interfaces/journal-entry.repository.interface.ts +0 -11
  177. package/src/payment/interfaces/payment.repository.interface.ts +0 -4
  178. package/src/payment/payment-item.repository.ts +0 -49
@@ -1,32 +1,43 @@
1
1
  import axios from 'axios';
2
+ import * as cuid from 'cuid';
2
3
  import {
3
4
  HashTable,
4
- IBaseRepository,
5
5
  LoginUserBase,
6
6
  ObjectBase,
7
+ RecordNotFoundError,
7
8
  } from '@tomei/general';
8
- import { BadRequestException } from '@nestjs/common';
9
+ import Account from '../account/account';
10
+ import JournalEntry from '../journal-entry/journal-entry';
11
+ import FinanceCustomerBase from '../customer/customer';
12
+ import Document from '../document/document';
9
13
  import { IAccountSystem } from '../interfaces';
10
- import * as cuid from 'cuid';
11
14
  import { FinanceCompanyRepository } from './finance-company.repository';
12
15
  import { FinanceCustomerRepository } from '../customer/finance-customer.repository';
13
- import { JournalEntryRepository } from '../journal-entry/journal-entry.repository';
14
- import { Account } from '../account/account';
15
16
  import { LedgerTransactionRepository } from '../ledger-transaction/ledger-transaction.repository';
16
- import { FinanceCustomerBase } from '../customer/customer';
17
- import { JournalEntry } from '../journal-entry/journal-entry';
17
+ import { DocType, TransactionTypeOptions } from '../enum';
18
+ import PaymentMethodType from '../payment-method-type/payment-method-type';
19
+ import { PaymentRepository } from '../payment/payment.repository';
20
+ import { PaymentItemRepository } from '../payment-item/payment-item.repository';
21
+ import Payment from '../payment/payment';
22
+ import { DocumentRepository } from '../document/document.repository';
23
+ import { DocumentItemRepository } from '../document/document-item.repository';
24
+
25
+ const { getConfig } = require('../config');
26
+ const config = getConfig();
18
27
 
19
28
  export default class FinanceCompany extends ObjectBase {
20
29
  private _CompanyId = 'New';
21
30
  private _CompSystemCode = '';
22
31
  private _CompSystemRefId = '';
23
32
  private _AccSystemCode = '';
24
- private _AccSystemRefId = '';
25
- protected BaseRepository: IBaseRepository;
26
33
  private static _htFinanceCompanyIds = new HashTable();
27
34
  private static _htFinanceCompanies = new HashTable();
28
- private static financeCompanyRepository = new FinanceCompanyRepository();
29
- journalEntryRepository: JournalEntryRepository;
35
+ private static _financeCompanyRepository = new FinanceCompanyRepository();
36
+ private static _PaymentRepository = new PaymentRepository();
37
+ private static _PaymentItemRepository = new PaymentItemRepository();
38
+ private static _DocumentRepository = new DocumentRepository();
39
+ private static _DocumentItemRepository = new DocumentItemRepository();
40
+
30
41
  financeCustomerRepository: FinanceCustomerRepository;
31
42
  ledgerTransactionRepository: LedgerTransactionRepository;
32
43
  AccountingSystem: IAccountSystem;
@@ -55,10 +66,6 @@ export default class FinanceCompany extends ObjectBase {
55
66
  this._AccSystemCode = code;
56
67
  }
57
68
 
58
- get AccSystemRefId() {
59
- return this._AccSystemRefId;
60
- }
61
-
62
69
  get CompanyId() {
63
70
  return this._CompanyId;
64
71
  }
@@ -109,7 +116,7 @@ export default class FinanceCompany extends ObjectBase {
109
116
 
110
117
  /*Retrieve the finance company from finance_Company table using compSystemCode,
111
118
  * CompSystemRefId and accSystemCode */
112
- const company = await FinanceCompany.financeCompanyRepository.findOne({
119
+ const company = await FinanceCompany._financeCompanyRepository.findOne({
113
120
  where: {
114
121
  CompSystemCode: compSystemCode,
115
122
  CompSystemRefId: compSystemRefId,
@@ -138,7 +145,7 @@ export default class FinanceCompany extends ObjectBase {
138
145
  if (!FinanceCompany._htFinanceCompanies.get(companyId)) {
139
146
  /*Retrieve the finance company from finance_Company table using compSystemCode,
140
147
  * CompSystemRefId and accSystemCode */
141
- const company = await FinanceCompany.financeCompanyRepository.findOne({
148
+ const company = await FinanceCompany._financeCompanyRepository.findOne({
142
149
  where: { CompanyId: companyId },
143
150
  });
144
151
 
@@ -188,7 +195,7 @@ export default class FinanceCompany extends ObjectBase {
188
195
  );
189
196
 
190
197
  /*Validating if the finance company already exists in finance_Company*/
191
- const company = await FinanceCompany.financeCompanyRepository.findOne({
198
+ const company = await FinanceCompany._financeCompanyRepository.findOne({
192
199
  where: {
193
200
  CompSystemCode: compSystemCode,
194
201
  CompSystemRefId: compSystemRefId,
@@ -206,13 +213,12 @@ export default class FinanceCompany extends ObjectBase {
206
213
  financeCompany.ObjectId = cuid();
207
214
 
208
215
  /*Save the FinanceCompany to the finance_Company table*/
209
- await FinanceCompany.financeCompanyRepository.create(
216
+ await FinanceCompany._financeCompanyRepository.create(
210
217
  {
211
218
  CompanyId: financeCompany.CompanyId,
212
219
  CompSystemCode: financeCompany.CompSystemCode,
213
220
  CompSystemRefId: financeCompany.CompSystemRefId,
214
221
  AccSystemCode: financeCompany.AccSystemCode,
215
- AccSystemRefId: financeCompany.AccSystemRefId,
216
222
  },
217
223
  {
218
224
  transaction: dbTransaction,
@@ -236,7 +242,7 @@ export default class FinanceCompany extends ObjectBase {
236
242
  ) {
237
243
  try {
238
244
  if (customer.CustSystemCode || customer.CustSystemRefId) {
239
- throw new BadRequestException(
245
+ throw new Error(
240
246
  'CustSystemCode and CustomerRefId are required fields.',
241
247
  );
242
248
  }
@@ -252,7 +258,7 @@ export default class FinanceCompany extends ObjectBase {
252
258
  });
253
259
 
254
260
  if (financeCustomerData) {
255
- throw new BadRequestException('Customer already created previously.');
261
+ throw new Error('Customer already created previously.');
256
262
  }
257
263
 
258
264
  // Retrieve the type of accounting system, API Key, and API secret based on SysCode from the Config.ts
@@ -274,10 +280,7 @@ export default class FinanceCompany extends ObjectBase {
274
280
  EntityId: newCustomer.CustomerId,
275
281
  };
276
282
 
277
- await axios.post(
278
- `${process.env.COMMON_API_URL}/activity-histories`,
279
- payload,
280
- );
283
+ await axios.post(`${config.commonApiUrl}/activity-histories`, payload);
281
284
 
282
285
  return customer;
283
286
  } catch (error) {
@@ -286,27 +289,26 @@ export default class FinanceCompany extends ObjectBase {
286
289
  }
287
290
 
288
291
  async postJournal(dbTransaction: any, journalEntry: JournalEntry) {
292
+ const debitTransactions = await journalEntry.DebitTransactions;
293
+ const creditTransactions = await journalEntry.CreditTransactions;
289
294
  try {
290
- if (
291
- journalEntry.CreditTransactions?.length < 1 ||
292
- journalEntry.DebitTransactions?.length < 1
293
- ) {
294
- throw new BadRequestException(
295
+ if (creditTransactions.length < 1 || debitTransactions?.length < 1) {
296
+ throw new Error(
295
297
  'There should be at least 1 debit ledger transaction and 1 credit ledger transaction in the journal entry',
296
298
  );
297
299
  }
298
300
 
299
- const totalCreditAmount = journalEntry.CreditTransactions.reduce(
301
+ const totalCreditAmount = creditTransactions.reduce(
300
302
  (accumulator, currentValue) => accumulator + currentValue.CreditAmount,
301
303
  0,
302
304
  );
303
- const totalDebitAmount = journalEntry.DebitTransactions.reduce(
305
+ const totalDebitAmount = debitTransactions.reduce(
304
306
  (accumulator, currentValue) => accumulator + currentValue.DebitAmount,
305
307
  0,
306
308
  );
307
309
 
308
310
  if (totalCreditAmount !== totalDebitAmount) {
309
- throw new BadRequestException(
311
+ throw new Error(
310
312
  'Credit ledger transaction and debit ledger transaction should the same amount',
311
313
  );
312
314
  }
@@ -314,7 +316,7 @@ export default class FinanceCompany extends ObjectBase {
314
316
  const newJournalEntry = await journalEntry.save('test', dbTransaction);
315
317
 
316
318
  const allLedgerTransactions =
317
- await this.ledgerTransactionRepository.findAll();
319
+ await this.ledgerTransactionRepository.findAll({});
318
320
 
319
321
  for (const ledgerTransaction of allLedgerTransactions) {
320
322
  ledgerTransaction.JournalEntryId = newJournalEntry.JournalEntryId;
@@ -335,10 +337,7 @@ export default class FinanceCompany extends ObjectBase {
335
337
  EntityId: newJournalEntry.JournalEntryId,
336
338
  };
337
339
 
338
- await axios.post(
339
- `${process.env.COMMON_API_URL}/activity-histories`,
340
- payload,
341
- );
340
+ await axios.post(`${config.commonApiUrl}/activity-histories`, payload);
342
341
  } catch (error) {
343
342
  throw error;
344
343
  }
@@ -349,17 +348,17 @@ export default class FinanceCompany extends ObjectBase {
349
348
  account.validateAccountValue();
350
349
 
351
350
  let createAccountPayload: any = {
352
- Name: account.name,
351
+ Name: account.Name,
353
352
  AcctNum: account.AccountNo,
354
- AccountType: account.accountType,
355
- AccountSubType: account.accountSubType,
353
+ AccountType: account.AccountType,
354
+ AccountSubType: account.AccountSubtype,
356
355
  };
357
356
 
358
- if (account.isParentAccountExsits()) {
357
+ if (account.isParentAccountExists()) {
359
358
  createAccountPayload = {
360
359
  ...createAccountPayload,
361
360
  CurrencyRef: 'MYR',
362
- ParentRef: account.parentAccountNo,
361
+ ParentRef: account.ParentAccountNo,
363
362
  SubAccount: true,
364
363
  };
365
364
  }
@@ -386,14 +385,652 @@ export default class FinanceCompany extends ObjectBase {
386
385
  EntityId: newAccount.AccountNo,
387
386
  };
388
387
 
389
- await axios.post(
390
- `${process.env.COMMON_API_URL}/activity-histories`,
391
- payload,
392
- );
388
+ await axios.post(`${config.commonApiUrl}/activity-histories`, payload);
393
389
 
394
390
  return account;
395
391
  } catch (error) {
396
392
  throw error;
397
393
  }
398
394
  }
395
+
396
+ /**
397
+ * Issue an invoice
398
+ *
399
+ * @param dbTransaction - The database transaction to be used
400
+ * @param loginUser - The user issuing the invoice
401
+ * @param invoice - The document containing the invoice details
402
+ * @param customer - The customer to be issued the invoice
403
+ * @param dtAccountNo - The account number of the Account Receivable (AR) account to debit. If not provided, will debit the customer's default AR account
404
+ *
405
+ * @returns {Document} - Document object representing the full details of the invoice issued
406
+ */
407
+ async issueInvoice(
408
+ dbTransaction: any,
409
+ loginUser: LoginUserBase,
410
+ invoice: Document,
411
+ customer: FinanceCustomerBase,
412
+ dtAccountNo?: string,
413
+ ): Promise<Document> {
414
+ try {
415
+ /*Check if the invoice number already exists (should be unique)*/
416
+ const duplicateInvoice = await FinanceCompany._DocumentRepository.findOne(
417
+ {
418
+ where: {
419
+ DocNo: invoice.DocNo,
420
+ },
421
+ transaction: dbTransaction,
422
+ },
423
+ );
424
+
425
+ if (duplicateInvoice) {
426
+ throw new Error('Invoice number already exists');
427
+ }
428
+
429
+ const documentItems = await invoice.DocumentItems;
430
+
431
+ /*Check if the document has at least 1 document item*/
432
+ if (!documentItems.length) {
433
+ throw new Error('Document must have at least 1 document item');
434
+ }
435
+
436
+ /*Check if each document item has CtAccountNo provided*/
437
+ for (const invoiceItem of documentItems) {
438
+ if (!invoiceItem.CtAccountNo) {
439
+ throw new Error(
440
+ 'Each document item should have CtAccountNo provided',
441
+ );
442
+ }
443
+ }
444
+
445
+ /*Set up the document type*/
446
+ invoice.DocType = DocType.INVOICE;
447
+
448
+ /*Saving the document and document items to the database*/
449
+ await FinanceCompany._DocumentRepository.create(
450
+ {
451
+ DocNo: invoice.DocNo,
452
+ DocType: invoice.DocType,
453
+ DocDate: invoice.DocDate,
454
+ CompanyId: invoice.CompanyId,
455
+ Currency: invoice.Currency,
456
+ Amount: invoice.Amount,
457
+ Description: invoice.Description,
458
+ Status: invoice.Status,
459
+ IssuedById: loginUser.ObjectId,
460
+ IssuedToId: customer.ObjectId,
461
+ IssuedToType: invoice.IssuedToType,
462
+ CreatedById: loginUser.ObjectId,
463
+ CreatedAt: new Date(),
464
+ UpdatedById: loginUser.ObjectId,
465
+ UpdatedAt: new Date(),
466
+ DocPDFFileMediaId: invoice.DocPDFFileMediaId,
467
+ DocHTMLFileMediaId: invoice.DocHTMLFileMediaId,
468
+ AccSystemRefId: invoice.AccSystemRefId,
469
+ PostedToAccSystemYN: invoice.PostedToAccSystemYN,
470
+ PostedById: invoice.PostedById,
471
+ PostedDateTime: new Date(),
472
+ UseAccSystemDocYN: invoice.UseAccSystemDocYN,
473
+ },
474
+ {
475
+ transaction: dbTransaction,
476
+ },
477
+ );
478
+
479
+ documentItems.forEach(async (documentItem) => {
480
+ await FinanceCompany._DocumentItemRepository.create(
481
+ {
482
+ DocumentItemId: documentItem.DocumentItemId,
483
+ DocNo: documentItem.DocNo,
484
+ Name: documentItem.Name,
485
+ NameBM: documentItem.NameBM,
486
+ Description: documentItem.Description,
487
+ ItemId: documentItem.ItemId,
488
+ ItemType: documentItem.ItemType,
489
+ ItemSKU: documentItem.ItemSKU,
490
+ ItemSerialNo: documentItem.ItemSerialNo,
491
+ Currency: documentItem.Currency,
492
+ UnitPrice: documentItem.UnitPrice,
493
+ Quantity: documentItem.Quantity,
494
+ QuantityUOM: documentItem.QuantityUOM,
495
+ Amount: documentItem.Amount,
496
+ TaxCode: documentItem.TaxCode,
497
+ TaxAmount: documentItem.TaxAmount,
498
+ TaxRate: documentItem.TaxRate,
499
+ TaxInclusiveYN: documentItem.TaxInclusiveYN,
500
+ DtAccountNo: documentItem.DtAccountNo,
501
+ CtAccountNo: documentItem.CtAccountNo,
502
+ },
503
+ {
504
+ transaction: dbTransaction,
505
+ },
506
+ );
507
+ });
508
+
509
+ /*Generating the invoice*/
510
+ if (invoice.UseAccSystemDocYN) {
511
+ /*todo: Posting to accounting system to generate invoice*/
512
+ await this.AccountingSystem.createInvoice(invoice);
513
+ } else {
514
+ /*todo: check config file to see which invoice template is to be used for specific project*/
515
+
516
+ /*Generating invoice based on template*/
517
+ invoice.generateInvoice(loginUser.IDNo, customer);
518
+ }
519
+
520
+ const journalEntry = new JournalEntry(dbTransaction);
521
+ const transactionDate = new Date();
522
+
523
+ const ledgerTransaction = await journalEntry.newLedgerTransaction(
524
+ TransactionTypeOptions.DEBIT,
525
+ );
526
+
527
+ if (dtAccountNo) {
528
+ /*Transacting using AR account provided*/
529
+ ledgerTransaction.AccountNo = dtAccountNo;
530
+ } else {
531
+ /*Transacting based on default customer AR account*/
532
+ ledgerTransaction.AccountNo = customer.CustSystemCode + '-AR';
533
+ }
534
+
535
+ ledgerTransaction.Currency = invoice.Currency;
536
+ ledgerTransaction.DebitAmount = invoice.Amount;
537
+ ledgerTransaction.Date = transactionDate;
538
+ ledgerTransaction.Name = invoice.DocNo;
539
+
540
+ for (const invoiceItem of documentItems) {
541
+ const itemLedger = await journalEntry.newLedgerTransaction(
542
+ TransactionTypeOptions.CREDIT,
543
+ );
544
+ itemLedger.AccountNo = invoiceItem.CtAccountNo;
545
+ itemLedger.Currency = invoiceItem.Currency;
546
+ itemLedger.CreditAmount = invoiceItem.Amount;
547
+ itemLedger.Date = transactionDate;
548
+ itemLedger.Name = invoiceItem.Name;
549
+ }
550
+
551
+ this.postJournal(dbTransaction, journalEntry);
552
+
553
+ const payload = {
554
+ Action: 'Create',
555
+ Activity: 'Issuing an Invoice',
556
+ Description: `Ledger Transaction (ID: ${ledgerTransaction.TransactionId}) has been created`,
557
+ EntityType: 'LedgerTransaction',
558
+ EntityValueBefore: JSON.stringify({}),
559
+ EntityValueAfter: JSON.stringify(ledgerTransaction),
560
+ PerformedById: 'test',
561
+ PerformedAt: new Date(),
562
+ EntityId: ledgerTransaction.TransactionId,
563
+ };
564
+
565
+ await axios.post(`${config.commonApiUrl}/activity-histories`, payload);
566
+
567
+ return invoice;
568
+ } catch (err) {
569
+ // tslint:disable-next-line:no-console
570
+ console.log('Issue invoice err: ', err);
571
+ throw err;
572
+ }
573
+ }
574
+
575
+ /**
576
+ * Issue a debit note
577
+ *
578
+ * @param dbTransaction - The database transaction to be used
579
+ * @param loginUser - The user issuing the invoice
580
+ * @param invoice - The document containing the invoice details
581
+ * @param customer - The customer to be issued the invoice
582
+ * @param dtAccountNo - The account number of the Account Receivable (AR) account to debit. If not provided, will debit the customer's default AR account
583
+ *
584
+ * @returns {Document} - Document object representing the full details of the invoice issued
585
+ */
586
+ async issueDebitNote(
587
+ dbTransaction: any,
588
+ loginUser: LoginUserBase,
589
+ invoice: Document,
590
+ customer: FinanceCustomerBase,
591
+ dtAccountNo?: string,
592
+ ): Promise<Document> {
593
+ try {
594
+ /*Check if the invoice number already exists (should be unique)*/
595
+ const duplicateInvoice = await FinanceCompany._DocumentRepository.findOne(
596
+ {
597
+ where: {
598
+ DocNo: invoice.DocNo,
599
+ },
600
+ transaction: dbTransaction,
601
+ },
602
+ );
603
+
604
+ if (duplicateInvoice) {
605
+ throw new Error('Invoice number already exists');
606
+ }
607
+
608
+ const documentItems = await invoice.DocumentItems;
609
+
610
+ /*Check if the document has at least 1 document item*/
611
+ if (!documentItems.length) {
612
+ throw new Error('Document must have at least 1 document item');
613
+ }
614
+
615
+ /*Check if each document item has CtAccountNo provided*/
616
+ for (const invoiceItem of documentItems) {
617
+ if (!invoiceItem.CtAccountNo) {
618
+ throw new Error(
619
+ 'Each document item should have CtAccountNo provided',
620
+ );
621
+ }
622
+ }
623
+
624
+ /*Set up the document type*/
625
+ invoice.DocType = DocType.DEBIT_NOTE;
626
+
627
+ /*Saving the document and document items to the database*/
628
+ await FinanceCompany._DocumentRepository.create(
629
+ {
630
+ DocNo: invoice.DocNo,
631
+ DocType: invoice.DocType,
632
+ DocDate: invoice.DocDate,
633
+ CompanyId: invoice.CompanyId,
634
+ Currency: invoice.Currency,
635
+ Amount: invoice.Amount,
636
+ Description: invoice.Description,
637
+ Status: invoice.Status,
638
+ IssuedById: loginUser.ObjectId,
639
+ IssuedToId: customer.ObjectId,
640
+ IssuedToType: invoice.IssuedToType,
641
+ CreatedById: loginUser.ObjectId,
642
+ CreatedAt: new Date(),
643
+ UpdatedById: loginUser.ObjectId,
644
+ UpdatedAt: new Date(),
645
+ DocPDFFileMediaId: invoice.DocPDFFileMediaId,
646
+ DocHTMLFileMediaId: invoice.DocHTMLFileMediaId,
647
+ AccSystemRefId: invoice.AccSystemRefId,
648
+ PostedToAccSystemYN: invoice.PostedToAccSystemYN,
649
+ PostedById: invoice.PostedById,
650
+ PostedDateTime: new Date(),
651
+ UseAccSystemDocYN: invoice.UseAccSystemDocYN,
652
+ },
653
+ {
654
+ transaction: dbTransaction,
655
+ },
656
+ );
657
+
658
+ documentItems.forEach(async (documentItem) => {
659
+ await FinanceCompany._DocumentItemRepository.create(
660
+ {
661
+ DocumentItemId: documentItem.DocumentItemId,
662
+ DocNo: documentItem.DocNo,
663
+ Name: documentItem.Name,
664
+ NameBM: documentItem.NameBM,
665
+ Description: documentItem.Description,
666
+ ItemId: documentItem.ItemId,
667
+ ItemType: documentItem.ItemType,
668
+ ItemSKU: documentItem.ItemSKU,
669
+ ItemSerialNo: documentItem.ItemSerialNo,
670
+ Currency: documentItem.Currency,
671
+ UnitPrice: documentItem.UnitPrice,
672
+ Quantity: documentItem.Quantity,
673
+ QuantityUOM: documentItem.QuantityUOM,
674
+ Amount: documentItem.Amount,
675
+ TaxCode: documentItem.TaxCode,
676
+ TaxAmount: documentItem.TaxAmount,
677
+ TaxRate: documentItem.TaxRate,
678
+ TaxInclusiveYN: documentItem.TaxInclusiveYN,
679
+ DtAccountNo: documentItem.DtAccountNo,
680
+ CtAccountNo: documentItem.CtAccountNo,
681
+ },
682
+ {
683
+ transaction: dbTransaction,
684
+ },
685
+ );
686
+ });
687
+
688
+ /*Generating the invoice*/
689
+ if (invoice.UseAccSystemDocYN) {
690
+ /*todo: Posting to accounting system to generate invoice*/
691
+ await this.AccountingSystem.createInvoice(invoice);
692
+ } else {
693
+ /*todo: check config file to see which invoice template is to be used for specific project*/
694
+
695
+ /*Generating invoice based on template*/
696
+ invoice.generateInvoice(loginUser.IDNo, customer);
697
+ }
698
+
699
+ const journalEntry = new JournalEntry(dbTransaction);
700
+ const transactionDate = new Date();
701
+
702
+ const debitTransaction = await journalEntry.newLedgerTransaction(
703
+ TransactionTypeOptions.DEBIT,
704
+ );
705
+
706
+ if (dtAccountNo) {
707
+ /*Transacting using AR account provided*/
708
+ debitTransaction.AccountNo = dtAccountNo;
709
+ } else {
710
+ /*Transacting based on default customer AR account*/
711
+ debitTransaction.AccountNo = customer.CustSystemCode + '-AR';
712
+ }
713
+
714
+ debitTransaction.Currency = invoice.Currency;
715
+ debitTransaction.DebitAmount = invoice.Amount;
716
+ debitTransaction.Date = transactionDate;
717
+ debitTransaction.Name = invoice.DocNo;
718
+
719
+ for (const invoiceItem of documentItems) {
720
+ const itemLedger = await journalEntry.newLedgerTransaction(
721
+ TransactionTypeOptions.CREDIT,
722
+ );
723
+ itemLedger.AccountNo = invoiceItem.CtAccountNo;
724
+ itemLedger.Currency = invoiceItem.Currency;
725
+ itemLedger.CreditAmount = invoiceItem.Amount;
726
+ itemLedger.Date = transactionDate;
727
+ itemLedger.Name = invoiceItem.Name;
728
+ }
729
+
730
+ this.postJournal(dbTransaction, journalEntry);
731
+
732
+ const payload = {
733
+ Action: 'Create',
734
+ Activity: 'Issuing a Debit Note',
735
+ Description: `Debit Transaction (ID: ${debitTransaction.TransactionId}) has been created`,
736
+ EntityType: 'DebitTransaction',
737
+ EntityValueBefore: JSON.stringify({}),
738
+ EntityValueAfter: JSON.stringify(debitTransaction),
739
+ PerformedById: 'test',
740
+ PerformedAt: new Date(),
741
+ EntityId: debitTransaction.TransactionId,
742
+ };
743
+
744
+ await axios.post(`${config.commonApiUrl}/activity-histories`, payload);
745
+
746
+ return invoice;
747
+ } catch (err) {
748
+ // tslint:disable-next-line:no-console
749
+ console.log('Issue debit note err: ', err);
750
+ throw err;
751
+ }
752
+ }
753
+
754
+ /**
755
+ * Issue a credit note
756
+ *
757
+ * @param dbTransaction - The database transaction to be used
758
+ * @param loginUser - The user issuing the credit note
759
+ * @param creditNote - The document containing the credit note details
760
+ * @param customer - The customer to be issued the credit note
761
+ * @param ctAccountNo - The account number of the Account Payable (AP) account to debit. If not provided, will debit the customer's default AR account
762
+ *
763
+ * @returns {Document} - Document object representing the full details of the invoice issued
764
+ */
765
+ async issueCreditNote(
766
+ dbTransaction: any,
767
+ loginUser: LoginUserBase,
768
+ creditNote: Document,
769
+ customer: FinanceCustomerBase,
770
+ ctAccountNo?: string,
771
+ ): Promise<Document> {
772
+ try {
773
+ /*Check if the invoice number already exists (should be unique)*/
774
+ const duplicateCreditNote =
775
+ await FinanceCompany._DocumentRepository.findOne({
776
+ where: {
777
+ DocNo: creditNote.DocNo,
778
+ },
779
+ transaction: dbTransaction,
780
+ });
781
+
782
+ if (duplicateCreditNote) {
783
+ throw new Error('Invoice number already exists');
784
+ }
785
+
786
+ const documentItems = await creditNote.DocumentItems;
787
+
788
+ /*Check if the document has at least 1 document item*/
789
+ if (!documentItems.length) {
790
+ throw new Error('Document must have at least 1 document item');
791
+ }
792
+
793
+ /*Check if each document item has CtAccountNo provided*/
794
+ for (const invoiceItem of documentItems) {
795
+ if (!invoiceItem.CtAccountNo) {
796
+ throw new Error(
797
+ 'Each document item should have CtAccountNo provided',
798
+ );
799
+ }
800
+ }
801
+
802
+ /*Set up the document type*/
803
+ creditNote.DocType = DocType.DEBIT_NOTE;
804
+
805
+ /*Saving the document and document items to the database*/
806
+ await FinanceCompany._DocumentRepository.create(
807
+ {
808
+ DocNo: creditNote.DocNo,
809
+ DocType: creditNote.DocType,
810
+ DocDate: creditNote.DocDate,
811
+ CompanyId: creditNote.CompanyId,
812
+ Currency: creditNote.Currency,
813
+ Amount: creditNote.Amount,
814
+ Description: creditNote.Description,
815
+ Status: creditNote.Status,
816
+ IssuedById: loginUser.ObjectId,
817
+ IssuedToId: customer.ObjectId,
818
+ IssuedToType: creditNote.IssuedToType,
819
+ CreatedById: loginUser.ObjectId,
820
+ CreatedAt: new Date(),
821
+ UpdatedById: loginUser.ObjectId,
822
+ UpdatedAt: new Date(),
823
+ DocPDFFileMediaId: creditNote.DocPDFFileMediaId,
824
+ DocHTMLFileMediaId: creditNote.DocHTMLFileMediaId,
825
+ AccSystemRefId: creditNote.AccSystemRefId,
826
+ PostedToAccSystemYN: creditNote.PostedToAccSystemYN,
827
+ PostedById: creditNote.PostedById,
828
+ PostedDateTime: new Date(),
829
+ UseAccSystemDocYN: creditNote.UseAccSystemDocYN,
830
+ },
831
+ {
832
+ transaction: dbTransaction,
833
+ },
834
+ );
835
+
836
+ documentItems.forEach(async (documentItem) => {
837
+ await FinanceCompany._DocumentItemRepository.create(
838
+ {
839
+ DocumentItemId: documentItem.DocumentItemId,
840
+ DocNo: documentItem.DocNo,
841
+ Name: documentItem.Name,
842
+ NameBM: documentItem.NameBM,
843
+ Description: documentItem.Description,
844
+ ItemId: documentItem.ItemId,
845
+ ItemType: documentItem.ItemType,
846
+ ItemSKU: documentItem.ItemSKU,
847
+ ItemSerialNo: documentItem.ItemSerialNo,
848
+ Currency: documentItem.Currency,
849
+ UnitPrice: documentItem.UnitPrice,
850
+ Quantity: documentItem.Quantity,
851
+ QuantityUOM: documentItem.QuantityUOM,
852
+ Amount: documentItem.Amount,
853
+ TaxCode: documentItem.TaxCode,
854
+ TaxAmount: documentItem.TaxAmount,
855
+ TaxRate: documentItem.TaxRate,
856
+ TaxInclusiveYN: documentItem.TaxInclusiveYN,
857
+ DtAccountNo: documentItem.DtAccountNo,
858
+ CtAccountNo: documentItem.CtAccountNo,
859
+ },
860
+ {
861
+ transaction: dbTransaction,
862
+ },
863
+ );
864
+ });
865
+
866
+ /*Generating the credit note*/
867
+ if (creditNote.UseAccSystemDocYN) {
868
+ /*todo: Posting to accounting system to generate creditNote*/
869
+ await this.AccountingSystem.createCreditNote(creditNote);
870
+ } else {
871
+ /*todo: check config file to see which invoice template is to be used for specific project*/
872
+
873
+ /*Generating credit note based on template*/
874
+ creditNote.generateCreditNote(loginUser.IDNo, customer);
875
+ }
876
+
877
+ const journalEntry = new JournalEntry(dbTransaction);
878
+ const transactionDate = new Date();
879
+
880
+ const creditTransaction = await journalEntry.newLedgerTransaction(
881
+ TransactionTypeOptions.CREDIT,
882
+ );
883
+
884
+ if (ctAccountNo) {
885
+ /*Transacting using AR account provided*/
886
+ creditTransaction.AccountNo = ctAccountNo;
887
+ } else {
888
+ /*Transacting based on default customer AR account*/
889
+ creditTransaction.AccountNo = customer.CustSystemCode + '-AP';
890
+ }
891
+
892
+ creditTransaction.Currency = creditNote.Currency;
893
+ creditTransaction.DebitAmount = creditNote.Amount;
894
+ creditTransaction.Date = transactionDate;
895
+ creditTransaction.Name = creditNote.DocNo;
896
+
897
+ for (const invoiceItem of documentItems) {
898
+ const itemLedger = await journalEntry.newLedgerTransaction(
899
+ TransactionTypeOptions.CREDIT,
900
+ );
901
+ itemLedger.AccountNo = invoiceItem.CtAccountNo;
902
+ itemLedger.Currency = invoiceItem.Currency;
903
+ itemLedger.CreditAmount = invoiceItem.Amount;
904
+ itemLedger.Date = transactionDate;
905
+ itemLedger.Name = invoiceItem.Name;
906
+ }
907
+
908
+ this.postJournal(dbTransaction, journalEntry);
909
+
910
+ const payload = {
911
+ Action: 'Create',
912
+ Activity: 'Issuing a Credit Note Transaction',
913
+ Description: `Credit Transaction (ID: ${creditTransaction.TransactionId}) has been created`,
914
+ EntityType: 'CreditTransaction',
915
+ EntityValueBefore: JSON.stringify({}),
916
+ EntityValueAfter: JSON.stringify(creditTransaction),
917
+ PerformedById: 'test',
918
+ PerformedAt: transactionDate,
919
+ EntityId: creditTransaction.TransactionId,
920
+ };
921
+
922
+ await axios.post(`${config.commonApiUrl}/activity-histories`, payload);
923
+
924
+ return creditNote;
925
+ } catch (err) {
926
+ // tslint:disable-next-line:no-console
927
+ console.log('Issue credit note err: ', err);
928
+ throw err;
929
+ }
930
+ }
931
+
932
+ /**
933
+ * Register a payment collected
934
+ *
935
+ * @param dbTransaction - The database transaction to be used
936
+ * @param loginUser - The user collecting the payment
937
+ * @param payment - The payment object containing payment details
938
+ * @param customer - The customer making the payment
939
+ * @param ctAccountNo - The customer's Account Receivable (AR) account to credit
940
+ *
941
+ * @returns {Payment} - Payment object representing the full detals of the payment collection recorded
942
+ */
943
+ async collectPayment(
944
+ dbTransaction: any,
945
+ loginUser: LoginUserBase,
946
+ payment: Payment,
947
+ customer: FinanceCustomerBase,
948
+ ctAccountNo?: string,
949
+ ): Promise<Payment> {
950
+ let paymentMethodType: PaymentMethodType;
951
+ try {
952
+ paymentMethodType = new PaymentMethodType(
953
+ dbTransaction,
954
+ payment.MethodTypeId,
955
+ );
956
+
957
+ const paymentItems = await payment.PaymentItems;
958
+ if (paymentItems.length < 1) {
959
+ throw new Error(
960
+ 'Atleast one payment item is required to identify what payment is being paid for',
961
+ );
962
+ }
963
+
964
+ payment.PaymentId = cuid();
965
+
966
+ await FinanceCompany._PaymentRepository.create({
967
+ PaymentId: payment.PaymentId,
968
+ PaymentType: payment.PaymentType,
969
+ PaymentDate: payment.PaymentDate,
970
+ CompanyId: this.CompanyId,
971
+ MethodTypeId: payment.MethodTypeId,
972
+ Currency: payment.Currency,
973
+ Amount: payment.Amount,
974
+ Status: payment.Status,
975
+ TransactionId: payment.TransactionId,
976
+ TransactionApprovalCode: payment.TransactionApprovalCode,
977
+ TransactionAccountName: payment.TransactionAccountName,
978
+ TransactionAccountNo: payment.TransactionAccountNo,
979
+ ReceivedBy: payment.ReceivedBy,
980
+ UpdatedAt: new Date(),
981
+ UpdatedBy: loginUser.ObjectId,
982
+ CreatedAt: new Date(),
983
+ CreatedBy: loginUser.ObjectId,
984
+ });
985
+
986
+ paymentItems.forEach(async (paymentItem) => {
987
+ await FinanceCompany._PaymentItemRepository.create({
988
+ PaymentId: payment.PaymentId,
989
+ PayForObjectId: paymentItem.PayForObjectId,
990
+ PayForObjectType: paymentItem.PayForObjectType,
991
+ Currency: paymentItem.Currency,
992
+ Amount: paymentItem.Amount,
993
+ });
994
+ });
995
+
996
+ const journalEntry = new JournalEntry(dbTransaction);
997
+ const transactionDate = new Date();
998
+
999
+ const debitLT = await journalEntry.newLedgerTransaction(
1000
+ TransactionTypeOptions.DEBIT,
1001
+ );
1002
+ debitLT.AccountNo = paymentMethodType.AccountNo;
1003
+ debitLT.Currency = payment.Currency;
1004
+ debitLT.CreditAmount = payment.Amount;
1005
+ debitLT.Date = transactionDate;
1006
+ debitLT.Name = customer.FullName;
1007
+
1008
+ const creditLT = await journalEntry.newLedgerTransaction(
1009
+ TransactionTypeOptions.CREDIT,
1010
+ );
1011
+
1012
+ if (ctAccountNo) {
1013
+ creditLT.AccountNo = ctAccountNo;
1014
+ } else {
1015
+ // const config = getConfig();
1016
+ creditLT.AccountNo = customer.CustSystemCode + '-AR';
1017
+ }
1018
+ creditLT.Currency = payment.Currency;
1019
+ creditLT.DebitAmount = payment.Amount;
1020
+ creditLT.Date = transactionDate;
1021
+ creditLT.Name = paymentMethodType.Name;
1022
+
1023
+ await this.postJournal(dbTransaction, journalEntry);
1024
+
1025
+ /*todo: saving a record into the activity history table*/
1026
+
1027
+ return payment;
1028
+ } catch (error) {
1029
+ if (error instanceof RecordNotFoundError) {
1030
+ throw new Error('Invalid PaymentMethodType id');
1031
+ } else {
1032
+ throw error;
1033
+ }
1034
+ }
1035
+ }
399
1036
  }