From e7e7a95aa18173f4c0afa24b8822ce0e34df3ba8 Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Tue, 14 Jan 2025 22:57:54 +0200 Subject: [PATCH] refactor: dynamic list to nestjs --- packages/server-nest/package.json | 3 +- packages/server-nest/src/interfaces/Model.ts | 2 + .../logic-evaluation/{Lexer.js => Lexer.ts} | 4 + .../logic-evaluation/{Parser.js => Parser.ts} | 5 +- .../{QueryParser.js => QueryParser.ts} | 5 +- .../modules/Accounts/Accounts.constants.ts | 32 ++-- .../modules/Accounts/DeleteAccount.service.ts | 2 +- .../modules/Accounts/GetAccounts.service.ts | 2 +- .../modules/Accounts/models/Account.model.ts | 29 ++-- .../repositories/Account.repository.ts | 4 +- .../BankingPlaid/command/PlaidSyncDB.ts | 13 +- .../BankingTransactions/models/BankAccount.ts | 6 +- .../queries/BankAccountTransformer.ts | 8 +- .../queries/GetBankAccounts.service.ts | 2 +- .../src/modules/Bills/models/Bill.ts | 6 +- .../modules/Bills/queries/GetBills.service.ts | 2 +- .../CreditNotes/CreditNotes.controller.ts | 2 + .../modules/CreditNotes/models/CreditNote.ts | 10 +- .../queries/GetCreditNotes.service.ts | 5 +- .../CreditNotes/types/CreditNotes.types.ts | 34 ++-- .../CustomViews/CustomViewBaseModel.ts | 19 ++- .../src/modules/Customers/models/Customer.ts | 5 +- .../Customers/queries/GetCustomers.service.ts | 2 +- .../DynamicFilter/DynamicFilter.ts | 21 ++- .../DynamicFilter/DynamicFilter.types.ts | 2 +- .../DynamicFilter/DynamicFilterAbstractor.ts | 6 +- .../DynamicFilter/DynamicFilterQueryParser.ts | 2 +- .../DynamicFilterRoleAbstractor.ts | 34 ++-- .../DynamicFilter/DynamicFilterSearch.ts | 18 +- .../DynamicFilter/DynamicFilterSortBy.ts | 17 +- .../DynamicFilter/DynamicFilterViews.ts | 1 + .../DynamicListing/DynamicList.service.ts | 21 ++- .../DynamicListCustomView.service.ts | 19 ++- .../DynamicListFilterRoles.service.ts | 20 +-- .../DynamicListSortBy.service.ts | 7 +- .../DynamicListing/models/MetadataModel.ts | 2 +- .../models/SearchableBaseModel.ts | 8 +- .../DynamicListing/types/DynamicList.types.ts | 11 +- .../modules/Expenses/models/Expense.model.ts | 18 +- .../InventoryAdjustmentService.ts | 154 ------------------ .../InventoryAdjustments.controller.ts | 7 + .../models/InventoryAdjustment.ts | 17 +- .../GetInventoryAdjustments.service.ts | 2 +- .../src/modules/InventoryCost/Inventory.ts | 6 +- .../InventoryCost/InventoryCost.module.ts | 6 +- .../InventoryCost/InventoryCostApplication.ts | 17 +- .../InventoryCost/InventoryCostMethod.ts | 33 ++-- .../InventoryItemsQuantitySync.service.ts | 26 +-- .../models/InventoryCostLotTracker.ts | 33 ++-- .../models/InventoryTransaction.ts | 18 +- .../models/InventoryTransactionMeta.ts | 29 ++++ .../models/ItemCategory.model.ts | 9 +- .../src/modules/Items/models/Item.ts | 16 +- .../modules/Mail/MailTransporter.service.ts | 3 +- .../ContactMailNotification.ts | 5 +- .../src/modules/MailNotification/utils.ts | 4 +- .../ManualJournals/models/ManualJournal.ts | 4 +- .../queries/GetManualJournals.service.ts | 2 +- .../PaymentsReceived.controller.ts | 3 + .../PaymentReceivedMailNotification.ts | 15 +- .../PaymentReceived/models/PaymentReceived.ts | 16 +- .../queries/GetPaymentsReceived.service.ts | 2 +- .../SaleEstimates/models/SaleEstimate.ts | 17 +- .../modules/SaleInvoices/SaleInvoice.types.ts | 45 ++--- .../SaleInvoices/SaleInvoices.application.ts | 79 ++++----- .../SaleInvoices/SaleInvoices.module.ts | 2 - .../SendInvoiceInvoiceMailCommon.service.ts | 11 +- .../commands/SendSaleInvoiceMail.ts | 2 +- .../commands/SendSaleInvoiceMailReminder.ts | 96 ----------- .../SaleInvoices/models/SaleInvoice.ts | 17 +- .../GetSaleInvoiceMailState.service.ts | 84 +++++----- .../SaleInvoices/queries/GetSaleInvoices.ts | 4 +- .../SaleReceipts/models/SaleReceipt.ts | 87 ++++++---- .../modules/System/models/TenantBaseModel.ts | 15 ++ .../src/modules/Transformer/Transformer.ts | 2 +- .../VendorCredit/models/VendorCredit.ts | 14 +- .../VendorCreditApplyBills.controller.ts | 2 + .../src/modules/Vendors/models/Vendor.ts | 3 +- .../Warehouses/Warehouses.controller.ts | 2 + .../server-nest/src/utils/format-message.ts | 16 ++ pnpm-lock.yaml | 4 +- 81 files changed, 596 insertions(+), 742 deletions(-) rename packages/server-nest/src/libs/logic-evaluation/{Lexer.js => Lexer.ts} (97%) rename packages/server-nest/src/libs/logic-evaluation/{Parser.js => Parser.ts} (96%) rename packages/server-nest/src/libs/logic-evaluation/{QueryParser.js => QueryParser.ts} (94%) delete mode 100644 packages/server-nest/src/modules/InventoryAdjutments/InventoryAdjustmentService.ts create mode 100644 packages/server-nest/src/modules/InventoryCost/models/InventoryTransactionMeta.ts delete mode 100644 packages/server-nest/src/modules/SaleInvoices/commands/SendSaleInvoiceMailReminder.ts create mode 100644 packages/server-nest/src/modules/System/models/TenantBaseModel.ts create mode 100644 packages/server-nest/src/utils/format-message.ts diff --git a/packages/server-nest/package.json b/packages/server-nest/package.json index 2ccc8d068..52f7e15ca 100644 --- a/packages/server-nest/package.json +++ b/packages/server-nest/package.json @@ -105,7 +105,8 @@ "ts-loader": "^9.4.3", "ts-node": "^10.9.1", "tsconfig-paths": "^4.2.0", - "typescript": "^5.1.3" + "typescript": "^5.1.3", + "mustache": "^3.0.3" }, "jest": { "moduleFileExtensions": [ diff --git a/packages/server-nest/src/interfaces/Model.ts b/packages/server-nest/src/interfaces/Model.ts index 7e0c1713d..3230dddb3 100644 --- a/packages/server-nest/src/interfaces/Model.ts +++ b/packages/server-nest/src/interfaces/Model.ts @@ -39,6 +39,8 @@ export interface IModelMetaFieldCommon { order?: number; unique?: number; dataTransferObjectKey?: string; + filterCustomQuery?: Function; + sortCustomQuery?: Function; } export interface IModelMetaFieldText { diff --git a/packages/server-nest/src/libs/logic-evaluation/Lexer.js b/packages/server-nest/src/libs/logic-evaluation/Lexer.ts similarity index 97% rename from packages/server-nest/src/libs/logic-evaluation/Lexer.js rename to packages/server-nest/src/libs/logic-evaluation/Lexer.ts index 3cfc04f41..67ed7c871 100644 --- a/packages/server-nest/src/libs/logic-evaluation/Lexer.js +++ b/packages/server-nest/src/libs/logic-evaluation/Lexer.ts @@ -7,6 +7,10 @@ const OperationType = { }; export class Lexer { + public currentIndex: number; + public input: string; + public tokenList: string[]; + // operation table static get optable() { return { diff --git a/packages/server-nest/src/libs/logic-evaluation/Parser.js b/packages/server-nest/src/libs/logic-evaluation/Parser.ts similarity index 96% rename from packages/server-nest/src/libs/logic-evaluation/Parser.js rename to packages/server-nest/src/libs/logic-evaluation/Parser.ts index 8e7156592..e2aa94a60 100644 --- a/packages/server-nest/src/libs/logic-evaluation/Parser.js +++ b/packages/server-nest/src/libs/logic-evaluation/Parser.ts @@ -26,7 +26,10 @@ export const OPERATION = { // grouped?: boolean; // }; -export default class Parser { +export class Parser { + public index: number; + public blockLevel: number; + public token: string[]; constructor(token) { this.index = -1; diff --git a/packages/server-nest/src/libs/logic-evaluation/QueryParser.js b/packages/server-nest/src/libs/logic-evaluation/QueryParser.ts similarity index 94% rename from packages/server-nest/src/libs/logic-evaluation/QueryParser.js rename to packages/server-nest/src/libs/logic-evaluation/QueryParser.ts index cd31c128d..3f72dcb7c 100644 --- a/packages/server-nest/src/libs/logic-evaluation/QueryParser.js +++ b/packages/server-nest/src/libs/logic-evaluation/QueryParser.ts @@ -1,6 +1,9 @@ import { OPERATION } from './Parser'; -export default class QueryParser { +export class QueryParser { + public tree: any; + public queries: any; + public query: any; constructor(tree, queries) { this.tree = tree; diff --git a/packages/server-nest/src/modules/Accounts/Accounts.constants.ts b/packages/server-nest/src/modules/Accounts/Accounts.constants.ts index bcd1cc641..f35aecef0 100644 --- a/packages/server-nest/src/modules/Accounts/Accounts.constants.ts +++ b/packages/server-nest/src/modules/Accounts/Accounts.constants.ts @@ -1,30 +1,30 @@ export const OtherExpensesAccount = { name: 'Other Expenses', slug: 'other-expenses', - account_type: 'other-expense', + accountType: 'other-expense', code: '40011', description: '', - active: 1, + active: true, index: 1, - predefined: 1, + predefined: true, }; export const TaxPayableAccount = { name: 'Tax Payable', slug: 'tax-payable', - account_type: 'tax-payable', + accountType: 'tax-payable', code: '20006', description: '', - active: 1, + active: true, index: 1, - predefined: 1, + predefined: true, }; export const UnearnedRevenueAccount = { name: 'Unearned Revenue', slug: 'unearned-revenue', - account_type: 'other-current-liability', - parent_account_id: null, + accountType: 'other-current-liability', + parentAccountId: null, code: '50005', active: true, index: 1, @@ -34,8 +34,8 @@ export const UnearnedRevenueAccount = { export const PrepardExpenses = { name: 'Prepaid Expenses', slug: 'prepaid-expenses', - account_type: 'other-current-asset', - parent_account_id: null, + accountType: 'other-current-asset', + parentAccountId: null, code: '100010', active: true, index: 1, @@ -45,8 +45,8 @@ export const PrepardExpenses = { export const StripeClearingAccount = { name: 'Stripe Clearing', slug: 'stripe-clearing', - account_type: 'other-current-asset', - parent_account_id: null, + accountType: 'other-current-asset', + parentAccountId: null, code: '100020', active: true, index: 1, @@ -56,7 +56,7 @@ export const StripeClearingAccount = { export const DiscountExpenseAccount = { name: 'Discount', slug: 'discount', - account_type: 'other-income', + accountType: 'other-income', code: '40008', active: true, index: 1, @@ -66,7 +66,7 @@ export const DiscountExpenseAccount = { export const PurchaseDiscountAccount = { name: 'Purchase Discount', slug: 'purchase-discount', - account_type: 'other-expense', + accountType: 'other-expense', code: '40009', active: true, index: 1, @@ -76,7 +76,7 @@ export const PurchaseDiscountAccount = { export const OtherChargesAccount = { name: 'Other Charges', slug: 'other-charges', - account_type: 'other-income', + accountType: 'other-income', code: '40010', active: true, index: 1, @@ -87,7 +87,7 @@ export const SeedAccounts = [ { name: 'Bank Account', slug: 'bank-account', - account_type: 'bank', + accountType: 'bank', code: '10001', description: '', active: 1, diff --git a/packages/server-nest/src/modules/Accounts/DeleteAccount.service.ts b/packages/server-nest/src/modules/Accounts/DeleteAccount.service.ts index 2403bb3df..9479d6ea1 100644 --- a/packages/server-nest/src/modules/Accounts/DeleteAccount.service.ts +++ b/packages/server-nest/src/modules/Accounts/DeleteAccount.service.ts @@ -41,7 +41,7 @@ export class DeleteAccount { await this.accountModel .query(trx) .whereIn('parent_account_id', accountsIds) - .patch({ parent_account_id: null }); + .patch({ parentAccountId: null }); } /** diff --git a/packages/server-nest/src/modules/Accounts/GetAccounts.service.ts b/packages/server-nest/src/modules/Accounts/GetAccounts.service.ts index 9afe3ed9a..b029cef20 100644 --- a/packages/server-nest/src/modules/Accounts/GetAccounts.service.ts +++ b/packages/server-nest/src/modules/Accounts/GetAccounts.service.ts @@ -13,10 +13,10 @@ export class GetAccountsService { constructor( private readonly dynamicListService: DynamicListService, private readonly transformerService: TransformerInjectable, + private readonly accountRepository: AccountRepository, @Inject(Account.name) private readonly accountModel: typeof Account, - private readonly accountRepository: AccountRepository, ) {} /** diff --git a/packages/server-nest/src/modules/Accounts/models/Account.model.ts b/packages/server-nest/src/modules/Accounts/models/Account.model.ts index c4287d3eb..3a9b3e4bd 100644 --- a/packages/server-nest/src/modules/Accounts/models/Account.model.ts +++ b/packages/server-nest/src/modules/Accounts/models/Account.model.ts @@ -13,32 +13,29 @@ import { TenantModel } from '@/modules/System/models/TenantModel'; import { AccountTypesUtils } from '@/libs/accounts-utils/AccountTypesUtils'; import { Model } from 'objection'; import { PlaidItem } from '@/modules/BankingPlaid/models/PlaidItem'; +import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel'; // import AccountSettings from './Account.Settings'; // import { DEFAULT_VIEWS } from '@/modules/Accounts/constants'; // import { buildFilterQuery, buildSortColumnQuery } from '@/lib/ViewRolesBuilder'; // import { flatToNestedArray } from 'utils'; -// @ts-expect-error -// export class Account extends mixin(TenantModel, [ -// ModelSettings, -// CustomViewBaseModel, -// SearchableModel, -// ]) { -export class Account extends TenantModel { +export class Account extends TenantBaseModel { public name!: string; public slug!: string; public code!: string; public index!: number; public accountType!: string; + public parentAccountId!: number | null; public predefined!: boolean; public currencyCode!: string; public active!: boolean; public bankBalance!: number; - public lastFeedsUpdatedAt!: string | null; + public lastFeedsUpdatedAt!: string | Date | null; public amount!: number; public plaidItemId!: number; - + public plaidAccountId!: string | null; + public isFeedsActive!: boolean; public plaidItem!: PlaidItem; /** @@ -73,11 +70,11 @@ export class Account extends TenantModel { /** * Account normal. */ - get accountNormal() { + get accountNormal(): string { return AccountTypesUtils.getType(this.accountType, 'normal'); } - get accountNormalFormatted() { + get accountNormalFormatted(): string { const paris = { credit: 'Credit', debit: 'Debit', @@ -88,35 +85,35 @@ export class Account extends TenantModel { /** * Retrieve account type label. */ - get accountTypeLabel() { + get accountTypeLabel(): string { return AccountTypesUtils.getType(this.accountType, 'label'); } /** * Retrieve account parent type. */ - get accountParentType() { + get accountParentType(): string { return AccountTypesUtils.getType(this.accountType, 'parentType'); } /** * Retrieve account root type. */ - get accountRootType() { + get accountRootType(): string { return AccountTypesUtils.getType(this.accountType, 'rootType'); } /** * Retrieve whether the account is balance sheet account. */ - get isBalanceSheetAccount() { + get isBalanceSheetAccount(): boolean { return this.isBalanceSheet(); } /** * Retrieve whether the account is profit/loss sheet account. */ - get isPLSheet() { + get isPLSheet(): boolean { return this.isProfitLossSheet(); } /** diff --git a/packages/server-nest/src/modules/Accounts/repositories/Account.repository.ts b/packages/server-nest/src/modules/Accounts/repositories/Account.repository.ts index 3f3ef3d9f..bf93f3eee 100644 --- a/packages/server-nest/src/modules/Accounts/repositories/Account.repository.ts +++ b/packages/server-nest/src/modules/Accounts/repositories/Account.repository.ts @@ -147,7 +147,7 @@ export class AccountRepository extends TenantRepository { }), accountType: 'accounts-receivable', currencyCode, - active: 1, + active: true, ...extraAttrs, }); } @@ -199,7 +199,7 @@ export class AccountRepository extends TenantRepository { }), accountType: 'accounts-payable', currencyCode, - active: 1, + active: true, ...extraAttrs, }); } diff --git a/packages/server-nest/src/modules/BankingPlaid/command/PlaidSyncDB.ts b/packages/server-nest/src/modules/BankingPlaid/command/PlaidSyncDB.ts index 26dab195c..0a572e61c 100644 --- a/packages/server-nest/src/modules/BankingPlaid/command/PlaidSyncDB.ts +++ b/packages/server-nest/src/modules/BankingPlaid/command/PlaidSyncDB.ts @@ -47,7 +47,6 @@ export class PlaidSyncDb { /** * Syncs the Plaid bank account. - * @param {number} tenantId * @param {IAccountCreateDTO} createBankAccountDTO * @param {Knex.Transaction} trx * @returns {Promise} @@ -70,7 +69,6 @@ export class PlaidSyncDb { /** * Syncs the plaid accounts to the system accounts. - * @param {number} tenantId Tenant ID. * @param {PlaidAccount[]} plaidAccounts * @returns {Promise} */ @@ -94,7 +92,6 @@ export class PlaidSyncDb { /** * Synsc the Plaid transactions to the system GL entries. - * @param {number} tenantId - Tenant ID. * @param {number} plaidAccountId - Plaid account ID. * @param {PlaidTransaction[]} plaidTranasctions - Plaid transactions * @return {Promise} @@ -136,7 +133,6 @@ export class PlaidSyncDb { /** * Syncs the accounts transactions in paraller under controlled concurrency. - * @param {number} tenantId * @param {PlaidTransaction[]} plaidTransactions * @return {Promise} */ @@ -188,7 +184,6 @@ export class PlaidSyncDb { /** * Syncs the Plaid item last transaction cursor. - * @param {number} tenantId - Tenant ID. * @param {string} itemId - Plaid item ID. * @param {string} lastCursor - Last transaction cursor. * @return {Promise} @@ -206,8 +201,7 @@ export class PlaidSyncDb { /** * Updates the last feeds updated at of the given Plaid accounts ids. - * @param {number} tenantId - * @param {string[]} plaidAccountIds + * @param {string[]} plaidAccountIds - Plaid accounts ids. * @return {Promise} */ public async updateLastFeedsUpdatedAt( @@ -224,9 +218,8 @@ export class PlaidSyncDb { /** * Updates the accounts feed active status of the given Plaid accounts ids. - * @param {number} tenantId - * @param {number[]} plaidAccountIds - * @param {boolean} isFeedsActive + * @param {number[]} plaidAccountIds - Plaid accounts ids. + * @param {boolean} isFeedsActive - Feeds active status. * @returns {Promise} */ public async updateAccountsFeedsActive( diff --git a/packages/server-nest/src/modules/BankingTransactions/models/BankAccount.ts b/packages/server-nest/src/modules/BankingTransactions/models/BankAccount.ts index fa588320f..268bec5ba 100644 --- a/packages/server-nest/src/modules/BankingTransactions/models/BankAccount.ts +++ b/packages/server-nest/src/modules/BankingTransactions/models/BankAccount.ts @@ -1,11 +1,11 @@ /* eslint-disable global-require */ -import { mixin, Model } from 'objection'; +import { Model } from 'objection'; import { castArray } from 'lodash'; -import { BaseModel } from '@/models/Model'; import { AccountTypesUtils } from '@/libs/accounts-utils/AccountTypesUtils'; import { PlaidItem } from '@/modules/BankingPlaid/models/PlaidItem'; +import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel'; -export class BankAccount extends BaseModel { +export class BankAccount extends TenantBaseModel { public name!: string; public slug!: string; public code!: string; diff --git a/packages/server-nest/src/modules/BankingTransactions/queries/BankAccountTransformer.ts b/packages/server-nest/src/modules/BankingTransactions/queries/BankAccountTransformer.ts index f645a2d73..fc72a67c2 100644 --- a/packages/server-nest/src/modules/BankingTransactions/queries/BankAccountTransformer.ts +++ b/packages/server-nest/src/modules/BankingTransactions/queries/BankAccountTransformer.ts @@ -48,7 +48,9 @@ export class CashflowAccountTransformer extends Transformer { * @returns {string} */ protected lastFeedsUpdatedAtFormatted(account: Account): string { - return this.formatDate(account.lastFeedsUpdatedAt); + return account.lastFeedsUpdatedAt + ? this.formatDate(account.lastFeedsUpdatedAt) + : ''; } /** @@ -57,6 +59,8 @@ export class CashflowAccountTransformer extends Transformer { * @returns {string} */ protected lastFeedsUpdatedFromNow(account: Account): string { - return this.formatDateFromNow(account.lastFeedsUpdatedAt); + return account.lastFeedsUpdatedAt + ? this.formatDateFromNow(account.lastFeedsUpdatedAt) + : ''; } } diff --git a/packages/server-nest/src/modules/BankingTransactions/queries/GetBankAccounts.service.ts b/packages/server-nest/src/modules/BankingTransactions/queries/GetBankAccounts.service.ts index b37f813cd..f1094f0fd 100644 --- a/packages/server-nest/src/modules/BankingTransactions/queries/GetBankAccounts.service.ts +++ b/packages/server-nest/src/modules/BankingTransactions/queries/GetBankAccounts.service.ts @@ -29,7 +29,7 @@ export class GetBankAccountsService { // Dynamic list service. const dynamicList = await this.dynamicListService.dynamicList( - BankAccount, + this.bankAccountModel, filter, ); // Retrieve accounts model based on the given query. diff --git a/packages/server-nest/src/modules/Bills/models/Bill.ts b/packages/server-nest/src/modules/Bills/models/Bill.ts index d0cb162db..cfcedb458 100644 --- a/packages/server-nest/src/modules/Bills/models/Bill.ts +++ b/packages/server-nest/src/modules/Bills/models/Bill.ts @@ -164,7 +164,7 @@ export class Bill extends BaseModel { * Adjustment amount in local currency. * @returns {number | null} */ - get adjustmentLocal() { + get adjustmentLocal(): number | null { return this.adjustment ? this.adjustment * this.exchangeRate : null; } @@ -172,7 +172,7 @@ export class Bill extends BaseModel { * Invoice total. (Tax included) * @returns {number} */ - get total() { + get total(): number { const adjustmentAmount = defaultTo(this.adjustment, 0); return R.compose( @@ -186,7 +186,7 @@ export class Bill extends BaseModel { * Invoice total in local currency. (Tax included) * @returns {number} */ - get totalLocal() { + get totalLocal(): number { return this.total * this.exchangeRate; } diff --git a/packages/server-nest/src/modules/Bills/queries/GetBills.service.ts b/packages/server-nest/src/modules/Bills/queries/GetBills.service.ts index 51de6a884..14dcae783 100644 --- a/packages/server-nest/src/modules/Bills/queries/GetBills.service.ts +++ b/packages/server-nest/src/modules/Bills/queries/GetBills.service.ts @@ -30,7 +30,7 @@ export class GetBillsService { // Dynamic list service. const dynamicFilter = await this.dynamicListService.dynamicList( - Bill, + this.billModel, filter, ); const { results, pagination } = await this.billModel diff --git a/packages/server-nest/src/modules/CreditNotes/CreditNotes.controller.ts b/packages/server-nest/src/modules/CreditNotes/CreditNotes.controller.ts index d32f45b71..f4b11681c 100644 --- a/packages/server-nest/src/modules/CreditNotes/CreditNotes.controller.ts +++ b/packages/server-nest/src/modules/CreditNotes/CreditNotes.controller.ts @@ -15,8 +15,10 @@ import { ICreditNotesQueryDTO, } from './types/CreditNotes.types'; import { PublicRoute } from '../Auth/Jwt.guard'; +import { ApiTags } from '@nestjs/swagger'; @Controller('credit-notes') +@ApiTags('credit-notes') @PublicRoute() export class CreditNotesController { /** diff --git a/packages/server-nest/src/modules/CreditNotes/models/CreditNote.ts b/packages/server-nest/src/modules/CreditNotes/models/CreditNote.ts index 25364f7ba..482fef214 100644 --- a/packages/server-nest/src/modules/CreditNotes/models/CreditNote.ts +++ b/packages/server-nest/src/modules/CreditNotes/models/CreditNote.ts @@ -2,18 +2,12 @@ import { DiscountType } from '@/common/types/Discount'; import { BaseModel } from '@/models/Model'; import { Branch } from '@/modules/Branches/models/Branch.model'; import { Customer } from '@/modules/Customers/models/Customer'; +import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel'; import { ItemEntry } from '@/modules/TransactionItemEntry/models/ItemEntry'; import { Warehouse } from '@/modules/Warehouses/models/Warehouse.model'; import { mixin, Model, raw } from 'objection'; -// import TenantModel from 'models/TenantModel'; -// import ModelSetting from './ModelSetting'; -// import CustomViewBaseModel from './CustomViewBaseModel'; -// import { DEFAULT_VIEWS } from '@/services/CreditNotes/constants'; -// import ModelSearchable from './ModelSearchable'; -// import CreditNoteMeta from './CreditNote.Meta'; -// import { DiscountType } from '@/interfaces'; -export class CreditNote extends BaseModel { +export class CreditNote extends TenantBaseModel { public amount: number; public exchangeRate: number; public openedAt: Date; diff --git a/packages/server-nest/src/modules/CreditNotes/queries/GetCreditNotes.service.ts b/packages/server-nest/src/modules/CreditNotes/queries/GetCreditNotes.service.ts index eb9aa2e83..db2c71b4d 100644 --- a/packages/server-nest/src/modules/CreditNotes/queries/GetCreditNotes.service.ts +++ b/packages/server-nest/src/modules/CreditNotes/queries/GetCreditNotes.service.ts @@ -39,7 +39,7 @@ export class GetCreditNotesService { // Dynamic list service. const dynamicFilter = await this.dynamicListService.dynamicList( - CreditNote, + this.creditNoteModel, filter, ); const { results, pagination } = await this.creditNoteModel @@ -47,8 +47,9 @@ export class GetCreditNotesService { .onBuild((builder) => { builder.withGraphFetched('entries.item'); builder.withGraphFetched('customer'); + dynamicFilter.buildQuery()(builder); - creditNotesQuery?.filterQuery && creditNotesQuery?.filterQuery(builder); + creditNotesQuery?.filterQuery?.(builder as any); }) .pagination(filter.page - 1, filter.pageSize); diff --git a/packages/server-nest/src/modules/CreditNotes/types/CreditNotes.types.ts b/packages/server-nest/src/modules/CreditNotes/types/CreditNotes.types.ts index 1207fa7e9..2362a001a 100644 --- a/packages/server-nest/src/modules/CreditNotes/types/CreditNotes.types.ts +++ b/packages/server-nest/src/modules/CreditNotes/types/CreditNotes.types.ts @@ -5,6 +5,7 @@ import { AttachmentLinkDTO } from '@/modules/Attachments/Attachments.types'; import { IItemEntryDTO } from '@/modules/TransactionItemEntry/ItemEntry.types'; import { IFilterMeta, IPaginationMeta } from '@/interfaces/Model'; import { IDynamicListFilter } from '@/modules/DynamicListing/DynamicFilter/DynamicFilter.types'; +import { ILedgerEntry } from '@/modules/Ledger/types/Ledger.types'; export interface ICreditNoteEntryNewDTO extends IItemEntryDTO {} @@ -97,6 +98,7 @@ export interface ICreditNotesQueryDTO extends IDynamicListFilter { page: number; pageSize: number; searchKeyword?: string; + filterQuery?: (builder: Knex.QueryBuilder) => void; } export interface ICreditNoteRefundDTO { @@ -109,22 +111,22 @@ export interface ICreditNoteRefundDTO { branchId?: number; } -// export type ICreditNoteGLCommonEntry = Pick< -// ILedgerEntry, -// | 'date' -// | 'userId' -// | 'currencyCode' -// | 'exchangeRate' -// | 'transactionType' -// | 'transactionId' -// | 'transactionNumber' -// | 'referenceNumber' -// | 'createdAt' -// | 'indexGroup' -// | 'credit' -// | 'debit' -// | 'branchId' -// >; +export type ICreditNoteGLCommonEntry = Pick< + ILedgerEntry, + | 'date' + | 'userId' + | 'currencyCode' + | 'exchangeRate' + | 'transactionType' + | 'transactionId' + | 'transactionNumber' + | 'referenceNumber' + | 'createdAt' + | 'indexGroup' + | 'credit' + | 'debit' + | 'branchId' +>; export interface GetCreditNotesResponse { creditNotes: CreditNote[]; diff --git a/packages/server-nest/src/modules/CustomViews/CustomViewBaseModel.ts b/packages/server-nest/src/modules/CustomViews/CustomViewBaseModel.ts index 024595e8a..498bd8f4a 100644 --- a/packages/server-nest/src/modules/CustomViews/CustomViewBaseModel.ts +++ b/packages/server-nest/src/modules/CustomViews/CustomViewBaseModel.ts @@ -1,8 +1,17 @@ -import { BaseModel } from "@/models/Model"; -; +import { BaseModel } from '@/models/Model'; +import { IView } from '../Views/Views.types'; + type GConstructor = new (...args: any[]) => T; -export const CustomViewBaseModelMixin = >(Model: T) => +export interface ICustomViewBaseModel { + defaultViews: IView[]; + getDefaultViewBySlug(viewSlug: string): IView | null; + getDefaultViews(): IView[]; +} + +export const CustomViewBaseModelMixin = >( + Model: T, +) => class CustomViewBaseModel extends Model { /** * Retrieve the default custom views, roles and columns. @@ -18,6 +27,10 @@ export const CustomViewBaseModelMixin = >(Mode return this.defaultViews.find((view) => view.slug === viewSlug) || null; } + /** + * Retrieve the default views. + * @returns {IView[]} + */ static getDefaultViews() { return this.defaultViews; } diff --git a/packages/server-nest/src/modules/Customers/models/Customer.ts b/packages/server-nest/src/modules/Customers/models/Customer.ts index 95791d224..f047b0382 100644 --- a/packages/server-nest/src/modules/Customers/models/Customer.ts +++ b/packages/server-nest/src/modules/Customers/models/Customer.ts @@ -1,5 +1,4 @@ -import { Model, mixin } from 'objection'; -import { BaseModel } from '@/models/Model'; +import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel'; // import TenantModel from 'models/TenantModel'; // import PaginationQueryBuilder from './Pagination'; // import ModelSetting from './ModelSetting'; @@ -20,7 +19,7 @@ import { BaseModel } from '@/models/Model'; // } // } -export class Customer extends BaseModel{ +export class Customer extends TenantBaseModel{ contactService: string; contactType: string; diff --git a/packages/server-nest/src/modules/Customers/queries/GetCustomers.service.ts b/packages/server-nest/src/modules/Customers/queries/GetCustomers.service.ts index 198a47145..62338d06f 100644 --- a/packages/server-nest/src/modules/Customers/queries/GetCustomers.service.ts +++ b/packages/server-nest/src/modules/Customers/queries/GetCustomers.service.ts @@ -38,7 +38,7 @@ export class GetCustomers { const filter = this.parseCustomersListFilterDTO(filterDTO); const dynamicList = await this.dynamicListService.dynamicList( - Customer, + this.customerModel, filter, ); const { results, pagination } = await this.customerModel diff --git a/packages/server-nest/src/modules/DynamicListing/DynamicFilter/DynamicFilter.ts b/packages/server-nest/src/modules/DynamicListing/DynamicFilter/DynamicFilter.ts index 2bdf7b515..ef0d8d3ba 100644 --- a/packages/server-nest/src/modules/DynamicListing/DynamicFilter/DynamicFilter.ts +++ b/packages/server-nest/src/modules/DynamicListing/DynamicFilter/DynamicFilter.ts @@ -1,15 +1,18 @@ import { forEach } from 'lodash'; import { DynamicFilterAbstractor } from './DynamicFilterAbstractor'; -import { IDynamicFilter, IFilterRole } from './DynamicFilter.types'; -import { BaseModel } from '@/models/Model'; +import { IFilterRole } from './DynamicFilter.types'; import { DynamicFilterRoleAbstractor } from './DynamicFilterRoleAbstractor'; +import { MetableModel } from '../types/DynamicList.types'; + +export class DynamicFilter extends DynamicFilterAbstractor { + public model: MetableModel; + public dynamicFilters: DynamicFilterRoleAbstractor[]; -export class DynamicFilter extends DynamicFilterAbstractor { /** * Constructor. - * @param {String} tableName - + * @param {MetableModel} model - Metable model. */ - constructor(model: typeof BaseModel) { + constructor(model: MetableModel) { super(); this.model = model; @@ -29,7 +32,7 @@ export class DynamicFilter extends DynamicFilterAbstractor { /** * Retrieve dynamic filter build queries. - * @returns + * @returns {Function[]} */ private dynamicFiltersBuildQuery = () => { return this.dynamicFilters.map((filter) => { @@ -72,16 +75,16 @@ export class DynamicFilter extends DynamicFilterAbstractor { /** * Retrieve response metadata from all filters adapters. */ - public getResponseMeta = () => { + public getResponseMeta = (): R => { const responseMeta = {}; this.dynamicFilters.forEach((filter) => { - const { responseMeta: filterMeta } = filter; + const filterMeta = filter.getResponseMeta(); forEach(filterMeta, (value, key) => { responseMeta[key] = value; }); }); - return responseMeta; + return responseMeta as R; }; } diff --git a/packages/server-nest/src/modules/DynamicListing/DynamicFilter/DynamicFilter.types.ts b/packages/server-nest/src/modules/DynamicListing/DynamicFilter/DynamicFilter.types.ts index ac9162d66..d175b0308 100644 --- a/packages/server-nest/src/modules/DynamicListing/DynamicFilter/DynamicFilter.types.ts +++ b/packages/server-nest/src/modules/DynamicListing/DynamicFilter/DynamicFilter.types.ts @@ -19,7 +19,7 @@ export interface IDynamicListFilter { customViewId?: number; filterRoles?: IFilterRole[]; columnSortBy: ISortOrder; - sortOrder: string; + sortOrder: ISortOrder; stringifiedFilterRoles?: string; searchKeyword?: string; viewSlug?: string; diff --git a/packages/server-nest/src/modules/DynamicListing/DynamicFilter/DynamicFilterAbstractor.ts b/packages/server-nest/src/modules/DynamicListing/DynamicFilter/DynamicFilterAbstractor.ts index 79f23c86f..35da303be 100644 --- a/packages/server-nest/src/modules/DynamicListing/DynamicFilter/DynamicFilterAbstractor.ts +++ b/packages/server-nest/src/modules/DynamicListing/DynamicFilter/DynamicFilterAbstractor.ts @@ -1,13 +1,13 @@ -import { BaseModel } from '@/models/Model'; import { IDynamicFilter } from './DynamicFilter.types'; +import { MetableModel } from '../types/DynamicList.types'; export class DynamicFilterAbstractor { - public model: typeof BaseModel; + public model: MetableModel; public dynamicFilters: IDynamicFilter[]; /** * Extract relation table name from relation. - * @param {String} column - + * @param {String} column - Column name * @return {String} - join relation table. */ protected getTableFromRelationColumn = (column: string) => { diff --git a/packages/server-nest/src/modules/DynamicListing/DynamicFilter/DynamicFilterQueryParser.ts b/packages/server-nest/src/modules/DynamicListing/DynamicFilter/DynamicFilterQueryParser.ts index 59df7d729..3da1288d3 100644 --- a/packages/server-nest/src/modules/DynamicListing/DynamicFilter/DynamicFilterQueryParser.ts +++ b/packages/server-nest/src/modules/DynamicListing/DynamicFilter/DynamicFilterQueryParser.ts @@ -1,7 +1,7 @@ // @ts-nocheck import { OPERATION } from '@/libs/logic-evaluation/Parser'; -export default class QueryParser { +export class DynamicFilterQueryParser { constructor(tree, queries) { this.tree = tree; this.queries = queries; diff --git a/packages/server-nest/src/modules/DynamicListing/DynamicFilter/DynamicFilterRoleAbstractor.ts b/packages/server-nest/src/modules/DynamicListing/DynamicFilter/DynamicFilterRoleAbstractor.ts index 890df56f4..66509d298 100644 --- a/packages/server-nest/src/modules/DynamicListing/DynamicFilter/DynamicFilterRoleAbstractor.ts +++ b/packages/server-nest/src/modules/DynamicListing/DynamicFilter/DynamicFilterRoleAbstractor.ts @@ -1,27 +1,26 @@ import moment from 'moment'; import * as R from 'ramda'; import { IFilterRole, IDynamicFilter } from './DynamicFilter.types'; -import Parser from '@/libs/logic-evaluation/Parser'; +import { Parser } from '@/libs/logic-evaluation/Parser'; import { Lexer } from '@/libs/logic-evaluation/Lexer'; -import DynamicFilterQueryParser from './DynamicFilterQueryParser'; +import { DynamicFilterQueryParser } from './DynamicFilterQueryParser'; import { COMPARATOR_TYPE, FIELD_TYPE } from './constants'; import { BaseModel } from '@/models/Model'; -import { IMetadataModel } from '../models/MetadataModel'; - -type MetadataModel = typeof BaseModel & IMetadataModel; +import { MetableModel } from '../types/DynamicList.types'; +import { Knex } from 'knex'; export abstract class DynamicFilterRoleAbstractor implements IDynamicFilter { - protected filterRoles: IFilterRole[] = []; - protected tableName: string; - protected model: MetadataModel; - protected responseMeta: { [key: string]: any } = {}; + public filterRoles: IFilterRole[] = []; + public tableName: string; + public model: MetableModel; + public responseMeta: { [key: string]: any } = {}; public relationFields = []; /** * Sets model the dynamic filter service. * @param {IModel} model */ - public setModel(model: MetadataModel) { + public setModel(model: MetableModel) { this.model = model; this.tableName = model.tableName; } @@ -118,7 +117,7 @@ export abstract class DynamicFilterRoleAbstractor implements IDynamicFilter { * @param {IModel} model - * @param {} - */ - private getFieldComparatorColumn = (field) => { + protected getFieldComparatorColumn = (field) => { return field.fieldType === FIELD_TYPE.RELATION ? this.getFieldComparatorRelationColumn(field) : `${this.tableName}.${field.column}`; @@ -129,7 +128,7 @@ export abstract class DynamicFilterRoleAbstractor implements IDynamicFilter { * @param {IModel} model - * @param {Object} role - */ - protected buildRoleQuery = (model: MetadataModel, role: IFilterRole) => { + protected buildRoleQuery = (model: MetableModel, role: IFilterRole) => { const field = model.getField(role.fieldKey); const comparatorColumn = this.getFieldComparatorColumn(field); @@ -384,10 +383,17 @@ export abstract class DynamicFilterRoleAbstractor implements IDynamicFilter { */ onInitialize() {} - buildQuery(): void { + /** + * Builds the query. + */ + buildQuery(): (builder: Knex.QueryBuilder) => void { throw new Error('Method not implemented.'); } + + /** + * Retrieves the response meta. + */ getResponseMeta() { throw new Error('Method not implemented.'); - } + } } diff --git a/packages/server-nest/src/modules/DynamicListing/DynamicFilter/DynamicFilterSearch.ts b/packages/server-nest/src/modules/DynamicListing/DynamicFilter/DynamicFilterSearch.ts index 1f8975d01..353a0a109 100644 --- a/packages/server-nest/src/modules/DynamicListing/DynamicFilter/DynamicFilterSearch.ts +++ b/packages/server-nest/src/modules/DynamicListing/DynamicFilter/DynamicFilterSearch.ts @@ -1,6 +1,10 @@ import { IFilterRole } from './DynamicFilter.types'; import { DynamicFilterFilterRoles } from './DynamicFilterFilterRoles'; +export interface IDynamicFilterSearchResponseMeta { + searchKeyword: string; +} + export class DynamicFilterSearch extends DynamicFilterFilterRoles { private searchKeyword: string; @@ -23,7 +27,7 @@ export class DynamicFilterSearch extends DynamicFilterFilterRoles { /** * Retrieve the filter roles from model search roles. - * @param {string} searchKeyword + * @param {string} searchKeyword * @returns {IFilterRole[]} */ private getModelSearchFilterRoles(searchKeyword: string): IFilterRole[] { @@ -37,11 +41,21 @@ export class DynamicFilterSearch extends DynamicFilterFilterRoles { } /** - * + * Sets the response meta. */ setResponseMeta() { this.responseMeta = { searchKeyword: this.searchKeyword, }; } + + /** + * Retrieves the response meta. + * @returns {IDynamicFilterSearchResponseMeta} + */ + public getResponseMeta(): IDynamicFilterSearchResponseMeta { + return { + searchKeyword: this.searchKeyword, + }; + } } diff --git a/packages/server-nest/src/modules/DynamicListing/DynamicFilter/DynamicFilterSortBy.ts b/packages/server-nest/src/modules/DynamicListing/DynamicFilter/DynamicFilterSortBy.ts index c06eea2d1..23d4ea47c 100644 --- a/packages/server-nest/src/modules/DynamicListing/DynamicFilter/DynamicFilterSortBy.ts +++ b/packages/server-nest/src/modules/DynamicListing/DynamicFilter/DynamicFilterSortBy.ts @@ -1,5 +1,4 @@ import { FIELD_TYPE } from './constants'; -import { DynamicFilterAbstractor } from './DynamicFilterAbstractor'; import { DynamicFilterRoleAbstractor } from './DynamicFilterRoleAbstractor'; interface ISortRole { @@ -8,7 +7,10 @@ interface ISortRole { } export class DynamicFilterSortBy extends DynamicFilterRoleAbstractor { - private sortRole: ISortRole = {}; + private sortRole: ISortRole = { + fieldKey: '', + order: '', + }; /** * Constructor method. @@ -22,7 +24,6 @@ export class DynamicFilterSortBy extends DynamicFilterRoleAbstractor { fieldKey: sortByFieldKey, order: sortDirection, }; - this.setResponseMeta(); } /** @@ -54,7 +55,7 @@ export class DynamicFilterSortBy extends DynamicFilterRoleAbstractor { * @param {IModel} field * @returns {string} */ - private getFieldComparatorColumn = (field): string => { + getFieldComparatorColumn = (field) => { return field.fieldType === FIELD_TYPE.RELATION ? this.getFieldComparatorRelationColumn(field) : `${this.tableName}.${field.column}`; @@ -84,10 +85,10 @@ export class DynamicFilterSortBy extends DynamicFilterRoleAbstractor { /** * Sets response meta. */ - public setResponseMeta() { - this.responseMeta = { - sortOrder: this.sortRole.fieldKey, - sortBy: this.sortRole.order, + public getResponseMeta(): ISortRole { + return { + fieldKey: this.sortRole.fieldKey, + order: this.sortRole.order, }; } } diff --git a/packages/server-nest/src/modules/DynamicListing/DynamicFilter/DynamicFilterViews.ts b/packages/server-nest/src/modules/DynamicListing/DynamicFilter/DynamicFilterViews.ts index 64edf06f5..5b40e9b17 100644 --- a/packages/server-nest/src/modules/DynamicListing/DynamicFilter/DynamicFilterViews.ts +++ b/packages/server-nest/src/modules/DynamicListing/DynamicFilter/DynamicFilterViews.ts @@ -1,5 +1,6 @@ import { omit } from 'lodash'; import { DynamicFilterRoleAbstractor } from './DynamicFilterRoleAbstractor'; +import { IView } from '@/modules/Views/Views.types'; export class DynamicFilterViews extends DynamicFilterRoleAbstractor { private viewSlug: string; diff --git a/packages/server-nest/src/modules/DynamicListing/DynamicList.service.ts b/packages/server-nest/src/modules/DynamicListing/DynamicList.service.ts index bb8b112dc..9e6e8062c 100644 --- a/packages/server-nest/src/modules/DynamicListing/DynamicList.service.ts +++ b/packages/server-nest/src/modules/DynamicListing/DynamicList.service.ts @@ -6,7 +6,8 @@ import { DynamicListCustomView } from './DynamicListCustomView.service'; import { Injectable } from '@nestjs/common'; import { DynamicListFilterRoles } from './DynamicListFilterRoles.service'; import { DynamicFilter } from './DynamicFilter'; -import { BaseModel } from '@/models/Model'; +import { MetableModel } from './types/DynamicList.types'; +import { IFilterMeta } from '@/interfaces/Model'; @Injectable() export class DynamicListService { @@ -19,10 +20,13 @@ export class DynamicListService { /** * Parses filter DTO. - * @param {IMode} model - - * @param {} filterDTO - + * @param {MetableModel} model - Metable model. + * @param {IDynamicListFilter} filterDTO - Dynamic list filter DTO. */ - private parseFilterObject = (model, filterDTO) => { + private parseFilterObject = ( + model: MetableModel, + filterDTO: IDynamicListFilter, + ) => { return { // Merges the default properties with filter object. ...(model.defaultSort @@ -37,15 +41,14 @@ export class DynamicListService { /** * Dynamic listing. - * @param {number} tenantId - Tenant id. - * @param {IModel} model - Model. + * @param {IModel} model - Metable model. * @param {IDynamicListFilter} filter - Dynamic filter DTO. */ public dynamicList = async ( - model: typeof BaseModel, + model: MetableModel, filter: IDynamicListFilter, ) => { - const dynamicFilter = new DynamicFilter(model); + const dynamicFilter = new DynamicFilter(model); // Parses the filter object. const parsedFilter = this.parseFilterObject(model, filter); @@ -99,5 +102,5 @@ export class DynamicListService { ? castArray(JSON.parse(filterRoles.stringifiedFilterRoles)) : [], }; - }; + } } diff --git a/packages/server-nest/src/modules/DynamicListing/DynamicListCustomView.service.ts b/packages/server-nest/src/modules/DynamicListing/DynamicListCustomView.service.ts index f8f04db1b..60b693a30 100644 --- a/packages/server-nest/src/modules/DynamicListing/DynamicListCustomView.service.ts +++ b/packages/server-nest/src/modules/DynamicListing/DynamicListCustomView.service.ts @@ -2,21 +2,22 @@ import { Injectable } from '@nestjs/common'; import { ERRORS } from './constants'; import { DynamicFilterViews } from './DynamicFilter'; import { ServiceError } from '../Items/ServiceError'; -import { BaseModel } from '@/models/Model'; import { DynamicListServiceAbstract } from './DynamicListServiceAbstract'; +import { IView } from '../Views/Views.types'; +import { MetableModel } from './types/DynamicList.types'; @Injectable() export class DynamicListCustomView extends DynamicListServiceAbstract { /** * Retreive custom view or throws error not found. - * @param {number} tenantId - * @param {number} viewId + * @param {string} viewSlug - View slug. + * @param {MetableModel} model - Metable model. * @return {Promise} */ - private getCustomViewOrThrowError = async ( + private async getCustomViewOrThrowError( viewSlug: string, - model: BaseModel, - ) => { + model: MetableModel, + ): Promise { // Finds the default view by the given view slug. const defaultView = model.getDefaultViewBySlug(viewSlug); @@ -24,12 +25,12 @@ export class DynamicListCustomView extends DynamicListServiceAbstract { throw new ServiceError(ERRORS.VIEW_NOT_FOUND); } return defaultView; - }; + } /** * Dynamic list custom view. - * @param {IModel} model - * @param {number} customViewId + * @param {DynamicFilter} dynamicFilter - Dynamic filter. + * @param {string} customViewSlug - Custom view slug. * @returns {DynamicFilterRoleAbstractor} */ public dynamicListCustomView = async ( diff --git a/packages/server-nest/src/modules/DynamicListing/DynamicListFilterRoles.service.ts b/packages/server-nest/src/modules/DynamicListing/DynamicListFilterRoles.service.ts index 0058046eb..0042af3b6 100644 --- a/packages/server-nest/src/modules/DynamicListing/DynamicListFilterRoles.service.ts +++ b/packages/server-nest/src/modules/DynamicListing/DynamicListFilterRoles.service.ts @@ -3,10 +3,10 @@ import { Injectable } from '@nestjs/common'; import validator from 'is-my-json-valid'; import { IFilterRole } from './DynamicFilter/DynamicFilter.types'; import { DynamicFilterAdvancedFilter } from './DynamicFilter/DynamicFilterAdvancedFilter'; -import { ERRORS } from './constants'; -import { ServiceError } from '../Items/ServiceError'; -import { BaseModel } from '@/models/Model'; import { DynamicFilterRoleAbstractor } from './DynamicFilter/DynamicFilterRoleAbstractor'; +import { MetableModel } from './types/DynamicList.types'; +import { ServiceError } from '../Items/ServiceError'; +import { ERRORS } from './constants'; @Injectable() export class DynamicListFilterRoles extends DynamicFilterRoleAbstractor { @@ -34,12 +34,12 @@ export class DynamicListFilterRoles extends DynamicFilterRoleAbstractor { /** * Retrieve filter roles fields key that not exists on the given model. - * @param {BaseModel} model + * @param {MetableModel} model * @param {IFilterRole} filterRoles * @returns {string[]} */ private getFilterRolesFieldsNotExist = ( - model: BaseModel, + model: MetableModel, filterRoles: IFilterRole[], ): string[] => { return filterRoles @@ -49,12 +49,12 @@ export class DynamicListFilterRoles extends DynamicFilterRoleAbstractor { /** * Validates existance the fields of filter roles. - * @param {BaseModel} model + * @param {MetableModel} model * @param {IFilterRole[]} filterRoles * @throws {ServiceError} */ private validateFilterRolesFieldsExistance = ( - model: BaseModel, + model: MetableModel, filterRoles: IFilterRole[], ) => { const invalidFieldsKeys = this.getFilterRolesFieldsNotExist( @@ -82,12 +82,12 @@ export class DynamicListFilterRoles extends DynamicFilterRoleAbstractor { /** * Dynamic list filter roles. - * @param {BaseModel} model - * @param {IFilterRole[]} filterRoles + * @param {MetableModel} model - Metable model. + * @param {IFilterRole[]} filterRoles - Filter roles. * @returns {DynamicFilterFilterRoles} */ public dynamicList = ( - model: BaseModel, + model: MetableModel, filterRoles: IFilterRole[], ): DynamicFilterAdvancedFilter => { const filterRolesParsed = R.compose(this.incrementFilterRolesIndex)( diff --git a/packages/server-nest/src/modules/DynamicListing/DynamicListSortBy.service.ts b/packages/server-nest/src/modules/DynamicListing/DynamicListSortBy.service.ts index 5bf5c3c1b..9069b3b94 100644 --- a/packages/server-nest/src/modules/DynamicListing/DynamicListSortBy.service.ts +++ b/packages/server-nest/src/modules/DynamicListing/DynamicListSortBy.service.ts @@ -4,10 +4,11 @@ import { ERRORS } from './constants'; import { DynamicFilterSortBy } from './DynamicFilter'; import { ServiceError } from '../Items/ServiceError'; import { BaseModel } from '@/models/Model'; -import { DynamicFilterRoleAbstractor } from './DynamicFilter/DynamicFilterRoleAbstractor'; +import { DynamicFilterAbstractor } from './DynamicFilter/DynamicFilterAbstractor'; +import { MetableModel } from './types/DynamicList.types'; @Injectable() -export class DynamicListSortBy extends DynamicFilterRoleAbstractor { +export class DynamicListSortBy extends DynamicFilterAbstractor { /** * Dynamic list sort by. * @param {BaseModel} model @@ -16,7 +17,7 @@ export class DynamicListSortBy extends DynamicFilterRoleAbstractor { * @returns {DynamicFilterSortBy} */ public dynamicSortBy( - model: BaseModel, + model: MetableModel, columnSortBy: string, sortOrder: ISortOrder, ) { diff --git a/packages/server-nest/src/modules/DynamicListing/models/MetadataModel.ts b/packages/server-nest/src/modules/DynamicListing/models/MetadataModel.ts index 754237aad..fbebba33c 100644 --- a/packages/server-nest/src/modules/DynamicListing/models/MetadataModel.ts +++ b/packages/server-nest/src/modules/DynamicListing/models/MetadataModel.ts @@ -11,7 +11,7 @@ const defaultModelMeta = { fields2: {}, }; -export interface IMetadataModel extends BaseModel { +export interface IMetadataModel { meta: IModelMeta; parsedMeta: IModelMeta; fields: { [key: string]: IModelMetaField }; diff --git a/packages/server-nest/src/modules/DynamicListing/models/SearchableBaseModel.ts b/packages/server-nest/src/modules/DynamicListing/models/SearchableBaseModel.ts index d93d83f57..2991a75f6 100644 --- a/packages/server-nest/src/modules/DynamicListing/models/SearchableBaseModel.ts +++ b/packages/server-nest/src/modules/DynamicListing/models/SearchableBaseModel.ts @@ -1,9 +1,13 @@ import { BaseModel } from '@/models/Model'; import { IModelMeta } from '@/interfaces/Model'; -import { ISearchRole } from '../DynamicFilter.types'; +import { ISearchRole } from '../DynamicFilter/DynamicFilter.types'; type GConstructor = new (...args: any[]) => T; +export interface ISearchableBaseModel { + searchRoles: ISearchRole[]; +} + export const SearchableBaseModelMixin = >( Model: T, ) => @@ -11,7 +15,7 @@ export const SearchableBaseModelMixin = >( /** * Searchable model. */ - static get searchable(): IModelMeta { + static get searchable(): boolean { throw true; } diff --git a/packages/server-nest/src/modules/DynamicListing/types/DynamicList.types.ts b/packages/server-nest/src/modules/DynamicListing/types/DynamicList.types.ts index ae4a255f6..6e0f5a5ba 100644 --- a/packages/server-nest/src/modules/DynamicListing/types/DynamicList.types.ts +++ b/packages/server-nest/src/modules/DynamicListing/types/DynamicList.types.ts @@ -1,5 +1,9 @@ import { ISortOrder } from '@/interfaces/Model'; +import { BaseModel } from '@/models/Model'; +import { ICustomViewBaseModel } from '@/modules/CustomViews/CustomViewBaseModel'; import { IFilterRole } from '../DynamicFilter/DynamicFilter.types'; +import { IMetadataModel } from '../models/MetadataModel'; +import { ISearchableBaseModel } from '../models/SearchableBaseModel'; export interface IDynamicListFilter { customViewId?: number; @@ -8,4 +12,9 @@ export interface IDynamicListFilter { sortOrder: string; stringifiedFilterRoles: string; searchKeyword?: string; -} \ No newline at end of file +} + +export type MetableModel = typeof BaseModel & + IMetadataModel & + ISearchableBaseModel & + ICustomViewBaseModel; diff --git a/packages/server-nest/src/modules/Expenses/models/Expense.model.ts b/packages/server-nest/src/modules/Expenses/models/Expense.model.ts index 1ca0433d5..04da1f635 100644 --- a/packages/server-nest/src/modules/Expenses/models/Expense.model.ts +++ b/packages/server-nest/src/modules/Expenses/models/Expense.model.ts @@ -1,22 +1,10 @@ -import { Model, mixin, raw } from 'objection'; -// import TenantModel from 'models/TenantModel'; -// import { viewRolesBuilder } from '@/lib/ViewRolesBuilder'; -// import ModelSetting from './ModelSetting'; -// import ExpenseSettings from './Expense.Settings'; -// import CustomViewBaseModel from './CustomViewBaseModel'; -// import { DEFAULT_VIEWS } from '@/services/Expenses/constants'; -// import ModelSearchable from './ModelSearchable'; +import { Model, raw } from 'objection'; import moment from 'moment'; -import { BaseModel } from '@/models/Model'; import { ExpenseCategory } from './ExpenseCategory.model'; import { Account } from '@/modules/Accounts/models/Account.model'; +import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel'; -export class Expense extends BaseModel { - // ModelSetting, - // CustomViewBaseModel, - // ModelSearchable, - // ]) { - +export class Expense extends TenantBaseModel { totalAmount!: number; currencyCode!: string; exchangeRate!: number; diff --git a/packages/server-nest/src/modules/InventoryAdjutments/InventoryAdjustmentService.ts b/packages/server-nest/src/modules/InventoryAdjutments/InventoryAdjustmentService.ts deleted file mode 100644 index 98342bf3a..000000000 --- a/packages/server-nest/src/modules/InventoryAdjutments/InventoryAdjustmentService.ts +++ /dev/null @@ -1,154 +0,0 @@ -// import { Inject, Service } from 'typedi'; -// import { omit } from 'lodash'; -// import moment from 'moment'; -// import * as R from 'ramda'; -// import { Knex } from 'knex'; -// import { ServiceError } from '@/exceptions'; -// import { -// IInventoryAdjustment, -// IPaginationMeta, -// IInventoryAdjustmentsFilter, -// IInventoryTransaction, -// IInventoryAdjustmentEventPublishedPayload, -// IInventoryAdjustmentEventDeletedPayload, -// IInventoryAdjustmentDeletingPayload, -// IInventoryAdjustmentPublishingPayload, -// } from '@/interfaces'; -// import events from '@/subscribers/events'; -// import DynamicListingService from '@/services/DynamicListing/DynamicListService'; -// import HasTenancyService from '@/services/Tenancy/TenancyService'; -// import InventoryService from './Inventory'; -// import UnitOfWork from '@/services/UnitOfWork'; -// import { EventPublisher } from '@/lib/EventPublisher/EventPublisher'; -// import InventoryAdjustmentTransformer from './InventoryAdjustmentTransformer'; -// import { BranchTransactionDTOTransform } from '@/services/Branches/Integrations/BranchTransactionDTOTransform'; -// import { WarehouseTransactionDTOTransform } from '@/services/Warehouses/Integrations/WarehouseTransactionDTOTransform'; -// import { TransformerInjectable } from '@/lib/Transformer/TransformerInjectable'; - -// const ERRORS = { -// INVENTORY_ADJUSTMENT_NOT_FOUND: 'INVENTORY_ADJUSTMENT_NOT_FOUND', -// ITEM_SHOULD_BE_INVENTORY_TYPE: 'ITEM_SHOULD_BE_INVENTORY_TYPE', -// INVENTORY_ADJUSTMENT_ALREADY_PUBLISHED: -// 'INVENTORY_ADJUSTMENT_ALREADY_PUBLISHED', -// }; - -// @Service() -// export default class InventoryAdjustmentService { -// @Inject() -// private tenancy: HasTenancyService; - -// @Inject() -// private eventPublisher: EventPublisher; - -// @Inject() -// private inventoryService: InventoryService; - -// @Inject() -// private dynamicListService: DynamicListingService; - -// @Inject() -// private uow: UnitOfWork; - -// @Inject() -// private branchDTOTransform: BranchTransactionDTOTransform; - -// @Inject() -// private warehouseDTOTransform: WarehouseTransactionDTOTransform; - -// @Inject() -// private transfromer: TransformerInjectable; - -// /** -// * Retrieve the inventory adjustment or throw not found service error. -// * @param {number} tenantId - -// * @param {number} adjustmentId - -// */ -// async getInventoryAdjustmentOrThrowError( -// tenantId: number, -// adjustmentId: number -// ) { -// const { InventoryAdjustment } = this.tenancy.models(tenantId); - -// const inventoryAdjustment = await InventoryAdjustment.query() -// .findById(adjustmentId) -// .withGraphFetched('entries'); - -// if (!inventoryAdjustment) { -// throw new ServiceError(ERRORS.INVENTORY_ADJUSTMENT_NOT_FOUND); -// } -// return inventoryAdjustment; -// } - - -// /** -// * Parses inventory adjustments list filter DTO. -// * @param filterDTO - -// */ -// private parseListFilterDTO(filterDTO) { -// return R.compose(this.dynamicListService.parseStringifiedFilter)(filterDTO); -// } - -// /** -// * Writes the inventory transactions from the inventory adjustment transaction. -// * @param {number} tenantId - -// * @param {IInventoryAdjustment} inventoryAdjustment - -// * @param {boolean} override - -// * @param {Knex.Transaction} trx - -// * @return {Promise} -// */ -// public async writeInventoryTransactions( -// tenantId: number, -// inventoryAdjustment: IInventoryAdjustment, -// override: boolean = false, -// trx?: Knex.Transaction -// ): Promise { -// const commonTransaction = { -// direction: inventoryAdjustment.inventoryDirection, -// date: inventoryAdjustment.date, -// transactionType: 'InventoryAdjustment', -// transactionId: inventoryAdjustment.id, -// createdAt: inventoryAdjustment.createdAt, -// costAccountId: inventoryAdjustment.adjustmentAccountId, - -// branchId: inventoryAdjustment.branchId, -// warehouseId: inventoryAdjustment.warehouseId, -// }; -// const inventoryTransactions = []; - -// inventoryAdjustment.entries.forEach((entry) => { -// inventoryTransactions.push({ -// ...commonTransaction, -// itemId: entry.itemId, -// quantity: entry.quantity, -// rate: entry.cost, -// }); -// }); -// // Saves the given inventory transactions to the storage. -// await this.inventoryService.recordInventoryTransactions( -// tenantId, -// inventoryTransactions, -// override, -// trx -// ); -// } - -// /** -// * Reverts the inventory transactions from the inventory adjustment transaction. -// * @param {number} tenantId -// * @param {number} inventoryAdjustmentId -// */ -// async revertInventoryTransactions( -// tenantId: number, -// inventoryAdjustmentId: number, -// trx?: Knex.Transaction -// ): Promise<{ oldInventoryTransactions: IInventoryTransaction[] }> { -// return this.inventoryService.deleteInventoryTransactions( -// tenantId, -// inventoryAdjustmentId, -// 'InventoryAdjustment', -// trx -// ); -// } - - -// } diff --git a/packages/server-nest/src/modules/InventoryAdjutments/InventoryAdjustments.controller.ts b/packages/server-nest/src/modules/InventoryAdjutments/InventoryAdjustments.controller.ts index 38c34afca..3dfdb522a 100644 --- a/packages/server-nest/src/modules/InventoryAdjutments/InventoryAdjustments.controller.ts +++ b/packages/server-nest/src/modules/InventoryAdjutments/InventoryAdjustments.controller.ts @@ -16,8 +16,10 @@ import { import { InventoryAdjustment } from './models/InventoryAdjustment'; import { PublicRoute } from '../Auth/Jwt.guard'; import { IPaginationMeta } from '@/interfaces/Model'; +import { ApiOperation, ApiTags } from '@nestjs/swagger'; @Controller('inventory-adjustments') +@ApiTags('inventory-adjustments') @PublicRoute() export class InventoryAdjustmentsController { constructor( @@ -25,6 +27,7 @@ export class InventoryAdjustmentsController { ) {} @Post('quick') + @ApiOperation({ summary: 'Create a quick inventory adjustment.' }) public async createQuickInventoryAdjustment( @Body() quickAdjustmentDTO: IQuickInventoryAdjustmentDTO, ): Promise { @@ -34,6 +37,7 @@ export class InventoryAdjustmentsController { } @Delete(':id') + @ApiOperation({ summary: 'Delete the given inventory adjustment.' }) public async deleteInventoryAdjustment( @Param('id') inventoryAdjustmentId: number, ): Promise { @@ -43,6 +47,7 @@ export class InventoryAdjustmentsController { } @Get() + @ApiOperation({ summary: 'Retrieves the inventory adjustments.' }) public async getInventoryAdjustments( @Query() filterDTO: IInventoryAdjustmentsFilter, ): Promise<{ @@ -55,6 +60,7 @@ export class InventoryAdjustmentsController { } @Get(':id') + @ApiOperation({ summary: 'Retrieves the inventory adjustment details.' }) public async getInventoryAdjustment( @Param('id') inventoryAdjustmentId: number, ): Promise { @@ -64,6 +70,7 @@ export class InventoryAdjustmentsController { } @Put(':id/publish') + @ApiOperation({ summary: 'Publish the given inventory adjustment.' }) public async publishInventoryAdjustment( @Param('id') inventoryAdjustmentId: number, ): Promise { diff --git a/packages/server-nest/src/modules/InventoryAdjutments/models/InventoryAdjustment.ts b/packages/server-nest/src/modules/InventoryAdjutments/models/InventoryAdjustment.ts index e18ee0c59..a49db213c 100644 --- a/packages/server-nest/src/modules/InventoryAdjutments/models/InventoryAdjustment.ts +++ b/packages/server-nest/src/modules/InventoryAdjutments/models/InventoryAdjustment.ts @@ -1,11 +1,8 @@ import { Model } from 'objection'; -// import TenantModel from 'models/TenantModel'; -// import InventoryAdjustmentSettings from './InventoryAdjustment.Settings'; -// import ModelSetting from './ModelSetting'; -import { BaseModel } from '@/models/Model'; import { InventoryAdjustmentEntry } from './InventoryAdjustmentEntry'; +import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel'; -export class InventoryAdjustment extends BaseModel { +export class InventoryAdjustment extends TenantBaseModel { date!: string; type!: string; adjustmentAccountId!: number; @@ -32,28 +29,28 @@ export class InventoryAdjustment extends BaseModel { /** * Timestamps columns. */ - get timestamps() { + get timestamps(): Array { return ['created_at']; } /** * Virtual attributes. */ - static get virtualAttributes() { + static get virtualAttributes(): Array { return ['formattedType', 'inventoryDirection', 'isPublished']; } /** * Retrieve formatted adjustment type. */ - get formattedType() { + get formattedType(): string { return InventoryAdjustment.getFormattedType(this.type); } /** * Retrieve formatted reference type. */ - get inventoryDirection() { + get inventoryDirection(): string { return InventoryAdjustment.getInventoryDirection(this.type); } @@ -61,7 +58,7 @@ export class InventoryAdjustment extends BaseModel { * Detarmines whether the adjustment is published. * @return {boolean} */ - get isPublished() { + get isPublished(): boolean { return !!this.publishedAt; } diff --git a/packages/server-nest/src/modules/InventoryAdjutments/queries/GetInventoryAdjustments.service.ts b/packages/server-nest/src/modules/InventoryAdjutments/queries/GetInventoryAdjustments.service.ts index c5f3f368e..b890edba8 100644 --- a/packages/server-nest/src/modules/InventoryAdjutments/queries/GetInventoryAdjustments.service.ts +++ b/packages/server-nest/src/modules/InventoryAdjutments/queries/GetInventoryAdjustments.service.ts @@ -31,7 +31,7 @@ export class GetInventoryAdjustmentsService { // Dynamic list service. const dynamicFilter = await this.dynamicListService.dynamicList( - InventoryAdjustment, + this.inventoryAdjustmentModel, filter, ); const { results, pagination } = await this.inventoryAdjustmentModel diff --git a/packages/server-nest/src/modules/InventoryCost/Inventory.ts b/packages/server-nest/src/modules/InventoryCost/Inventory.ts index 7b4352f08..0c8d48361 100644 --- a/packages/server-nest/src/modules/InventoryCost/Inventory.ts +++ b/packages/server-nest/src/modules/InventoryCost/Inventory.ts @@ -27,12 +27,8 @@ import InventoryCostMethod from './InventoryCostMethod'; export class InventoryService { constructor( private readonly eventEmitter: EventEmitter2, - private readonly itemsEntriesService: ItemsEntriesService, private readonly uow: UnitOfWork, - @Inject(Item.name) - private readonly itemModel: typeof Item, - @Inject(InventoryTransaction.name) private readonly inventoryTransactionModel: typeof InventoryTransaction, @@ -340,7 +336,7 @@ export class InventoryService { /** * Mark item cost computing is running. - * @param {boolean} isRunning - + * @param {boolean} isRunning - */ async markItemsCostComputeRunning(isRunning: boolean = true) { this.settings.set({ diff --git a/packages/server-nest/src/modules/InventoryCost/InventoryCost.module.ts b/packages/server-nest/src/modules/InventoryCost/InventoryCost.module.ts index e31161bc6..96ed6738e 100644 --- a/packages/server-nest/src/modules/InventoryCost/InventoryCost.module.ts +++ b/packages/server-nest/src/modules/InventoryCost/InventoryCost.module.ts @@ -1,9 +1,11 @@ import { Module } from '@nestjs/common'; -import { InventoryCostGLBeforeWriteSubscriber } from './subscribers/InventoryCostGLBeforeWriteSubscriber'; import { InventoryCostGLStorage } from './InventoryCostGLStorage.service'; import { RegisterTenancyModel } from '../Tenancy/TenancyModels/Tenancy.module'; import { InventoryCostLotTracker } from './models/InventoryCostLotTracker'; import { InventoryTransaction } from './models/InventoryTransaction'; +import { InventoryCostGLBeforeWriteSubscriber } from './subscribers/InventoryCostGLBeforeWriteSubscriber'; +import { InventoryItemsQuantitySyncService } from './InventoryItemsQuantitySync.service'; +import { InventoryCostMethod } from './InventoryCostMethod'; const models = [ RegisterTenancyModel(InventoryCostLotTracker), @@ -15,6 +17,8 @@ const models = [ ...models, InventoryCostGLBeforeWriteSubscriber, InventoryCostGLStorage, + InventoryItemsQuantitySyncService, + InventoryCostMethod, ], exports: [...models], }) diff --git a/packages/server-nest/src/modules/InventoryCost/InventoryCostApplication.ts b/packages/server-nest/src/modules/InventoryCost/InventoryCostApplication.ts index 23e03f45f..f262b929d 100644 --- a/packages/server-nest/src/modules/InventoryCost/InventoryCostApplication.ts +++ b/packages/server-nest/src/modules/InventoryCost/InventoryCostApplication.ts @@ -1,17 +1,17 @@ -import { IInventoryItemCostMeta } from '@/interfaces'; -import { Service, Inject } from 'typedi'; +import { Injectable } from '@nestjs/common'; import { InventoryItemCostService } from './InventoryCosts.service'; +import { IInventoryItemCostMeta } from './types/InventoryCost.types'; -@Service() +@Injectable() export class InventoryCostApplication { - @Inject() - inventoryCost: InventoryItemCostService; + constructor( + private readonly inventoryCost: InventoryItemCostService, + ) {} /** * Retrieves the items inventory valuation list. - * @param {number} tenantId - * @param {number[]} itemsId - * @param {Date} date + * @param {number[]} itemsId + * @param {Date} date * @returns {Promise} */ public getItemsInventoryValuationList = async ( @@ -19,7 +19,6 @@ export class InventoryCostApplication { date: Date ): Promise => { const itemsMap = await this.inventoryCost.getItemsInventoryValuation( - tenantId, itemsId, date ); diff --git a/packages/server-nest/src/modules/InventoryCost/InventoryCostMethod.ts b/packages/server-nest/src/modules/InventoryCost/InventoryCostMethod.ts index b90711db7..e52a77134 100644 --- a/packages/server-nest/src/modules/InventoryCost/InventoryCostMethod.ts +++ b/packages/server-nest/src/modules/InventoryCost/InventoryCostMethod.ts @@ -1,21 +1,14 @@ import { omit } from 'lodash'; -import { Container } from 'typedi'; -import TenancyService from '@/services/Tenancy/TenancyService'; -import { IInventoryLotCost } from '@/interfaces'; +import { InventoryCostLotTracker } from './models/InventoryCostLotTracker'; +import { Inject } from '@nestjs/common'; +import { Knex } from 'knex'; -export default class InventoryCostMethod { - tenancy: TenancyService; - tenantModels: any; - - /** - * Constructor method. - * @param {number} tenantId - The given tenant id. - */ - constructor(tenantId: number, startingDate: Date, itemId: number) { - const tenancyService = Container.get(TenancyService); - - this.tenantModels = tenancyService.models(tenantId); - } +export class InventoryCostMethod { + constructor( + @Inject(InventoryCostLotTracker.name) + private readonly inventoryCostLotTracker: typeof InventoryCostLotTracker + ) {} + /** * Stores the inventory lots costs transactions in bulk. @@ -23,19 +16,19 @@ export default class InventoryCostMethod { * @return {Promise[]} */ public storeInventoryLotsCost( - costLotsTransactions: IInventoryLotCost[] + costLotsTransactions: InventoryCostLotTracker[], + trx: Knex.Transaction ): Promise { - const { InventoryCostLotTracker } = this.tenantModels; const opers: any = []; costLotsTransactions.forEach((transaction: any) => { if (transaction.lotTransId && transaction.decrement) { - const decrementOper = InventoryCostLotTracker.query(this.trx) + const decrementOper = this.inventoryCostLotTracker.query(trx) .where('id', transaction.lotTransId) .decrement('remaining', transaction.decrement); opers.push(decrementOper); } else if (!transaction.lotTransId) { - const operation = InventoryCostLotTracker.query(this.trx).insert({ + const operation = this.inventoryCostLotTracker.query(trx).insert({ ...omit(transaction, ['decrement', 'invTransId', 'lotTransId']), }); opers.push(operation); diff --git a/packages/server-nest/src/modules/InventoryCost/InventoryItemsQuantitySync.service.ts b/packages/server-nest/src/modules/InventoryCost/InventoryItemsQuantitySync.service.ts index 97ab23c51..a16ccc2c3 100644 --- a/packages/server-nest/src/modules/InventoryCost/InventoryItemsQuantitySync.service.ts +++ b/packages/server-nest/src/modules/InventoryCost/InventoryItemsQuantitySync.service.ts @@ -1,9 +1,10 @@ import { toSafeInteger } from 'lodash'; -import { IInventoryTransaction, IItemsQuantityChanges } from '@/interfaces'; +import { IItemsQuantityChanges } from './types/InventoryCost.types'; import { Knex } from 'knex'; import { Inject } from '@nestjs/common'; import { Item } from '../Items/models/Item'; import { Injectable } from '@nestjs/common'; +import { InventoryTransaction } from './models/InventoryTransaction'; /** * Syncs the inventory transactions with inventory items quantity. @@ -11,8 +12,7 @@ import { Injectable } from '@nestjs/common'; @Injectable() export class InventoryItemsQuantitySyncService { constructor( - @Inject(Item.name) - private readonly itemModel: typeof Item, + @Inject(Item.name) private readonly itemModel: typeof Item, ) {} /** @@ -21,12 +21,14 @@ export class InventoryItemsQuantitySyncService { * @return {IInventoryTransaction[]} */ public reverseInventoryTransactions( - inventroyTransactions: IInventoryTransaction[], - ): IInventoryTransaction[] { - return inventroyTransactions.map((transaction) => ({ - ...transaction, - direction: transaction.direction === 'OUT' ? 'IN' : 'OUT', - })); + inventroyTransactions: InventoryTransaction[], + ): InventoryTransaction[] { + return inventroyTransactions.map((transaction) => { + const cloned = transaction.$clone(); + cloned.direction = cloned.direction === 'OUT' ? 'IN' : 'OUT'; + + return cloned; + }); } /** @@ -35,7 +37,7 @@ export class InventoryItemsQuantitySyncService { * @return {IItemsQuantityChanges[]} */ public getReverseItemsQuantityChanges( - inventroyTransactions: IInventoryTransaction[], + inventroyTransactions: InventoryTransaction[], ): IItemsQuantityChanges[] { const reversedTransactions = this.reverseInventoryTransactions( inventroyTransactions, @@ -49,12 +51,12 @@ export class InventoryItemsQuantitySyncService { * @return {IItemsQuantityChanges[]} */ public getItemsQuantityChanges( - inventroyTransactions: IInventoryTransaction[], + inventroyTransactions: InventoryTransaction[], ): IItemsQuantityChanges[] { const balanceMap: { [itemId: number]: number } = {}; inventroyTransactions.forEach( - (inventoryTransaction: IInventoryTransaction) => { + (inventoryTransaction: InventoryTransaction) => { const { itemId, direction, quantity } = inventoryTransaction; if (!balanceMap[itemId]) { diff --git a/packages/server-nest/src/modules/InventoryCost/models/InventoryCostLotTracker.ts b/packages/server-nest/src/modules/InventoryCost/models/InventoryCostLotTracker.ts index bf604ff9a..4703f1ded 100644 --- a/packages/server-nest/src/modules/InventoryCost/models/InventoryCostLotTracker.ts +++ b/packages/server-nest/src/modules/InventoryCost/models/InventoryCostLotTracker.ts @@ -55,7 +55,16 @@ export class InventoryCostLotTracker extends BaseModel { query.groupBy('date'); query.groupBy('item_id'); }, - filterDateRange(query, startDate, endDate, type: unitOfTime.StartOf = 'day') { + + /** + * Filters transactions by the given date range. + */ + filterDateRange( + query, + startDate, + endDate, + type: unitOfTime.StartOf = 'day', + ) { const dateFormat = 'YYYY-MM-DD'; const fromDate = moment(startDate).startOf(type).format(dateFormat); const toDate = moment(endDate).endOf(type).format(dateFormat); @@ -71,7 +80,7 @@ export class InventoryCostLotTracker extends BaseModel { /** * Filters transactions by the given branches. */ - filterByBranches(query, branchesIds) { + filterByBranches(query, branchesIds: number | Array) { const formattedBranchesIds = castArray(branchesIds); query.whereIn('branchId', formattedBranchesIds); @@ -80,7 +89,7 @@ export class InventoryCostLotTracker extends BaseModel { /** * Filters transactions by the given warehosues. */ - filterByWarehouses(query, branchesIds) { + filterByWarehouses(query, branchesIds: number | Array) { const formattedWarehousesIds = castArray(branchesIds); query.whereIn('warehouseId', formattedWarehousesIds); @@ -92,15 +101,17 @@ export class InventoryCostLotTracker extends BaseModel { * Relationship mapping. */ static get relationMappings() { - const Item = require('models/Item'); - const SaleInvoice = require('models/SaleInvoice'); - const ItemEntry = require('models/ItemEntry'); - const SaleReceipt = require('models/SaleReceipt'); + const { Item } = require('../../Items/models/Item'); + const { SaleInvoice } = require('../../SaleInvoices/models/SaleInvoice'); + const { + ItemEntry, + } = require('../../TransactionItemEntry/models/ItemEntry'); + const { SaleReceipt } = require('../../SaleReceipts/models/SaleReceipt'); return { item: { relation: Model.BelongsToOneRelation, - modelClass: Item.default, + modelClass: Item, join: { from: 'inventory_cost_lot_tracker.itemId', to: 'items.id', @@ -108,7 +119,7 @@ export class InventoryCostLotTracker extends BaseModel { }, invoice: { relation: Model.BelongsToOneRelation, - modelClass: SaleInvoice.default, + modelClass: SaleInvoice, join: { from: 'inventory_cost_lot_tracker.transactionId', to: 'sales_invoices.id', @@ -116,7 +127,7 @@ export class InventoryCostLotTracker extends BaseModel { }, itemEntry: { relation: Model.BelongsToOneRelation, - modelClass: ItemEntry.default, + modelClass: ItemEntry, join: { from: 'inventory_cost_lot_tracker.entryId', to: 'items_entries.id', @@ -124,7 +135,7 @@ export class InventoryCostLotTracker extends BaseModel { }, receipt: { relation: Model.BelongsToOneRelation, - modelClass: SaleReceipt.default, + modelClass: SaleReceipt, join: { from: 'inventory_cost_lot_tracker.transactionId', to: 'sales_receipts.id', diff --git a/packages/server-nest/src/modules/InventoryCost/models/InventoryTransaction.ts b/packages/server-nest/src/modules/InventoryCost/models/InventoryTransaction.ts index c4eac468c..81baa356e 100644 --- a/packages/server-nest/src/modules/InventoryCost/models/InventoryTransaction.ts +++ b/packages/server-nest/src/modules/InventoryCost/models/InventoryTransaction.ts @@ -106,10 +106,12 @@ export class InventoryTransaction extends BaseModel { * Relationship mapping. */ static get relationMappings() { - const Item = require('models/Item'); - const ItemEntry = require('models/ItemEntry'); - const InventoryTransactionMeta = require('models/InventoryTransactionMeta'); - const InventoryCostLots = require('models/InventoryCostLotTracker'); + const { Item } = require('../../Items/models/Item'); + const { + ItemEntry, + } = require('../../TransactionItemEntry/models/ItemEntry'); + const { InventoryTransactionMeta } = require('./InventoryTransactionMeta'); + const { InventoryCostLotTracker } = require('./InventoryCostLotTracker'); return { // Transaction meta. @@ -124,7 +126,7 @@ export class InventoryTransaction extends BaseModel { // Item cost aggregated. itemCostAggregated: { relation: Model.HasOneRelation, - modelClass: InventoryCostLots.default, + modelClass: InventoryCostLotTracker, join: { from: 'inventory_transactions.itemId', to: 'inventory_cost_lot_tracker.itemId', @@ -138,7 +140,7 @@ export class InventoryTransaction extends BaseModel { }, costLotAggregated: { relation: Model.HasOneRelation, - modelClass: InventoryCostLots.default, + modelClass: InventoryCostLotTracker, join: { from: 'inventory_transactions.id', to: 'inventory_cost_lot_tracker.inventoryTransactionId', @@ -151,7 +153,7 @@ export class InventoryTransaction extends BaseModel { }, item: { relation: Model.BelongsToOneRelation, - modelClass: Item.default, + modelClass: Item, join: { from: 'inventory_transactions.itemId', to: 'items.id', @@ -159,7 +161,7 @@ export class InventoryTransaction extends BaseModel { }, itemEntry: { relation: Model.BelongsToOneRelation, - modelClass: ItemEntry.default, + modelClass: ItemEntry, join: { from: 'inventory_transactions.entryId', to: 'items_entries.id', diff --git a/packages/server-nest/src/modules/InventoryCost/models/InventoryTransactionMeta.ts b/packages/server-nest/src/modules/InventoryCost/models/InventoryTransactionMeta.ts new file mode 100644 index 000000000..1889e2bed --- /dev/null +++ b/packages/server-nest/src/modules/InventoryCost/models/InventoryTransactionMeta.ts @@ -0,0 +1,29 @@ +import { BaseModel } from '@/models/Model'; +import { Model, raw } from 'objection'; + +export class InventoryTransactionMeta extends BaseModel { + /** + * Table name + */ + static get tableName() { + return 'inventory_transaction_meta'; + } + + /** + * Relationship mapping. + */ + static get relationMappings() { + const { InventoryTransaction } = require('./InventoryTransaction'); + + return { + inventoryTransaction: { + relation: Model.BelongsToOneRelation, + modelClass: InventoryTransaction, + join: { + from: 'inventory_transaction_meta.inventoryTransactionId', + to: 'inventory_transactions.inventoryTransactionId' + } + } + }; + } +} diff --git a/packages/server-nest/src/modules/ItemCategories/models/ItemCategory.model.ts b/packages/server-nest/src/modules/ItemCategories/models/ItemCategory.model.ts index 462aa8fdc..cb57c6d68 100644 --- a/packages/server-nest/src/modules/ItemCategories/models/ItemCategory.model.ts +++ b/packages/server-nest/src/modules/ItemCategories/models/ItemCategory.model.ts @@ -1,10 +1,7 @@ -import { BaseModel } from '@/models/Model'; -import { Model, mixin } from 'objection'; -// import TenantModel from 'models/TenantModel'; -// import ModelSetting from './ModelSetting'; -// import ItemCategorySettings from './ItemCategory.Settings'; +import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel'; +import { Model } from 'objection'; -export class ItemCategory extends BaseModel { +export class ItemCategory extends TenantBaseModel { name!: string; description!: string; diff --git a/packages/server-nest/src/modules/Items/models/Item.ts b/packages/server-nest/src/modules/Items/models/Item.ts index 5b9c61e8f..2bd448c71 100644 --- a/packages/server-nest/src/modules/Items/models/Item.ts +++ b/packages/server-nest/src/modules/Items/models/Item.ts @@ -1,19 +1,7 @@ -import * as R from 'ramda'; -import { BaseModel } from '@/models/Model'; import { Warehouse } from '@/modules/Warehouses/models/Warehouse.model'; -import { CustomViewBaseModelMixin } from '@/modules/CustomViews/CustomViewBaseModel'; -import { SearchableBaseModelMixin } from '@/modules/DynamicListing/models/SearchableBaseModel'; -import { ResourceableModelMixin } from '@/modules/Resource/models/ResourcableModel'; -import { MetadataModelMixin } from '@/modules/DynamicListing/models/MetadataModel'; +import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel'; -const ExtendedItem = R.pipe( - CustomViewBaseModelMixin, - SearchableBaseModelMixin, - ResourceableModelMixin, - MetadataModelMixin -)(BaseModel); - -export class Item extends ExtendedItem { +export class Item extends TenantBaseModel{ public readonly quantityOnHand: number; public readonly name: string; public readonly active: boolean; diff --git a/packages/server-nest/src/modules/Mail/MailTransporter.service.ts b/packages/server-nest/src/modules/Mail/MailTransporter.service.ts index cbae45ea2..3bfd7969e 100644 --- a/packages/server-nest/src/modules/Mail/MailTransporter.service.ts +++ b/packages/server-nest/src/modules/Mail/MailTransporter.service.ts @@ -1,8 +1,9 @@ import { Transporter } from 'nodemailer'; import { Mail } from './Mail'; -import { Inject } from '@nestjs/common'; +import { Inject, Injectable } from '@nestjs/common'; import { MAIL_TRANSPORTER_PROVIDER } from './Mail.constants'; +@Injectable() export class MailTransporter { constructor( @Inject(MAIL_TRANSPORTER_PROVIDER) diff --git a/packages/server-nest/src/modules/MailNotification/ContactMailNotification.ts b/packages/server-nest/src/modules/MailNotification/ContactMailNotification.ts index be2e29c54..9fab1a595 100644 --- a/packages/server-nest/src/modules/MailNotification/ContactMailNotification.ts +++ b/packages/server-nest/src/modules/MailNotification/ContactMailNotification.ts @@ -4,6 +4,7 @@ import { MailTenancy } from '../MailTenancy/MailTenancy.service'; import { TenancyContext } from '../Tenancy/TenancyContext.service'; import { Customer } from '../Customers/models/Customer'; import { CommonMailOptions } from './MailNotification.types'; +import { formatMessage } from '@/utils/format-message'; @Injectable() export class ContactMailNotification { @@ -56,8 +57,8 @@ export class ContactMailNotification { ...commonFormatArgs, ...formatterArgs, }; - const subjectFormatted = formatSmsMessage(mailOptions?.subject, formatArgs); - const messageFormatted = formatSmsMessage(mailOptions?.message, formatArgs); + const subjectFormatted = formatMessage(mailOptions?.subject, formatArgs); + const messageFormatted = formatMessage(mailOptions?.message, formatArgs); return { ...mailOptions, diff --git a/packages/server-nest/src/modules/MailNotification/utils.ts b/packages/server-nest/src/modules/MailNotification/utils.ts index 63e9550ba..b4a24027d 100644 --- a/packages/server-nest/src/modules/MailNotification/utils.ts +++ b/packages/server-nest/src/modules/MailNotification/utils.ts @@ -1,7 +1,7 @@ import { castArray, isEmpty } from 'lodash'; -import { ServiceError } from '@/exceptions'; -import { CommonMailOptions } from '@/interfaces'; import { ERRORS } from './constants'; +import { CommonMailOptions } from './MailNotification.types'; +import { ServiceError } from '../Items/ServiceError'; /** * Merges the mail options with incoming options. diff --git a/packages/server-nest/src/modules/ManualJournals/models/ManualJournal.ts b/packages/server-nest/src/modules/ManualJournals/models/ManualJournal.ts index 41540d86f..b8cd7c336 100644 --- a/packages/server-nest/src/modules/ManualJournals/models/ManualJournal.ts +++ b/packages/server-nest/src/modules/ManualJournals/models/ManualJournal.ts @@ -7,10 +7,10 @@ import { Model, mixin } from 'objection'; // import { DEFAULT_VIEWS } from '@/services/ManualJournals/constants'; // import ModelSearchable from './ModelSearchable'; import { ManualJournalEntry } from './ManualJournalEntry'; -import { BaseModel } from '@/models/Model'; import { Document } from '@/modules/ChromiumlyTenancy/models/Document'; +import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel'; -export class ManualJournal extends BaseModel { +export class ManualJournal extends TenantBaseModel { date: Date; journalNumber: string; journalType: string; diff --git a/packages/server-nest/src/modules/ManualJournals/queries/GetManualJournals.service.ts b/packages/server-nest/src/modules/ManualJournals/queries/GetManualJournals.service.ts index 9072cac03..89b5cdbd7 100644 --- a/packages/server-nest/src/modules/ManualJournals/queries/GetManualJournals.service.ts +++ b/packages/server-nest/src/modules/ManualJournals/queries/GetManualJournals.service.ts @@ -41,7 +41,7 @@ export class GetManualJournals { // Dynamic service. const dynamicService = await this.dynamicListService.dynamicList( - ManualJournal, + this.manualJournalModel, filter, ); const { results, pagination } = await this.manualJournalModel diff --git a/packages/server-nest/src/modules/PaymentReceived/PaymentsReceived.controller.ts b/packages/server-nest/src/modules/PaymentReceived/PaymentsReceived.controller.ts index 0b12b608d..613458662 100644 --- a/packages/server-nest/src/modules/PaymentReceived/PaymentsReceived.controller.ts +++ b/packages/server-nest/src/modules/PaymentReceived/PaymentsReceived.controller.ts @@ -13,10 +13,13 @@ import { PaymentReceivesApplication } from './PaymentReceived.application'; import { IPaymentReceivedCreateDTO, IPaymentReceivedEditDTO, + IPaymentsReceivedFilter, } from './types/PaymentReceived.types'; import { PublicRoute } from '../Auth/Jwt.guard'; +import { ApiTags } from '@nestjs/swagger'; @Controller('payments-received') +@ApiTags('payments-received') @PublicRoute() export class PaymentReceivesController { constructor(private paymentReceivesApplication: PaymentReceivesApplication) {} diff --git a/packages/server-nest/src/modules/PaymentReceived/commands/PaymentReceivedMailNotification.ts b/packages/server-nest/src/modules/PaymentReceived/commands/PaymentReceivedMailNotification.ts index c02e92098..c33b1d003 100644 --- a/packages/server-nest/src/modules/PaymentReceived/commands/PaymentReceivedMailNotification.ts +++ b/packages/server-nest/src/modules/PaymentReceived/commands/PaymentReceivedMailNotification.ts @@ -3,7 +3,7 @@ import { DEFAULT_PAYMENT_MAIL_CONTENT, DEFAULT_PAYMENT_MAIL_SUBJECT, } from '../constants'; -import { transformPaymentReceivedToMailDataArgs } from './utils'; +import { transformPaymentReceivedToMailDataArgs } from '../utils'; import { EventEmitter2 } from '@nestjs/event-emitter'; import { events } from '@/common/events/events'; import { ContactMailNotification } from '@/modules/MailNotification/ContactMailNotification'; @@ -14,16 +14,19 @@ import { PaymentReceiveMailOptsDTO } from '../types/PaymentReceived.types'; import { PaymentReceiveMailOpts } from '../types/PaymentReceived.types'; import { PaymentReceiveMailPresendEvent } from '../types/PaymentReceived.types'; import { SendInvoiceMailDTO } from '@/modules/SaleInvoices/SaleInvoice.types'; +import { Mail } from '@/modules/Mail/Mail'; +import { MailTransporter } from '@/modules/Mail/MailTransporter.service'; @Injectable() export class SendPaymentReceiveMailNotification { constructor( - private getPaymentService: GetPaymentReceivedService, - private contactMailNotification: ContactMailNotification, - private eventEmitter: EventEmitter2, + private readonly getPaymentService: GetPaymentReceivedService, + private readonly contactMailNotification: ContactMailNotification, + private readonly eventEmitter: EventEmitter2, + private readonly mailTransport: MailTransporter, @Inject(PaymentReceived.name) - private paymentReceiveModel: typeof PaymentReceived, + private readonly paymentReceiveModel: typeof PaymentReceived, ) {} /** @@ -148,7 +151,7 @@ export class SendPaymentReceiveMailNotification { events.paymentReceive.onMailSend, eventPayload, ); - await mail.send(); + await this.mailTransport.send(mail); // Triggers `onPaymentReceiveMailSent` event. await this.eventEmitter.emitAsync( diff --git a/packages/server-nest/src/modules/PaymentReceived/models/PaymentReceived.ts b/packages/server-nest/src/modules/PaymentReceived/models/PaymentReceived.ts index 5f51011ad..a3f82f5c2 100644 --- a/packages/server-nest/src/modules/PaymentReceived/models/PaymentReceived.ts +++ b/packages/server-nest/src/modules/PaymentReceived/models/PaymentReceived.ts @@ -1,14 +1,8 @@ -import { Model, mixin } from 'objection'; -// import TenantModel from 'models/TenantModel'; -// import ModelSetting from './ModelSetting'; -// import PaymentReceiveSettings from './PaymentReceive.Settings'; -// import CustomViewBaseModel from './CustomViewBaseModel'; -// import { DEFAULT_VIEWS } from '@/services/Sales/PaymentReceived/constants'; -// import ModelSearchable from './ModelSearchable'; -import { BaseModel } from '@/models/Model'; +import { Model } from 'objection'; import { PaymentReceivedEntry } from './PaymentReceivedEntry'; +import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel'; -export class PaymentReceived extends BaseModel { +export class PaymentReceived extends TenantBaseModel { customerId: number; paymentDate: string; amount: number; @@ -69,7 +63,9 @@ export class PaymentReceived extends BaseModel { */ static get relationMappings() { const { PaymentReceivedEntry } = require('./PaymentReceivedEntry'); - const { AccountTransaction } = require('../../Accounts/models/AccountTransaction.model'); + const { + AccountTransaction, + } = require('../../Accounts/models/AccountTransaction.model'); const { Customer } = require('../../Customers/models/Customer'); const { Account } = require('../../Accounts/models/Account.model'); const { Branch } = require('../../Branches/models/Branch.model'); diff --git a/packages/server-nest/src/modules/PaymentReceived/queries/GetPaymentsReceived.service.ts b/packages/server-nest/src/modules/PaymentReceived/queries/GetPaymentsReceived.service.ts index 84c964aae..5297e1ee0 100644 --- a/packages/server-nest/src/modules/PaymentReceived/queries/GetPaymentsReceived.service.ts +++ b/packages/server-nest/src/modules/PaymentReceived/queries/GetPaymentsReceived.service.ts @@ -31,7 +31,7 @@ export class GetPaymentsReceivedService { // Dynamic list service. const dynamicList = await this.dynamicListService.dynamicList( - PaymentReceive, + PaymentReceived, filter, ); const { results, pagination } = await this.paymentReceivedModel diff --git a/packages/server-nest/src/modules/SaleEstimates/models/SaleEstimate.ts b/packages/server-nest/src/modules/SaleEstimates/models/SaleEstimate.ts index 99b0e14de..bbf019bd1 100644 --- a/packages/server-nest/src/modules/SaleEstimates/models/SaleEstimate.ts +++ b/packages/server-nest/src/modules/SaleEstimates/models/SaleEstimate.ts @@ -1,15 +1,10 @@ -import { BaseModel } from '@/models/Model'; import moment from 'moment'; import { Model } from 'objection'; -import { ItemEntry } from '../../TransactionItemEntry/models/ItemEntry'; -import { Customer } from '../../Customers/models/Customer'; -import { Branch } from '../../Branches/models/Branch.model'; -import { Warehouse } from '../../Warehouses/models/Warehouse.model'; -import { Document } from '../../ChromiumlyTenancy/models/Document'; import { Injectable } from '@nestjs/common'; +import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel'; @Injectable() -export class SaleEstimate extends BaseModel { +export class SaleEstimate extends TenantBaseModel { exchangeRate!: number; amount!: number; @@ -207,12 +202,16 @@ export class SaleEstimate extends BaseModel { * Relationship mapping. */ static get relationMappings() { - const { ItemEntry } = require('../../TransactionItemEntry/models/ItemEntry'); + const { + ItemEntry, + } = require('../../TransactionItemEntry/models/ItemEntry'); const { Customer } = require('../../Customers/models/Customer'); const { Branch } = require('../../Branches/models/Branch.model'); const { Warehouse } = require('../../Warehouses/models/Warehouse.model'); const { Document } = require('../../ChromiumlyTenancy/models/Document'); - const { PdfTemplateModel } = require('../../PdfTemplate/models/PdfTemplate'); + const { + PdfTemplateModel, + } = require('../../PdfTemplate/models/PdfTemplate'); return { customer: { diff --git a/packages/server-nest/src/modules/SaleInvoices/SaleInvoice.types.ts b/packages/server-nest/src/modules/SaleInvoices/SaleInvoice.types.ts index 6f558313f..69c0d3da9 100644 --- a/packages/server-nest/src/modules/SaleInvoices/SaleInvoice.types.ts +++ b/packages/server-nest/src/modules/SaleInvoices/SaleInvoice.types.ts @@ -3,7 +3,10 @@ import { IItemEntryDTO } from '../TransactionItemEntry/ItemEntry.types'; import { AttachmentLinkDTO } from '../Attachments/Attachments.types'; import { SaleInvoice } from './models/SaleInvoice'; import { IDynamicListFilter } from '../DynamicListing/DynamicFilter/DynamicFilter.types'; -import { CommonMailOptionsDTO } from '../MailNotification/MailNotification.types'; +import { + CommonMailOptions, + CommonMailOptionsDTO, +} from '../MailNotification/MailNotification.types'; // import SaleInvoice from './models/SaleInvoice'; // import { SystemUser } from '../System/models/SystemUser'; // import { ISystemUser, IAccount, ITaxTransaction } from '@/interfaces'; @@ -185,34 +188,34 @@ export enum SaleInvoiceAction { NotifyBySms = 'NotifyBySms', } -// export interface SaleInvoiceMailOptions extends CommonMailOptions { -// attachInvoice?: boolean; -// formatArgs?: Record; -// } +export interface SaleInvoiceMailOptions extends CommonMailOptions { + attachInvoice?: boolean; + formatArgs?: Record; +} -// export interface SaleInvoiceMailState extends SaleInvoiceMailOptions { -// invoiceNo: string; +export interface SaleInvoiceMailState extends SaleInvoiceMailOptions { + invoiceNo: string; -// invoiceDate: string; -// invoiceDateFormatted: string; + invoiceDate: string; + invoiceDateFormatted: string; -// dueDate: string; -// dueDateFormatted: string; + dueDate: string; + dueDateFormatted: string; -// total: number; -// totalFormatted: string; + total: number; + totalFormatted: string; -// subtotal: number; -// subtotalFormatted: number; + subtotal: number; + subtotalFormatted: number; -// companyName: string; -// companyLogoUri: string; + companyName: string; + companyLogoUri: string; -// customerName: string; + customerName: string; -// // # Invoice entries -// entries?: Array<{ label: string; total: string; quantity: string | number }>; -// } + // # Invoice entries + entries?: Array<{ label: string; total: string; quantity: string | number }>; +} export interface SendInvoiceMailDTO extends CommonMailOptionsDTO { attachInvoice?: boolean; diff --git a/packages/server-nest/src/modules/SaleInvoices/SaleInvoices.application.ts b/packages/server-nest/src/modules/SaleInvoices/SaleInvoices.application.ts index 0dde4191f..5ca651226 100644 --- a/packages/server-nest/src/modules/SaleInvoices/SaleInvoices.application.ts +++ b/packages/server-nest/src/modules/SaleInvoices/SaleInvoices.application.ts @@ -3,7 +3,6 @@ import { CreateSaleInvoice } from './commands/CreateSaleInvoice.service'; import { DeleteSaleInvoice } from './commands/DeleteSaleInvoice.service'; import { GetSaleInvoice } from './queries/GetSaleInvoice.service'; import { EditSaleInvoice } from './commands/EditSaleInvoice.service'; -// import { GetSaleInvoices } from './queries/GetSaleInvoices'; import { DeliverSaleInvoice } from './commands/DeliverSaleInvoice.service'; import { GetSaleInvoicesPayable } from './queries/GetSaleInvoicesPayable.service'; import { WriteoffSaleInvoice } from './commands/WriteoffSaleInvoice.service'; @@ -11,16 +10,18 @@ import { SaleInvoicePdf } from './queries/SaleInvoicePdf.service'; import { GetInvoicePaymentsService } from './queries/GetInvoicePayments.service'; // import { SaleInvoiceNotifyBySms } from './SaleInvoiceNotifyBySms'; // import { SendInvoiceMailReminder } from './commands/SendSaleInvoiceMailReminder'; -// import { SendSaleInvoiceMail } from './commands/SendSaleInvoiceMail'; import { GetSaleInvoiceState } from './queries/GetSaleInvoiceState.service'; -// import { GetSaleInvoiceMailState } from './queries/GetSaleInvoiceMailState.service'; +import { GetSaleInvoiceMailState } from './queries/GetSaleInvoiceMailState.service'; import { ISaleInvoiceCreateDTO, ISaleInvoiceEditDTO, ISaleInvoiceWriteoffDTO, ISalesInvoicesFilter, + SaleInvoiceMailState, + SendInvoiceMailDTO, } from './SaleInvoice.types'; import { GetSaleInvoicesService } from './queries/GetSaleInvoices'; +import { SendSaleInvoiceMail } from './commands/SendSaleInvoiceMail'; @Injectable() export class SaleInvoiceApplication { @@ -36,10 +37,9 @@ export class SaleInvoiceApplication { private getInvoicePaymentsService: GetInvoicePaymentsService, private pdfSaleInvoiceService: SaleInvoicePdf, private getSaleInvoiceStateService: GetSaleInvoiceState, + private sendSaleInvoiceMailService: SendSaleInvoiceMail, + private getSaleInvoiceMailStateService: GetSaleInvoiceMailState, // private invoiceSms: SaleInvoiceNotifyBySms, - private sendInvoiceReminderService: SendInvoiceMailReminder, - // private sendSaleInvoiceMailService: SendSaleInvoiceMail, - // private getSaleInvoiceMailStateService: GetSaleInvoiceMailState, ) {} /** @@ -175,6 +175,22 @@ export class SaleInvoiceApplication { return this.pdfSaleInvoiceService.getSaleInvoiceHtml(saleInvoiceId); } + /** + * Sends the invoice mail of the given sale invoice. + * @param {number} saleInvoiceId - Sale invoice id. + * @param {SendInvoiceMailDTO} messageDTO - Message data. + * @returns {Promise} + */ + public sendSaleInvoiceMail( + saleInvoiceId: number, + messageDTO: SendInvoiceMailDTO, + ) { + return this.sendSaleInvoiceMailService.triggerMail( + saleInvoiceId, + messageDTO, + ); + } + /** * * @param {number} tenantId @@ -223,53 +239,16 @@ export class SaleInvoiceApplication { // ); // } - /** - * Sends reminder of the given invoice to the invoice's customer. - * @param {number} tenantId - * @param {number} saleInvoiceId - * @returns {} - */ - // public sendSaleInvoiceMailReminder( - // tenantId: number, - // saleInvoiceId: number, - // messageDTO: SendInvoiceMailDTO, - // ) { - // return this.sendInvoiceReminderService.triggerMail( - // tenantId, - // saleInvoiceId, - // messageDTO, - // ); - // } - - /** - * Sends the invoice mail of the given sale invoice. - * @param {number} tenantId - * @param {number} saleInvoiceId - * @param {SendInvoiceMailDTO} messageDTO - * @returns {Promise} - */ - // public sendSaleInvoiceMail( - // tenantId: number, - // saleInvoiceId: number, - // messageDTO: SendInvoiceMailDTO, - // ) { - // return this.sendSaleInvoiceMailService.triggerMail( - // tenantId, - // saleInvoiceId, - // messageDTO, - // ); - // } - /** * Retrieves the default mail options of the given sale invoice. * @param {number} saleInvoiceid * @returns {Promise} */ - // public getSaleInvoiceMailState( - // saleInvoiceid: number, - // ): Promise { - // return this.getSaleInvoiceMailStateService.getInvoiceMailState( - // saleInvoiceid, - // ); - // } + public getSaleInvoiceMailState( + saleInvoiceid: number, + ): Promise { + return this.getSaleInvoiceMailStateService.getInvoiceMailState( + saleInvoiceid, + ); + } } diff --git a/packages/server-nest/src/modules/SaleInvoices/SaleInvoices.module.ts b/packages/server-nest/src/modules/SaleInvoices/SaleInvoices.module.ts index 88c4e98e7..e39569ceb 100644 --- a/packages/server-nest/src/modules/SaleInvoices/SaleInvoices.module.ts +++ b/packages/server-nest/src/modules/SaleInvoices/SaleInvoices.module.ts @@ -37,7 +37,6 @@ import SaleInvoiceWriteoffSubscriber from './subscribers/SaleInvoiceWriteoffSubs import { SaleInvoiceWriteoffGLStorage } from './commands/writeoff/SaleInvoiceWriteoffGLStorage'; import { InvoiceInventoryTransactions } from './commands/inventory/InvoiceInventoryTransactions'; import { SendSaleEstimateMail } from '../SaleEstimates/commands/SendSaleEstimateMail'; -import { SendInvoiceMailReminder } from './commands/SendSaleInvoiceMailReminder'; import { MailModule } from '../Mail/Mail.module'; @Module({ @@ -84,7 +83,6 @@ import { MailModule } from '../Mail/Mail.module'; SaleInvoiceWriteoffSubscriber, InvoiceInventoryTransactions, SendSaleEstimateMail, - SendInvoiceMailReminder, ], }) export class SaleInvoicesModule {} diff --git a/packages/server-nest/src/modules/SaleInvoices/commands/SendInvoiceInvoiceMailCommon.service.ts b/packages/server-nest/src/modules/SaleInvoices/commands/SendInvoiceInvoiceMailCommon.service.ts index 1e7f3f3c0..f79276a79 100644 --- a/packages/server-nest/src/modules/SaleInvoices/commands/SendInvoiceInvoiceMailCommon.service.ts +++ b/packages/server-nest/src/modules/SaleInvoices/commands/SendInvoiceInvoiceMailCommon.service.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import { GetSaleInvoice } from '../queries/GetSaleInvoice.service'; import { DEFAULT_INVOICE_MAIL_CONTENT, @@ -8,6 +9,7 @@ import { GenerateShareLink } from './GenerateInvoicePaymentLink.service'; import { Inject, Injectable } from '@nestjs/common'; import { SaleInvoice } from '../models/SaleInvoice'; import { ContactMailNotification } from '@/modules/MailNotification/ContactMailNotification'; +import { SaleInvoiceMailOptions } from '../SaleInvoice.types'; @Injectable() export class SendSaleInvoiceMailCommon { @@ -15,7 +17,7 @@ export class SendSaleInvoiceMailCommon { private getSaleInvoiceService: GetSaleInvoice, private contactMailNotification: ContactMailNotification, private getInvoicePaymentMail: GetInvoicePaymentMail, - private generatePaymentLinkService: GenerateShareLink, + private generatePaymentLinkService: GenerateShareLink, @Inject(SaleInvoice.name) private readonly saleInvoiceModel: typeof SaleInvoice, @@ -91,17 +93,17 @@ export class SendSaleInvoiceMailCommon { /** * Retrieves the formatted text of the given sale invoice. - * @param {number} tenantId - Tenant id. * @param {number} invoiceId - Sale invoice id. * @param {string} text - The given text. * @returns {Promise} */ + // @ts-nocheck public getInvoiceFormatterArgs = async ( invoiceId: number, ): Promise> => { const invoice = await this.getSaleInvoiceService.getSaleInvoice(invoiceId); - const commonArgs = - await this.contactMailNotification.getCommonFormatArgs(tenantId); + const commonArgs = await this.contactMailNotification.getCommonFormatArgs(); + return { ...commonArgs, 'Customer Name': invoice.customer.displayName, @@ -114,4 +116,3 @@ export class SendSaleInvoiceMailCommon { }; }; } - \ No newline at end of file diff --git a/packages/server-nest/src/modules/SaleInvoices/commands/SendSaleInvoiceMail.ts b/packages/server-nest/src/modules/SaleInvoices/commands/SendSaleInvoiceMail.ts index 8bb7475fd..2f9aa6589 100644 --- a/packages/server-nest/src/modules/SaleInvoices/commands/SendSaleInvoiceMail.ts +++ b/packages/server-nest/src/modules/SaleInvoices/commands/SendSaleInvoiceMail.ts @@ -4,7 +4,7 @@ import { SendSaleInvoiceMailCommon } from './SendInvoiceInvoiceMailCommon.servic import { EventEmitter2 } from '@nestjs/event-emitter'; import { events } from '@/common/events/events'; import { mergeAndValidateMailOptions } from '@/modules/MailNotification/utils'; -import { SendInvoiceMailDTO } from '../SaleInvoice.types'; +import { SaleInvoiceMailOptions, SendInvoiceMailDTO } from '../SaleInvoice.types'; import { ISaleInvoiceMailSend } from '../SaleInvoice.types'; import { Mail } from '@/modules/Mail/Mail'; import { MailTransporter } from '@/modules/Mail/MailTransporter.service'; diff --git a/packages/server-nest/src/modules/SaleInvoices/commands/SendSaleInvoiceMailReminder.ts b/packages/server-nest/src/modules/SaleInvoices/commands/SendSaleInvoiceMailReminder.ts deleted file mode 100644 index 11ce2ef97..000000000 --- a/packages/server-nest/src/modules/SaleInvoices/commands/SendSaleInvoiceMailReminder.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { - DEFAULT_INVOICE_REMINDER_MAIL_CONTENT, - DEFAULT_INVOICE_REMINDER_MAIL_SUBJECT, -} from '../constants'; -import { SaleInvoicePdf } from '../queries/SaleInvoicePdf.service'; -import { SendSaleInvoiceMailCommon } from './SendInvoiceInvoiceMailCommon.service'; -import { EventEmitter2 } from '@nestjs/event-emitter'; -import { events } from '@/common/events/events'; -import { ISaleInvoiceMailSend, ISaleInvoiceMailSent, SendInvoiceMailDTO } from '../SaleInvoice.types'; -import { mergeAndValidateMailOptions } from '@/modules/MailNotification/utils'; -import { MailTransporter } from '@/modules/Mail/MailTransporter.service'; -import { Mail } from '@/modules/Mail/Mail'; - -@Injectable() -export class SendInvoiceMailReminder { - constructor( - private readonly invoicePdf: SaleInvoicePdf, - private readonly invoiceCommonMail: SendSaleInvoiceMailCommon, - private readonly eventEmitter: EventEmitter2, - private readonly mailTransporter: MailTransporter, - ) {} - - /** - * Triggers the reminder mail of the given sale invoice. - * @param {number} saleInvoiceId - */ - public async triggerMail( - saleInvoiceId: number, - messageOptions: SendInvoiceMailDTO, - ) { - const payload = { - saleInvoiceId, - messageOptions, - }; - // await this.agenda.now('sale-invoice-reminder-mail-send', payload); - } - - /** - * Retrieves the mail options of the given sale invoice. - * @param {number} saleInvoiceId - The sale invocie id. - * @returns {Promise} - */ - public async getMailOption(saleInvoiceId: number) { - return this.invoiceCommonMail.getMailOption( - saleInvoiceId, - DEFAULT_INVOICE_REMINDER_MAIL_SUBJECT, - DEFAULT_INVOICE_REMINDER_MAIL_CONTENT, - ); - } - - /** - * Triggers the mail invoice. - * @param {number} saleInvoiceId - Sale invoice id. - * @param {SendInvoiceMailDTO} messageOptions - The message options. - * @returns {Promise} - */ - public async sendMail( - saleInvoiceId: number, - messageOptions: SendInvoiceMailDTO, - ) { - const localMessageOpts = await this.getMailOption(saleInvoiceId); - - const messageOpts = mergeAndValidateMailOptions( - localMessageOpts, - messageOptions, - ); - const mail = new Mail() - .setSubject(messageOpts.subject) - .setTo(messageOpts.to) - .setContent(messageOpts.body); - - if (messageOpts.attachInvoice) { - // Retrieves document buffer of the invoice pdf document. - const [invoicePdfBuffer, filename] = await this.invoicePdf.getSaleInvoicePdf( - saleInvoiceId, - ); - mail.setAttachments([ - { filename, content: invoicePdfBuffer }, - ]); - } - // Triggers the event `onSaleInvoiceSend`. - await this.eventEmitter.emitAsync(events.saleInvoice.onMailReminderSend, { - saleInvoiceId, - messageOptions, - } as ISaleInvoiceMailSend); - - await this.mailTransporter.send(mail); - - // Triggers the event `onSaleInvoiceSent`. - await this.eventEmitter.emitAsync(events.saleInvoice.onMailReminderSent, { - saleInvoiceId, - messageOptions, - } as ISaleInvoiceMailSent); - } -} diff --git a/packages/server-nest/src/modules/SaleInvoices/models/SaleInvoice.ts b/packages/server-nest/src/modules/SaleInvoices/models/SaleInvoice.ts index 00731259e..2cc6018a5 100644 --- a/packages/server-nest/src/modules/SaleInvoices/models/SaleInvoice.ts +++ b/packages/server-nest/src/modules/SaleInvoices/models/SaleInvoice.ts @@ -4,20 +4,15 @@ import * as moment from 'moment'; import * as R from 'ramda'; import { MomentInput, unitOfTime } from 'moment'; import { defaultTo } from 'ramda'; -// import TenantModel from 'models/TenantModel'; -// import ModelSetting from './ModelSetting'; -// import SaleInvoiceMeta from './SaleInvoice.Settings'; -// import CustomViewBaseModel from './CustomViewBaseModel'; -// import { DEFAULT_VIEWS } from '@/services/Sales/Invoices/constants'; -// import ModelSearchable from './ModelSearchable'; -import { BaseModel } from '@/models/Model'; import { TaxRateTransaction } from '@/modules/TaxRates/models/TaxRateTransaction.model'; import { ItemEntry } from '@/modules/TransactionItemEntry/models/ItemEntry'; import { Document } from '@/modules/ChromiumlyTenancy/models/Document'; import { DiscountType } from '@/common/types/Discount'; import { Account } from '@/modules/Accounts/models/Account.model'; +import { ISearchRole } from '@/modules/DynamicListing/DynamicFilter/DynamicFilter.types'; +import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel'; -export class SaleInvoice extends BaseModel { +export class SaleInvoice extends TenantBaseModel{ public taxAmountWithheld: number; public balance: number; public paymentAmount: number; @@ -749,11 +744,11 @@ export class SaleInvoice extends BaseModel { /** * Model search attributes. */ - static get searchRoles() { + static get searchRoles(): ISearchRole[] { return [ { fieldKey: 'invoice_no', comparator: 'contains' }, - { condition: 'or', fieldKey: 'reference_no', comparator: 'contains' }, - { condition: 'or', fieldKey: 'amount', comparator: 'equals' }, + // { condition: 'or', fieldKey: 'reference_no', comparator: 'contains' }, + // { condition: 'or', fieldKey: 'amount', comparator: 'equals' }, ]; } diff --git a/packages/server-nest/src/modules/SaleInvoices/queries/GetSaleInvoiceMailState.service.ts b/packages/server-nest/src/modules/SaleInvoices/queries/GetSaleInvoiceMailState.service.ts index 240638f25..4b84d86ea 100644 --- a/packages/server-nest/src/modules/SaleInvoices/queries/GetSaleInvoiceMailState.service.ts +++ b/packages/server-nest/src/modules/SaleInvoices/queries/GetSaleInvoiceMailState.service.ts @@ -1,46 +1,48 @@ -// import { Inject, Injectable } from '@nestjs/common'; -// import { GetSaleInvoiceMailStateTransformer } from './GetSaleInvoiceMailState.transformer'; -// import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectable.service'; -// import { SaleInvoice } from '../models/SaleInvoice'; +import { Inject, Injectable } from '@nestjs/common'; +import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectable.service'; +import { GetSaleInvoiceMailStateTransformer } from './GetSaleInvoiceMailState.transformer'; +import { SendSaleInvoiceMailCommon } from '../commands/SendInvoiceInvoiceMailCommon.service'; +import { SaleInvoice } from '../models/SaleInvoice'; +import { SaleInvoiceMailState } from '../SaleInvoice.types'; -// @Injectable() -// export class GetSaleInvoiceMailState { -// constructor( -// private transformer: TransformerInjectable, -// // private invoiceMail: SendSaleInvoiceMailCommon, +@Injectable() +export class GetSaleInvoiceMailState { + constructor( + private transformer: TransformerInjectable, + private invoiceMail: SendSaleInvoiceMailCommon, -// @Inject(SaleInvoice.name) -// private saleInvoiceModel: typeof SaleInvoice, -// ) {} + @Inject(SaleInvoice.name) + private saleInvoiceModel: typeof SaleInvoice, + ) {} -// /** -// * Retrieves the invoice mail state of the given sale invoice. -// * Invoice mail state includes the mail options, branding attributes and the invoice details. -// * @param {number} saleInvoiceId - Sale invoice id. -// * @returns {Promise} -// */ -// async getInvoiceMailState( -// saleInvoiceId: number, -// ): Promise { -// const saleInvoice = await this.saleInvoiceModel -// .query() -// .findById(saleInvoiceId) -// .withGraphFetched('customer') -// .withGraphFetched('entries.item') -// .withGraphFetched('pdfTemplate') -// .throwIfNotFound(); + /** + * Retrieves the invoice mail state of the given sale invoice. + * Invoice mail state includes the mail options, branding attributes and the invoice details. + * @param {number} saleInvoiceId - Sale invoice id. + * @returns {Promise} + */ + public async getInvoiceMailState( + saleInvoiceId: number, + ): Promise { + const saleInvoice = await this.saleInvoiceModel + .query() + .findById(saleInvoiceId) + .withGraphFetched('customer') + .withGraphFetched('entries.item') + .withGraphFetched('pdfTemplate') + .throwIfNotFound(); -// const mailOptions = -// await this.invoiceMail.getInvoiceMailOptions(saleInvoiceId); + const mailOptions = + await this.invoiceMail.getInvoiceMailOptions(saleInvoiceId); -// // Transforms the sale invoice mail state. -// const transformed = await this.transformer.transform( -// saleInvoice, -// new GetSaleInvoiceMailStateTransformer(), -// { -// mailOptions, -// }, -// ); -// return transformed; -// } -// } + // Transforms the sale invoice mail state. + const transformed = await this.transformer.transform( + saleInvoice, + new GetSaleInvoiceMailStateTransformer(), + { + mailOptions, + }, + ); + return transformed; + } +} diff --git a/packages/server-nest/src/modules/SaleInvoices/queries/GetSaleInvoices.ts b/packages/server-nest/src/modules/SaleInvoices/queries/GetSaleInvoices.ts index b4ab5a188..a7f58344e 100644 --- a/packages/server-nest/src/modules/SaleInvoices/queries/GetSaleInvoices.ts +++ b/packages/server-nest/src/modules/SaleInvoices/queries/GetSaleInvoices.ts @@ -6,6 +6,7 @@ import { DynamicListService } from '@/modules/DynamicListing/DynamicList.service import { IFilterMeta, IPaginationMeta } from '@/interfaces/Model'; import { SaleInvoice } from '../models/SaleInvoice'; import { ISalesInvoicesFilter } from '../SaleInvoice.types'; +import { Knex } from 'knex'; @Injectable() export class GetSaleInvoicesService { @@ -36,8 +37,9 @@ export class GetSaleInvoicesService { .onBuild((builder) => { builder.withGraphFetched('entries.item'); builder.withGraphFetched('customer'); + dynamicFilter.buildQuery()(builder); - filterDTO?.filterQuery && filterDTO?.filterQuery(builder); + filterDTO?.filterQuery?.(builder as any); }) .pagination(filter.page - 1, filter.pageSize); diff --git a/packages/server-nest/src/modules/SaleReceipts/models/SaleReceipt.ts b/packages/server-nest/src/modules/SaleReceipts/models/SaleReceipt.ts index 6cd98ddec..9102075b9 100644 --- a/packages/server-nest/src/modules/SaleReceipts/models/SaleReceipt.ts +++ b/packages/server-nest/src/modules/SaleReceipts/models/SaleReceipt.ts @@ -1,11 +1,6 @@ -import { Model, mixin } from 'objection'; -import { defaultTo } from 'ramda'; -// import TenantModel from 'models/TenantModel'; -// import ModelSetting from './ModelSetting'; -// import SaleReceiptSettings from './SaleReceipt.Settings'; -// import CustomViewBaseModel from './CustomViewBaseModel'; -// import { DEFAULT_VIEWS } from '@/services/Sales/Receipts/constants'; -// import ModelSearchable from './ModelSearchable'; +import { Model } from 'objection'; +import { defaultTo } from 'lodash'; +import * as R from 'ramda'; import { BaseModel } from '@/models/Model'; import { ItemEntry } from '@/modules/TransactionItemEntry/models/ItemEntry'; import { Customer } from '@/modules/Customers/models/Customer'; @@ -13,38 +8,48 @@ import { AccountTransaction } from '@/modules/Accounts/models/AccountTransaction import { Branch } from '@/modules/Branches/models/Branch.model'; import { Warehouse } from '@/modules/Warehouses/models/Warehouse.model'; import { DiscountType } from '@/common/types/Discount'; +import { MetadataModelMixin } from '@/modules/DynamicListing/models/MetadataModel'; +import { ResourceableModelMixin } from '@/modules/Resource/models/ResourcableModel'; +import { CustomViewBaseModelMixin } from '@/modules/CustomViews/CustomViewBaseModel'; +import { SearchableBaseModelMixin } from '@/modules/DynamicListing/models/SearchableBaseModel'; -export class SaleReceipt extends BaseModel { - amount: number; - exchangeRate: number; - currencyCode: string; - depositAccountId: number; - customerId: number; - receiptDate: Date; - receiptNumber: string; - referenceNo: string; - sendToEmail: string; - receiptMessage: string; - statement: string; - closedAt: Date | string; +const ExtendedModel = R.pipe( + CustomViewBaseModelMixin, + SearchableBaseModelMixin, + ResourceableModelMixin, + MetadataModelMixin, +)(BaseModel); - discountType: DiscountType; - discount: number; - adjustment: number; +export class SaleReceipt extends ExtendedModel { + public amount!: number; + public exchangeRate!: number; + public currencyCode!: string; + public depositAccountId!: number; + public customerId!: number; + public receiptDate!: Date; + public receiptNumber!: string; + public referenceNo!: string; + public sendToEmail!: string; + public receiptMessage!: string; + public statement!: string; + public closedAt!: Date | string; + public discountType!: DiscountType; + public discount!: number; + public adjustment!: number; - branchId: number; - warehouseId: number; + public branchId!: number; + public warehouseId!: number; - userId: number; + public userId!: number; - createdAt: Date; - updatedAt: Date | null; + public createdAt!: Date; + public updatedAt!: Date | null; - customer!: Customer; - entries!: ItemEntry[]; - transactions!: AccountTransaction[]; - branch!: Branch; - warehouse!: Warehouse; + public customer!: Customer; + public entries!: ItemEntry[]; + public transactions!: AccountTransaction[]; + public branch!: Branch; + public warehouse!: Warehouse; /** * Table name @@ -142,7 +147,7 @@ export class SaleReceipt extends BaseModel { * Receipt total. * @returns {number} */ - get total() { + get total(): number { const adjustmentAmount = defaultTo(this.adjustment, 0); return this.subtotal - this.discountAmount + adjustmentAmount; @@ -256,6 +261,9 @@ export class SaleReceipt extends BaseModel { const { Warehouse } = require('../../Warehouses/models/Warehouse.model'); return { + /** + * Sale receipt may has a customer. + */ customer: { relation: Model.BelongsToOneRelation, modelClass: Customer, @@ -268,6 +276,9 @@ export class SaleReceipt extends BaseModel { }, }, + /** + * Sale receipt may has a deposit account. + */ depositAccount: { relation: Model.BelongsToOneRelation, modelClass: Account, @@ -277,6 +288,9 @@ export class SaleReceipt extends BaseModel { }, }, + /** + * Sale receipt may has many items entries. + */ entries: { relation: Model.HasManyRelation, modelClass: ItemEntry, @@ -290,6 +304,9 @@ export class SaleReceipt extends BaseModel { }, }, + /** + * Sale receipt may has many transactions. + */ transactions: { relation: Model.HasManyRelation, modelClass: AccountTransaction, diff --git a/packages/server-nest/src/modules/System/models/TenantBaseModel.ts b/packages/server-nest/src/modules/System/models/TenantBaseModel.ts new file mode 100644 index 000000000..905ad8c4a --- /dev/null +++ b/packages/server-nest/src/modules/System/models/TenantBaseModel.ts @@ -0,0 +1,15 @@ +import * as R from 'ramda'; +import { BaseModel } from '@/models/Model'; +import { CustomViewBaseModelMixin } from '@/modules/CustomViews/CustomViewBaseModel'; +import { MetadataModelMixin } from '@/modules/DynamicListing/models/MetadataModel'; +import { SearchableBaseModelMixin } from '@/modules/DynamicListing/models/SearchableBaseModel'; +import { ResourceableModelMixin } from '@/modules/Resource/models/ResourcableModel'; + +const ExtendedItem = R.pipe( + CustomViewBaseModelMixin, + SearchableBaseModelMixin, + ResourceableModelMixin, + MetadataModelMixin, +)(BaseModel); + +export class TenantBaseModel extends ExtendedItem {} diff --git a/packages/server-nest/src/modules/Transformer/Transformer.ts b/packages/server-nest/src/modules/Transformer/Transformer.ts index 79a4fe97b..bde90e0d8 100644 --- a/packages/server-nest/src/modules/Transformer/Transformer.ts +++ b/packages/server-nest/src/modules/Transformer/Transformer.ts @@ -180,7 +180,7 @@ export class Transformer { * @param {string} date * @returns {string} */ - protected formatDateFromNow(date: string) { + protected formatDateFromNow(date: moment.MomentInput) { return date ? moment(date).fromNow(true) : ''; } diff --git a/packages/server-nest/src/modules/VendorCredit/models/VendorCredit.ts b/packages/server-nest/src/modules/VendorCredit/models/VendorCredit.ts index c090a4ce6..bb6f5754d 100644 --- a/packages/server-nest/src/modules/VendorCredit/models/VendorCredit.ts +++ b/packages/server-nest/src/modules/VendorCredit/models/VendorCredit.ts @@ -1,20 +1,12 @@ -import { Model, raw, mixin } from 'objection'; -// import TenantModel from 'models/TenantModel'; -// import BillSettings from './Bill.Settings'; -// import ModelSetting from './ModelSetting'; -// import CustomViewBaseModel from './CustomViewBaseModel'; -// import { DEFAULT_VIEWS } from '@/services/Purchases/VendorCredits/constants'; -// import ModelSearchable from './ModelSearchable'; -// import VendorCreditMeta from './VendorCredit.Meta'; -// import { DiscountType } from '@/interfaces'; +import { Model, raw } from 'objection'; import { Vendor } from '@/modules/Vendors/models/Vendor'; import { Warehouse } from '@/modules/Warehouses/models/Warehouse.model'; import { Branch } from '@/modules/Branches/models/Branch.model'; import { ItemEntry } from '@/modules/TransactionItemEntry/models/ItemEntry'; -import { BaseModel } from '@/models/Model'; import { DiscountType } from '@/common/types/Discount'; +import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel'; -export class VendorCredit extends BaseModel { +export class VendorCredit extends TenantBaseModel { vendorId: number; amount: number; currencyCode: string; diff --git a/packages/server-nest/src/modules/VendorCreditsApplyBills/VendorCreditApplyBills.controller.ts b/packages/server-nest/src/modules/VendorCreditsApplyBills/VendorCreditApplyBills.controller.ts index 56501e13d..b8ef054e5 100644 --- a/packages/server-nest/src/modules/VendorCreditsApplyBills/VendorCreditApplyBills.controller.ts +++ b/packages/server-nest/src/modules/VendorCreditsApplyBills/VendorCreditApplyBills.controller.ts @@ -1,8 +1,10 @@ import { Body, Controller, Delete, Get, Param, Post } from '@nestjs/common'; import { VendorCreditApplyBillsApplicationService } from './VendorCreditApplyBillsApplication.service'; import { IVendorCreditApplyToInvoicesDTO } from './types/VendorCreditApplyBills.types'; +import { ApiTags } from '@nestjs/swagger'; @Controller('vendor-credits') +@ApiTags('vendor-credits-apply-bills') export class VendorCreditApplyBillsController { constructor( private readonly vendorCreditApplyBillsApplication: VendorCreditApplyBillsApplicationService, diff --git a/packages/server-nest/src/modules/Vendors/models/Vendor.ts b/packages/server-nest/src/modules/Vendors/models/Vendor.ts index c8746d191..0005a00db 100644 --- a/packages/server-nest/src/modules/Vendors/models/Vendor.ts +++ b/packages/server-nest/src/modules/Vendors/models/Vendor.ts @@ -7,6 +7,7 @@ import { Model, mixin } from 'objection'; // import { DEFAULT_VIEWS } from '@/services/Contacts/Vendors/constants'; // import ModelSearchable from './ModelSearchable'; import { BaseModel } from '@/models/Model'; +import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel'; // class VendorQueryBuilder extends PaginationQueryBuilder { // constructor(...args) { @@ -20,7 +21,7 @@ import { BaseModel } from '@/models/Model'; // } // } -export class Vendor extends BaseModel { +export class Vendor extends TenantBaseModel { contactService: string; contactType: string; diff --git a/packages/server-nest/src/modules/Warehouses/Warehouses.controller.ts b/packages/server-nest/src/modules/Warehouses/Warehouses.controller.ts index e24ee6b47..29307317b 100644 --- a/packages/server-nest/src/modules/Warehouses/Warehouses.controller.ts +++ b/packages/server-nest/src/modules/Warehouses/Warehouses.controller.ts @@ -10,8 +10,10 @@ import { import { WarehousesApplication } from './WarehousesApplication.service'; import { ICreateWarehouseDTO, IEditWarehouseDTO } from './Warehouse.types'; import { PublicRoute } from '../Auth/Jwt.guard'; +import { ApiTags } from '@nestjs/swagger'; @Controller('warehouses') +@ApiTags('warehouses') @PublicRoute() export class WarehousesController { constructor(private warehousesApplication: WarehousesApplication) {} diff --git a/packages/server-nest/src/utils/format-message.ts b/packages/server-nest/src/utils/format-message.ts new file mode 100644 index 000000000..61e79a8e0 --- /dev/null +++ b/packages/server-nest/src/utils/format-message.ts @@ -0,0 +1,16 @@ +import { defaultTo } from 'lodash'; + +export const formatMessage = (message: string, args: Record) => { + let formattedMessage = message; + + Object.keys(args).forEach((key) => { + const variable = `{${key}}`; + const value = defaultTo(args[key], ''); + + formattedMessage = formattedMessage.replace( + new RegExp(variable, 'g'), + value + ); + }); + return formattedMessage; +}; \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 146271f44..05d8fcd90 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -713,6 +713,9 @@ importers: jest: specifier: ^29.5.0 version: 29.7.0(@types/node@20.5.1)(ts-node@10.9.2) + mustache: + specifier: ^3.0.3 + version: 3.2.1 prettier: specifier: ^3.0.0 version: 3.3.3 @@ -25664,7 +25667,6 @@ packages: resolution: {integrity: sha512-RERvMFdLpaFfSRIEe632yDm5nsd0SDKn8hGmcUwswnyiE5mtdZLDybtHAz6hjJhawokF0hXvGLtx9mrQfm6FkA==} engines: {npm: '>=1.4.0'} hasBin: true - dev: false /mustache@4.2.0: resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==}