From 04c25bd31a97fea07c2fefa899fbdb84087cbea1 Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Tue, 8 Apr 2025 16:19:35 +0200 Subject: [PATCH 1/5] refactor(nestjs): export module --- .../src/common/constants/http.constants.ts | 8 ++ .../src/modules/Accounts/Accounts.module.ts | 2 + .../Accounts/AccountsExportable.service.ts | 8 ++ .../modules/Accounts/models/Account.model.ts | 3 +- packages/server/src/modules/App/App.module.ts | 4 +- .../BillPayments/BillPayments.module.ts | 2 + .../BillPaymentsApplication.service.ts | 15 +- .../commands/BillPaymentExportable.ts | 34 ----- .../queries/BillPaymentsExportable.ts | 42 ++++++ .../server/src/modules/Bills/Bills.module.ts | 2 + .../modules/Bills/commands/BillsExportable.ts | 66 +++++---- .../server/src/modules/Bills/models/Bill.ts | 2 + .../modules/Bills/queries/GetBillPayments.ts | 3 +- .../modules/CreditNotes/CreditNotes.module.ts | 2 + .../commands/CreditNotesExportable.ts | 63 +++++---- .../modules/CreditNotes/models/CreditNote.ts | 2 + .../src/modules/Customers/Customers.module.ts | 4 +- .../Customers/CustomersApplication.service.ts | 26 ++-- .../modules/Customers/CustomersExportable.ts | 58 ++++---- .../src/modules/Expenses/Expenses.module.ts | 2 + .../modules/Expenses/ExpensesExportable.ts | 66 ++++----- .../modules/Expenses/models/Expense.model.ts | 2 + .../src/modules/Export/Export.controller.ts | 12 +- .../server/src/modules/Export/Export.utils.ts | 13 ++ .../src/modules/Export/ExportResources.ts | 21 +-- .../src/modules/Export/ExportService.ts | 9 +- .../server/src/modules/Export/Exportable.ts | 2 +- .../decorators/ExportableModel.decorator.ts | 32 +++++ packages/server/src/modules/Import/_utils.ts | 6 +- .../src/modules/Import/models/Import.ts | 1 + .../ItemCategoriesExportable.ts | 52 +++---- .../ItemCategories/ItemCategory.module.ts | 2 + .../models/ItemCategory.model.ts | 2 + .../server/src/modules/Items/models/Item.ts | 2 + .../ManualJournals/ManualJournals.module.ts | 4 +- .../ManualJournalsApplication.service.ts | 29 ++-- .../commands/ManualJournalExportable.ts | 55 ++++---- .../ManualJournals/models/ManualJournal.ts | 2 + .../PaymentsReceived.module.ts | 2 + .../commands/PaymentsReceivedExportable.ts | 69 +++++---- .../PaymentReceived/models/PaymentReceived.ts | 2 + .../SaleEstimates/SaleEstimates.module.ts | 4 +- .../SaleEstimates/SaleEstimatesExportable.ts | 67 ++++----- .../SaleEstimates/models/SaleEstimate.ts | 3 +- .../SaleInvoices/SaleInvoices.module.ts | 2 + .../commands/SaleInvoicesExportable.ts | 68 ++++----- .../SaleInvoices/models/SaleInvoice.ts | 2 + .../SaleReceipts/SaleReceipts.module.ts | 2 + .../commands/SaleReceiptsExportable.ts | 64 ++++----- .../SaleReceipts/models/SaleReceipt.ts | 2 + .../src/modules/TaxRates/TaxRate.module.ts | 2 + .../modules/TaxRates/TaxRatesExportable.ts | 34 ++--- .../modules/TaxRates/models/TaxRate.model.ts | 2 + .../VendorCredit/VendorCredits.module.ts | 4 +- .../commands/VendorCreditsExportable.ts | 68 ++++----- .../VendorCredit/models/VendorCredit.ts | 2 + .../src/modules/Vendors/Vendors.module.ts | 2 + .../src/modules/Vendors/VendorsExportable.ts | 58 ++++---- .../src/modules/Vendors/models/Vendor.ts | 2 + .../server/src/utils/multi-number-parse.ts | 131 ++++++++++++++++++ 60 files changed, 748 insertions(+), 504 deletions(-) create mode 100644 packages/server/src/common/constants/http.constants.ts delete mode 100644 packages/server/src/modules/BillPayments/commands/BillPaymentExportable.ts create mode 100644 packages/server/src/modules/BillPayments/queries/BillPaymentsExportable.ts create mode 100644 packages/server/src/modules/Export/Export.utils.ts create mode 100644 packages/server/src/modules/Export/decorators/ExportableModel.decorator.ts create mode 100644 packages/server/src/utils/multi-number-parse.ts diff --git a/packages/server/src/common/constants/http.constants.ts b/packages/server/src/common/constants/http.constants.ts new file mode 100644 index 000000000..96022929a --- /dev/null +++ b/packages/server/src/common/constants/http.constants.ts @@ -0,0 +1,8 @@ +export const ACCEPT_TYPE = { + APPLICATION_PDF: 'application/pdf', + APPLICATION_JSON: 'application/json', + APPLICATION_JSON_TABLE: 'application/json+table', + APPLICATION_XLSX: 'application/xlsx', + APPLICATION_CSV: 'application/csv', + APPLICATION_TEXT_HTML: 'application/json+html', +}; \ No newline at end of file diff --git a/packages/server/src/modules/Accounts/Accounts.module.ts b/packages/server/src/modules/Accounts/Accounts.module.ts index 7ed6c4f12..41ae6bc11 100644 --- a/packages/server/src/modules/Accounts/Accounts.module.ts +++ b/packages/server/src/modules/Accounts/Accounts.module.ts @@ -17,6 +17,7 @@ import { RegisterTenancyModel } from '../Tenancy/TenancyModels/Tenancy.module'; import { BankAccount } from '../BankingTransactions/models/BankAccount'; import { GetAccountsService } from './GetAccounts.service'; import { DynamicListModule } from '../DynamicListing/DynamicList.module'; +import { AccountsExportable } from './AccountsExportable.service'; // import { GetAccountsService } from './GetAccounts.service'; const models = [RegisterTenancyModel(BankAccount)]; @@ -38,6 +39,7 @@ const models = [RegisterTenancyModel(BankAccount)]; GetAccountTypesService, GetAccountTransactionsService, GetAccountsService, + AccountsExportable ], exports: [AccountRepository, CreateAccountService, ...models], }) diff --git a/packages/server/src/modules/Accounts/AccountsExportable.service.ts b/packages/server/src/modules/Accounts/AccountsExportable.service.ts index 4c010806e..e05c2db0d 100644 --- a/packages/server/src/modules/Accounts/AccountsExportable.service.ts +++ b/packages/server/src/modules/Accounts/AccountsExportable.service.ts @@ -2,8 +2,16 @@ import { AccountsApplication } from './AccountsApplication.service'; import { Exportable } from '../Export/Exportable'; import { EXPORT_SIZE_LIMIT } from '../Export/constants'; import { IAccountsFilter, IAccountsStructureType } from './Accounts.types'; +import { Injectable } from '@nestjs/common'; +import { ExportableService } from '../Export/decorators/ExportableModel.decorator'; +import { Account } from './models/Account.model'; +@Injectable() +@ExportableService({ name: Account.name }) export class AccountsExportable extends Exportable { + /** + * @param {AccountsApplication} accountsApplication + */ constructor(private readonly accountsApplication: AccountsApplication) { super(); } diff --git a/packages/server/src/modules/Accounts/models/Account.model.ts b/packages/server/src/modules/Accounts/models/Account.model.ts index 92cef8f59..40f127ec5 100644 --- a/packages/server/src/modules/Accounts/models/Account.model.ts +++ b/packages/server/src/modules/Accounts/models/Account.model.ts @@ -15,12 +15,13 @@ import { Model } from 'objection'; import { PlaidItem } from '@/modules/BankingPlaid/models/PlaidItem'; import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel'; import { flatToNestedArray } from '@/utils/flat-to-nested-array'; +import { ExportableModel } from '../../Export/decorators/ExportableModel.decorator'; // import AccountSettings from './Account.Settings'; // import { DEFAULT_VIEWS } from '@/modules/Accounts/constants'; // import { buildFilterQuery, buildSortColumnQuery } from '@/lib/ViewRolesBuilder'; // import { flatToNestedArray } from 'utils'; - +@ExportableModel() export class Account extends TenantBaseModel { public name!: string; public slug!: string; diff --git a/packages/server/src/modules/App/App.module.ts b/packages/server/src/modules/App/App.module.ts index 2f31cb1fc..0e0d0dc1c 100644 --- a/packages/server/src/modules/App/App.module.ts +++ b/packages/server/src/modules/App/App.module.ts @@ -79,6 +79,7 @@ import { TenancyModule } from '../Tenancy/Tenancy.module'; import { LoopsModule } from '../Loops/Loops.module'; import { AttachmentsModule } from '../Attachments/Attachment.module'; import { S3Module } from '../S3/S3.module'; +import { ExportModule } from '../Export/Export.module'; @Module({ imports: [ @@ -192,7 +193,8 @@ import { S3Module } from '../S3/S3.module'; PaymentServicesModule, LoopsModule, AttachmentsModule, - S3Module + S3Module, + ExportModule ], controllers: [AppController], providers: [ diff --git a/packages/server/src/modules/BillPayments/BillPayments.module.ts b/packages/server/src/modules/BillPayments/BillPayments.module.ts index 2feb3c04a..e9f01f6e7 100644 --- a/packages/server/src/modules/BillPayments/BillPayments.module.ts +++ b/packages/server/src/modules/BillPayments/BillPayments.module.ts @@ -16,6 +16,7 @@ import { BillPaymentGLEntries } from './commands/BillPaymentGLEntries'; import { BillPaymentGLEntriesSubscriber } from './subscribers/BillPaymentGLEntriesSubscriber'; import { LedgerModule } from '../Ledger/Ledger.module'; import { AccountsModule } from '../Accounts/Accounts.module'; +import { BillPaymentsExportable } from './queries/BillPaymentsExportable'; @Module({ imports: [LedgerModule, AccountsModule], @@ -34,6 +35,7 @@ import { AccountsModule } from '../Accounts/Accounts.module'; TenancyContext, BillPaymentGLEntries, BillPaymentGLEntriesSubscriber, + BillPaymentsExportable ], exports: [BillPaymentValidators, CreateBillPaymentService], controllers: [BillPaymentsController], diff --git a/packages/server/src/modules/BillPayments/BillPaymentsApplication.service.ts b/packages/server/src/modules/BillPayments/BillPaymentsApplication.service.ts index 59959244d..29a551ad2 100644 --- a/packages/server/src/modules/BillPayments/BillPaymentsApplication.service.ts +++ b/packages/server/src/modules/BillPayments/BillPaymentsApplication.service.ts @@ -20,12 +20,12 @@ export class BillPaymentsApplication { private deleteBillPaymentService: DeleteBillPayment, private getBillPaymentService: GetBillPayment, private getPaymentBillsService: GetPaymentBills, - // private getBillPaymentsService: GetBillPayments, + private getBillPaymentsService: GetBillPayments, ) {} /** * Creates a bill payment with associated GL entries. - * @param {IBillPaymentDTO} billPaymentDTO + * @param {IBillPaymentDTO} billPaymentDTO - Create bill payment dto. * @returns {Promise} */ public createBillPayment(billPaymentDTO: CreateBillPaymentDto) { @@ -34,7 +34,7 @@ export class BillPaymentsApplication { /** * Delets the given bill payment with associated GL entries. - * @param {number} billPaymentId + * @param {number} billPaymentId - Bill payment id. */ public deleteBillPayment(billPaymentId: number) { return this.deleteBillPaymentService.deleteBillPayment(billPaymentId); @@ -58,13 +58,10 @@ export class BillPaymentsApplication { /** * Retrieves bill payments list. - * @param {number} tenantId - * @param filterDTO - * @returns */ - // public getBillPayments(filterDTO: IBillPaymentsFilter) { - // return this.getBillPaymentsService.getBillPayments(filterDTO); - // } + public getBillPayments(filterDTO: IBillPaymentsFilter) { + return this.getBillPaymentsService.getBillPayments(filterDTO); + } /** * Retrieve specific bill payment. diff --git a/packages/server/src/modules/BillPayments/commands/BillPaymentExportable.ts b/packages/server/src/modules/BillPayments/commands/BillPaymentExportable.ts deleted file mode 100644 index 44bf4b6cf..000000000 --- a/packages/server/src/modules/BillPayments/commands/BillPaymentExportable.ts +++ /dev/null @@ -1,34 +0,0 @@ -// import { Inject, Service } from 'typedi'; -// import { Exportable } from '@/services/Export/Exportable'; -// import { BillPaymentsApplication } from './BillPaymentsApplication'; -// import { EXPORT_SIZE_LIMIT } from '@/services/Export/constants'; - -// @Service() -// export class BillPaymentExportable extends Exportable { -// @Inject() -// private billPaymentsApplication: BillPaymentsApplication; - -// /** -// * Retrieves the accounts data to exportable sheet. -// * @param {number} tenantId -// * @returns -// */ -// public exportable(tenantId: number, query: any) { -// const filterQuery = (builder) => { -// builder.withGraphFetched('entries.bill'); -// builder.withGraphFetched('branch'); -// }; -// const parsedQuery = { -// sortOrder: 'desc', -// columnSortBy: 'created_at', -// ...query, -// page: 1, -// pageSize: EXPORT_SIZE_LIMIT, -// filterQuery -// } as any; - -// return this.billPaymentsApplication -// .getBillPayments(tenantId, parsedQuery) -// .then((output) => output.billPayments); -// } -// } diff --git a/packages/server/src/modules/BillPayments/queries/BillPaymentsExportable.ts b/packages/server/src/modules/BillPayments/queries/BillPaymentsExportable.ts new file mode 100644 index 000000000..970730b75 --- /dev/null +++ b/packages/server/src/modules/BillPayments/queries/BillPaymentsExportable.ts @@ -0,0 +1,42 @@ +import { Injectable } from "@nestjs/common"; +import { BillPaymentsApplication } from "../BillPaymentsApplication.service"; +import { Exportable } from "@/modules/Export/Exportable"; +import { EXPORT_SIZE_LIMIT } from "@/modules/Export/constants"; +import { ExportableService } from "@/modules/Export/decorators/ExportableModel.decorator"; +import { BillPayment } from "../models/BillPayment"; + +@Injectable() +@ExportableService({ name: BillPayment.name }) +export class BillPaymentsExportable extends Exportable { + constructor( + private readonly billPaymentsApplication: BillPaymentsApplication + ) { + super(); + } + + /** + * Retrieves the accounts data to exportable sheet. + * @param {number} tenantId + * @returns + */ + public exportable(query: any) { + const filterQuery = (builder) => { + builder.withGraphFetched('entries.bill'); + builder.withGraphFetched('branch'); + }; + const parsedQuery = { + sortOrder: 'desc', + columnSortBy: 'created_at', + ...query, + page: 1, + pageSize: EXPORT_SIZE_LIMIT, + filterQuery + } as any; + + return []; + + // return this.billPaymentsApplication + // .billPayments(tenantId, parsedQuery) + // .then((output) => output.billPayments); + } +} diff --git a/packages/server/src/modules/Bills/Bills.module.ts b/packages/server/src/modules/Bills/Bills.module.ts index 87280de4c..a9f5549e1 100644 --- a/packages/server/src/modules/Bills/Bills.module.ts +++ b/packages/server/src/modules/Bills/Bills.module.ts @@ -26,6 +26,7 @@ import { BillInventoryTransactions } from './commands/BillInventoryTransactions' import { GetBillsService } from './queries/GetBills.service'; import { DynamicListModule } from '../DynamicListing/DynamicList.module'; import { InventoryCostModule } from '../InventoryCost/InventoryCost.module'; +import { BillsExportable } from './commands/BillsExportable'; @Module({ imports: [ @@ -57,6 +58,7 @@ import { InventoryCostModule } from '../InventoryCost/InventoryCost.module'; BillGLEntriesSubscriber, BillInventoryTransactions, BillWriteInventoryTransactionsSubscriber, + BillsExportable ], controllers: [BillsController], }) diff --git a/packages/server/src/modules/Bills/commands/BillsExportable.ts b/packages/server/src/modules/Bills/commands/BillsExportable.ts index e3dcf983f..df9d09b66 100644 --- a/packages/server/src/modules/Bills/commands/BillsExportable.ts +++ b/packages/server/src/modules/Bills/commands/BillsExportable.ts @@ -1,37 +1,35 @@ -// import { Inject, Service } from 'typedi'; -// import { Knex } from 'knex'; -// import { IBillsFilter } from '@/interfaces'; -// import { Exportable } from '@/services/Export/Exportable'; -// import { BillsApplication } from '../Bills.application'; -// import { EXPORT_SIZE_LIMIT } from '@/services/Export/constants'; -// import Objection from 'objection'; +import { Knex } from 'knex'; +import { BillsApplication } from '../Bills.application'; +import { Injectable } from '@nestjs/common'; +import { Exportable } from '@/modules/Export/Exportable'; +import { IBillsFilter } from '../Bills.types'; +import { EXPORT_SIZE_LIMIT } from '@/modules/Export/constants'; -// @Service() -// export class BillsExportable extends Exportable { -// @Inject() -// private billsApplication: BillsApplication; +@Injectable() +export class BillsExportable extends Exportable { + constructor(private readonly billsApplication: BillsApplication) { + super(); + } -// /** -// * Retrieves the accounts data to exportable sheet. -// * @param {number} tenantId -// * @returns -// */ -// public exportable(tenantId: number, query: IBillsFilter) { -// const filterQuery = (query) => { -// query.withGraphFetched('branch'); -// query.withGraphFetched('warehouse'); -// }; -// const parsedQuery = { -// sortOrder: 'desc', -// columnSortBy: 'created_at', -// ...query, -// page: 1, -// pageSize: EXPORT_SIZE_LIMIT, -// filterQuery, -// } as IBillsFilter; + /** + * Retrieves the accounts data to exportable sheet. + */ + public exportable(query: IBillsFilter) { + const filterQuery = (query) => { + query.withGraphFetched('branch'); + query.withGraphFetched('warehouse'); + }; + const parsedQuery = { + sortOrder: 'desc', + columnSortBy: 'created_at', + ...query, + page: 1, + pageSize: EXPORT_SIZE_LIMIT, + filterQuery, + } as IBillsFilter; -// return this.billsApplication -// .getBills(tenantId, parsedQuery) -// .then((output) => output.bills); -// } -// } + return this.billsApplication + .getBills(parsedQuery) + .then((output) => output.bills); + } +} diff --git a/packages/server/src/modules/Bills/models/Bill.ts b/packages/server/src/modules/Bills/models/Bill.ts index 2b55f32ea..41da17fc3 100644 --- a/packages/server/src/modules/Bills/models/Bill.ts +++ b/packages/server/src/modules/Bills/models/Bill.ts @@ -14,7 +14,9 @@ import { BillLandedCost } from '@/modules/BillLandedCosts/models/BillLandedCost' import { DiscountType } from '@/common/types/Discount'; import type { Knex, QueryBuilder } from 'knex'; import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel'; +import { ExportableModel } from '@/modules/Export/decorators/ExportableModel.decorator'; +@ExportableModel() export class Bill extends TenantBaseModel { public amount: number; public paymentAmount: number; diff --git a/packages/server/src/modules/Bills/queries/GetBillPayments.ts b/packages/server/src/modules/Bills/queries/GetBillPayments.ts index ef13ec272..6a1814bba 100644 --- a/packages/server/src/modules/Bills/queries/GetBillPayments.ts +++ b/packages/server/src/modules/Bills/queries/GetBillPayments.ts @@ -13,8 +13,7 @@ export class GetBillPayments { /** * Retrieve the specific bill associated payment transactions. - * @param {number} billId - * @returns {} + * @param {number} billId - Bill id. */ public getBillPayments = async (billId: number) => { const billsEntries = await this.billPaymentEntryModel diff --git a/packages/server/src/modules/CreditNotes/CreditNotes.module.ts b/packages/server/src/modules/CreditNotes/CreditNotes.module.ts index 0a1e5bafb..b7785488c 100644 --- a/packages/server/src/modules/CreditNotes/CreditNotes.module.ts +++ b/packages/server/src/modules/CreditNotes/CreditNotes.module.ts @@ -24,6 +24,7 @@ import { LedgerModule } from '../Ledger/Ledger.module'; import { AccountsModule } from '../Accounts/Accounts.module'; import { GetCreditNotesService } from './queries/GetCreditNotes.service'; import { DynamicListModule } from '../DynamicListing/DynamicList.module'; +import { CreditNotesExportable } from './commands/CreditNotesExportable'; @Module({ imports: [ @@ -53,6 +54,7 @@ import { DynamicListModule } from '../DynamicListing/DynamicList.module'; CreditNoteBrandingTemplate, CreditNoteGLEntries, CreditNoteGLEntriesSubscriber, + CreditNotesExportable ], exports: [ CreateCreditNoteService, diff --git a/packages/server/src/modules/CreditNotes/commands/CreditNotesExportable.ts b/packages/server/src/modules/CreditNotes/commands/CreditNotesExportable.ts index 8fd00ff7e..ac5c8b55a 100644 --- a/packages/server/src/modules/CreditNotes/commands/CreditNotesExportable.ts +++ b/packages/server/src/modules/CreditNotes/commands/CreditNotesExportable.ts @@ -1,35 +1,34 @@ -// import { Inject, Service } from 'typedi'; -// import { ICreditNotesQueryDTO } from '@/interfaces'; -// import { Exportable } from '@/services/Export/Exportable'; -// import ListCreditNotes from '../ListCreditNotes'; +import { Exportable } from '@/modules/Export/Exportable'; +import { CreditNoteApplication } from '../CreditNoteApplication.service'; +import { Injectable } from '@nestjs/common'; +import { ICreditNotesQueryDTO } from '../types/CreditNotes.types'; -// @Service() -// export class CreditNotesExportable extends Exportable { -// @Inject() -// private getCreditNotes: ListCreditNotes; +@Injectable() +export class CreditNotesExportable extends Exportable { + constructor(private readonly creditNotesApp: CreditNoteApplication) { + super(); + } -// /** -// * Retrieves the accounts data to exportable sheet. -// * @param {number} tenantId - -// * @param {IVendorCreditsQueryDTO} query - -// * @returns {} -// */ -// public exportable(tenantId: number, query: ICreditNotesQueryDTO) { -// const filterQuery = (query) => { -// query.withGraphFetched('branch'); -// query.withGraphFetched('warehouse'); -// }; -// const parsedQuery = { -// sortOrder: 'desc', -// columnSortBy: 'created_at', -// ...query, -// page: 1, -// pageSize: 12000, -// filterQuery, -// } as ICreditNotesQueryDTO; + /** + * Retrieves the accounts data to exportable sheet. + * @param {IVendorCreditsQueryDTO} query - + */ + public exportable(query: ICreditNotesQueryDTO) { + const filterQuery = (query) => { + query.withGraphFetched('branch'); + query.withGraphFetched('warehouse'); + }; + const parsedQuery = { + sortOrder: 'desc', + columnSortBy: 'created_at', + ...query, + page: 1, + pageSize: 12000, + filterQuery, + } as ICreditNotesQueryDTO; -// return this.getCreditNotes -// .getCreditNotesList(tenantId, parsedQuery) -// .then((output) => output.creditNotes); -// } -// } + return this.creditNotesApp + .getCreditNotes(parsedQuery) + .then((output) => output.creditNotes); + } +} diff --git a/packages/server/src/modules/CreditNotes/models/CreditNote.ts b/packages/server/src/modules/CreditNotes/models/CreditNote.ts index 482fef214..603338142 100644 --- a/packages/server/src/modules/CreditNotes/models/CreditNote.ts +++ b/packages/server/src/modules/CreditNotes/models/CreditNote.ts @@ -2,11 +2,13 @@ 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 { ExportableModel } from '@/modules/Export/decorators/ExportableModel.decorator'; 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'; +@ExportableModel() export class CreditNote extends TenantBaseModel { public amount: number; public exchangeRate: number; diff --git a/packages/server/src/modules/Customers/Customers.module.ts b/packages/server/src/modules/Customers/Customers.module.ts index ab576eb0e..192e68d69 100644 --- a/packages/server/src/modules/Customers/Customers.module.ts +++ b/packages/server/src/modules/Customers/Customers.module.ts @@ -12,6 +12,7 @@ import { CreateEditCustomerDTO } from './commands/CreateEditCustomerDTO.service' import { CustomersController } from './Customers.controller'; import { CustomersApplication } from './CustomersApplication.service'; import { DeleteCustomer } from './commands/DeleteCustomer.service'; +import { CustomersExportable } from './CustomersExportable'; @Module({ imports: [TenancyDatabaseModule], @@ -29,7 +30,8 @@ import { DeleteCustomer } from './commands/DeleteCustomer.service'; DeleteCustomer, TenancyContext, TransformerInjectable, - GetCustomerService + GetCustomerService, + CustomersExportable ], }) export class CustomersModule {} diff --git a/packages/server/src/modules/Customers/CustomersApplication.service.ts b/packages/server/src/modules/Customers/CustomersApplication.service.ts index 4d1da82c7..161d0532c 100644 --- a/packages/server/src/modules/Customers/CustomersApplication.service.ts +++ b/packages/server/src/modules/Customers/CustomersApplication.service.ts @@ -4,9 +4,10 @@ import { CreateCustomer } from './commands/CreateCustomer.service'; import { EditCustomer } from './commands/EditCustomer.service'; import { DeleteCustomer } from './commands/DeleteCustomer.service'; import { EditOpeningBalanceCustomer } from './commands/EditOpeningBalanceCustomer.service'; -import { ICustomerOpeningBalanceEditDTO } from './types/Customers.types'; +import { ICustomerOpeningBalanceEditDTO, ICustomersFilter } from './types/Customers.types'; import { CreateCustomerDto } from './dtos/CreateCustomer.dto'; import { EditCustomerDto } from './dtos/EditCustomer.dto'; +import { GetCustomers } from './queries/GetCustomers.service'; @Injectable() export class CustomersApplication { @@ -16,13 +17,12 @@ export class CustomersApplication { private editCustomerService: EditCustomer, private deleteCustomerService: DeleteCustomer, private editOpeningBalanceService: EditOpeningBalanceCustomer, - // private getCustomersService: GetCustomers, + private getCustomersService: GetCustomers, ) {} /** * Retrieves the given customer details. - * @param {number} tenantId - * @param {number} customerId + * @param {number} customerId - Customer id. */ public getCustomer = (customerId: number) => { return this.getCustomerService.getCustomer(customerId); @@ -30,7 +30,7 @@ export class CustomersApplication { /** * Creates a new customer. - * @param {ICustomerNewDTO} customerDTO + * @param {ICustomerNewDTO} customerDTO - Create customer dto. * @returns {Promise} */ public createCustomer = (customerDTO: CreateCustomerDto) => { @@ -49,9 +49,7 @@ export class CustomersApplication { /** * Deletes the given customer and associated transactions. - * @param {number} tenantId - * @param {number} customerId - * @param {ISystemUser} authorizedUser + * @param {number} customerId - Customer id. * @returns {Promise} */ public deleteCustomer = (customerId: number) => { @@ -60,9 +58,8 @@ export class CustomersApplication { /** * Changes the opening balance of the given customer. - * @param {number} tenantId - * @param {number} customerId - * @param {Date|string} openingBalanceEditDTO + * @param {number} customerId - Customer id. + * @param {Date|string} openingBalanceEditDTO - Opening balance edit dto. * @returns {Promise} */ public editOpeningBalance = ( @@ -77,10 +74,9 @@ export class CustomersApplication { /** * Retrieve customers paginated list. - * @param {number} tenantId - Tenant id. * @param {ICustomersFilter} filter - Cusotmers filter. */ - // public getCustomers = (filterDTO: ICustomersFilter) => { - // return this.getCustomersService.getCustomersList(filterDTO); - // }; + public getCustomers = (filterDTO: ICustomersFilter) => { + return this.getCustomersService.getCustomersList(filterDTO); + }; } diff --git a/packages/server/src/modules/Customers/CustomersExportable.ts b/packages/server/src/modules/Customers/CustomersExportable.ts index 0384df0d1..849f2f767 100644 --- a/packages/server/src/modules/Customers/CustomersExportable.ts +++ b/packages/server/src/modules/Customers/CustomersExportable.ts @@ -1,30 +1,34 @@ -// import { Inject, Service } from 'typedi'; -// import { IItemsFilter } from '@/interfaces'; -// import { CustomersApplication } from './CustomersApplication'; -// import { Exportable } from '@/services/Export/Exportable'; -// import { EXPORT_SIZE_LIMIT } from '@/services/Export/constants'; +import { Injectable } from '@nestjs/common'; +import { CustomersApplication } from './CustomersApplication.service'; +import { IItemsFilter } from '../Items/types/Items.types'; +import { EXPORT_SIZE_LIMIT } from '../Export/constants'; +import { Exportable } from '../Export/Exportable'; +import { ICustomersFilter } from './types/Customers.types'; +import { ExportableService } from '../Export/decorators/ExportableModel.decorator'; +import { Customer } from './models/Customer'; -// @Service() -// export class CustomersExportable extends Exportable { -// @Inject() -// private customersApplication: CustomersApplication; +@Injectable() +@ExportableService({ name: Customer.name }) +export class CustomersExportable extends Exportable { + constructor(private readonly customersApplication: CustomersApplication) { + super(); + } -// /** -// * Retrieves the accounts data to exportable sheet. -// * @param {number} tenantId -// * @returns -// */ -// public exportable(tenantId: number, query: IItemsFilter) { -// const parsedQuery = { -// sortOrder: 'DESC', -// columnSortBy: 'created_at', -// ...query, -// page: 1, -// pageSize: EXPORT_SIZE_LIMIT, -// } as IItemsFilter; + /** + * Retrieves the accounts data to exportable sheet. + * @param {ICustomersFilter} query - Customers query. + */ + public exportable(query: ICustomersFilter) { + const parsedQuery = { + sortOrder: 'DESC', + columnSortBy: 'created_at', + ...query, + page: 1, + pageSize: EXPORT_SIZE_LIMIT, + } as IItemsFilter; -// return this.customersApplication -// .getCustomers(tenantId, parsedQuery) -// .then((output) => output.customers); -// } -// } + return this.customersApplication + .getCustomers(parsedQuery) + .then((output) => output.customers); + } +} diff --git a/packages/server/src/modules/Expenses/Expenses.module.ts b/packages/server/src/modules/Expenses/Expenses.module.ts index f00b75f14..3c6cb10cd 100644 --- a/packages/server/src/modules/Expenses/Expenses.module.ts +++ b/packages/server/src/modules/Expenses/Expenses.module.ts @@ -17,6 +17,7 @@ import { LedgerModule } from '../Ledger/Ledger.module'; import { BranchesModule } from '../Branches/Branches.module'; import { GetExpensesService } from './queries/GetExpenses.service'; import { DynamicListModule } from '../DynamicListing/DynamicList.module'; +import { ExpensesExportable } from './ExpensesExportable'; @Module({ imports: [LedgerModule, BranchesModule, DynamicListModule], @@ -37,6 +38,7 @@ import { DynamicListModule } from '../DynamicListing/DynamicList.module'; ExpenseGLEntriesStorageService, ExpenseGLEntriesService, GetExpensesService, + ExpensesExportable ], }) export class ExpensesModule {} diff --git a/packages/server/src/modules/Expenses/ExpensesExportable.ts b/packages/server/src/modules/Expenses/ExpensesExportable.ts index 7a1681506..902a2c91a 100644 --- a/packages/server/src/modules/Expenses/ExpensesExportable.ts +++ b/packages/server/src/modules/Expenses/ExpensesExportable.ts @@ -1,34 +1,38 @@ -// import { Inject, Service } from 'typedi'; -// import { Exportable } from '../Export/Exportable'; -// import { IExpensesFilter } from '@/interfaces'; -// import { ExpensesApplication } from './ExpensesApplication.service'; -// import { EXPORT_SIZE_LIMIT } from '../Export/constants'; +import { Exportable } from '../Export/Exportable'; +import { ExpensesApplication } from './ExpensesApplication.service'; +import { EXPORT_SIZE_LIMIT } from '../Export/constants'; +import { Injectable } from '@nestjs/common'; +import { IExpensesFilter } from './Expenses.types'; +import { ExportableService } from '../Export/decorators/ExportableModel.decorator'; +import { Expense } from './models/Expense.model'; -// @Service() -// export class ExpensesExportable extends Exportable { -// @Inject() -// private expensesApplication: ExpensesApplication; +@Injectable() +@ExportableService({ name: Expense.name }) +export class ExpensesExportable extends Exportable { + constructor( + private readonly expensesApplication: ExpensesApplication, + ) { + super(); + } -// /** -// * Retrieves the accounts data to exportable sheet. -// * @param {number} tenantId -// * @returns -// */ -// public exportable(tenantId: number, query: IExpensesFilter) { -// const filterQuery = (query) => { -// query.withGraphFetched('branch'); -// }; -// const parsedQuery = { -// sortOrder: 'desc', -// columnSortBy: 'created_at', -// ...query, -// page: 1, -// pageSize: EXPORT_SIZE_LIMIT, -// filterQuery, -// } as IExpensesFilter; + /** + * Retrieves the accounts data to exportable sheet. + */ + public exportable(query: IExpensesFilter) { + const filterQuery = (query) => { + query.withGraphFetched('branch'); + }; + const parsedQuery = { + sortOrder: 'desc', + columnSortBy: 'created_at', + ...query, + page: 1, + pageSize: EXPORT_SIZE_LIMIT, + filterQuery, + } as IExpensesFilter; -// return this.expensesApplication -// .getExpenses(tenantId, parsedQuery) -// .then((output) => output.expenses); -// } -// } + return this.expensesApplication + .getExpenses(parsedQuery) + .then((output) => output.expenses); + } +} diff --git a/packages/server/src/modules/Expenses/models/Expense.model.ts b/packages/server/src/modules/Expenses/models/Expense.model.ts index 34630d9df..6dcc408d3 100644 --- a/packages/server/src/modules/Expenses/models/Expense.model.ts +++ b/packages/server/src/modules/Expenses/models/Expense.model.ts @@ -3,7 +3,9 @@ import * as moment from 'moment'; import { ExpenseCategory } from './ExpenseCategory.model'; import { Account } from '@/modules/Accounts/models/Account.model'; import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel'; +import { ExportableModel } from '@/modules/Export/decorators/ExportableModel.decorator'; +@ExportableModel() export class Expense extends TenantBaseModel { totalAmount!: number; currencyCode!: string; diff --git a/packages/server/src/modules/Export/Export.controller.ts b/packages/server/src/modules/Export/Export.controller.ts index e13559948..4eff9b663 100644 --- a/packages/server/src/modules/Export/Export.controller.ts +++ b/packages/server/src/modules/Export/Export.controller.ts @@ -1,20 +1,24 @@ import { Response } from 'express'; -import { convertAcceptFormatToFormat } from './_utils'; -import { Controller, Headers, Query, Res } from '@nestjs/common'; +import { ApiOperation, ApiTags } from '@nestjs/swagger'; +import { Controller, Get, Headers, Query, Res } from '@nestjs/common'; +import { AcceptType } from '@/constants/accept-type'; import { ExportQuery } from './dtos/ExportQuery.dto'; import { ExportResourceService } from './ExportService'; -import { AcceptType } from '@/constants/accept-type'; +import { convertAcceptFormatToFormat } from './Export.utils'; @Controller('/export') +@ApiTags('export') export class ExportController { constructor(private readonly exportResourceApp: ExportResourceService) {} + @Get() + @ApiOperation({ summary: 'Retrieves exported the given resource.' }) async export( @Query() query: ExportQuery, @Res() res: Response, @Headers('accept') acceptHeader: string, ) { - const applicationFormat = convertAcceptFormatToFormat(acceptType); + const applicationFormat = convertAcceptFormatToFormat(acceptHeader); const data = await this.exportResourceApp.export( query.resource, diff --git a/packages/server/src/modules/Export/Export.utils.ts b/packages/server/src/modules/Export/Export.utils.ts new file mode 100644 index 000000000..97b31125e --- /dev/null +++ b/packages/server/src/modules/Export/Export.utils.ts @@ -0,0 +1,13 @@ +import { ACCEPT_TYPE } from '@/common/constants/http.constants'; +import { ExportFormat } from './common'; + +export const convertAcceptFormatToFormat = (accept: string): ExportFormat => { + switch (accept) { + case ACCEPT_TYPE.APPLICATION_CSV: + return ExportFormat.Csv; + case ACCEPT_TYPE.APPLICATION_PDF: + return ExportFormat.Pdf; + case ACCEPT_TYPE.APPLICATION_XLSX: + return ExportFormat.Xlsx; + } +}; \ No newline at end of file diff --git a/packages/server/src/modules/Export/ExportResources.ts b/packages/server/src/modules/Export/ExportResources.ts index 7033e34e6..660b02829 100644 --- a/packages/server/src/modules/Export/ExportResources.ts +++ b/packages/server/src/modules/Export/ExportResources.ts @@ -1,22 +1,3 @@ -// import Container, { Service } from 'typedi'; -// import { AccountsExportable } from '../Accounts/AccountsExportable'; -// import { ExportableRegistry } from './ExportRegistery'; -// import { ItemsExportable } from '../Items/ItemsExportable'; -// import { CustomersExportable } from '../Contacts/Customers/CustomersExportable'; -// import { VendorsExportable } from '../Contacts/Vendors/VendorsExportable'; -// import { ExpensesExportable } from '../Expenses/ExpensesExportable'; -// import { SaleInvoicesExportable } from '../Sales/Invoices/SaleInvoicesExportable'; -// import { SaleEstimatesExportable } from '../Sales/Estimates/SaleEstimatesExportable'; -// import { SaleReceiptsExportable } from '../Sales/Receipts/SaleReceiptsExportable'; -// import { BillsExportable } from '../Purchases/Bills/BillsExportable'; -// import { PaymentsReceivedExportable } from '../Sales/PaymentReceived/PaymentsReceivedExportable'; -// import { BillPaymentExportable } from '../Purchases/BillPayments/BillPaymentExportable'; -// import { ManualJournalsExportable } from '../ManualJournals/ManualJournalExportable'; -// import { CreditNotesExportable } from '../CreditNotes/CreditNotesExportable'; -// import { VendorCreditsExportable } from '../Purchases/VendorCredits/VendorCreditsExportable'; -// import { ItemCategoriesExportable } from '../ItemCategories/ItemCategoriesExportable'; -// import { TaxRatesExportable } from '../TaxRates/TaxRatesExportable'; - import { Injectable } from "@nestjs/common"; import { ExportableRegistry } from "./ExportRegistery"; import { AccountsExportable } from "../Accounts/AccountsExportable.service"; @@ -33,7 +14,7 @@ export class ExportableResources { * Importable instances. */ private importables = [ - { resource: 'Account', exportable: AccountsExportable }, + // { resource: 'Account', exportable: AccountsExportable }, // { resource: 'Item', exportable: ItemsExportable }, // { resource: 'ItemCategory', exportable: ItemCategoriesExportable }, // { resource: 'Customer', exportable: CustomersExportable }, diff --git a/packages/server/src/modules/Export/ExportService.ts b/packages/server/src/modules/Export/ExportService.ts index 3a7a5b461..a7b659172 100644 --- a/packages/server/src/modules/Export/ExportService.ts +++ b/packages/server/src/modules/Export/ExportService.ts @@ -22,7 +22,6 @@ export class ExportResourceService { ) {} /** - * * @param {string} resourceName * @param {ExportFormat} format * @returns @@ -46,15 +45,14 @@ export class ExportResourceService { format: ExportFormat = ExportFormat.Csv ) { const resource = sanitizeResourceName(resourceName); - const resourceMeta = this.getResourceMeta(tenantId, resource); + const resourceMeta = this.getResourceMeta(resource); const resourceColumns = this.resourceService.getResourceColumns( - tenantId, resource ); this.validateResourceMeta(resourceMeta); - const data = await this.getExportableData(tenantId, resource); - const transformed = this.transformExportedData(tenantId, resource, data); + const data = await this.getExportableData(resource); + const transformed = this.transformExportedData(resource, data); // Returns the csv, xlsx format. if (format === ExportFormat.Csv || format === ExportFormat.Xlsx) { @@ -67,7 +65,6 @@ export class ExportResourceService { const printableColumns = this.getPrintableColumns(resourceMeta); return this.exportPdf.pdf( - tenantId, printableColumns, transformed, resourceMeta?.print?.pageTitle diff --git a/packages/server/src/modules/Export/Exportable.ts b/packages/server/src/modules/Export/Exportable.ts index 0859ebd64..c83f94549 100644 --- a/packages/server/src/modules/Export/Exportable.ts +++ b/packages/server/src/modules/Export/Exportable.ts @@ -6,7 +6,7 @@ export class Exportable { */ public async exportable( query: Record, - ): Promise>> { + ): Promise { return []; } diff --git a/packages/server/src/modules/Export/decorators/ExportableModel.decorator.ts b/packages/server/src/modules/Export/decorators/ExportableModel.decorator.ts new file mode 100644 index 000000000..28a64e8ff --- /dev/null +++ b/packages/server/src/modules/Export/decorators/ExportableModel.decorator.ts @@ -0,0 +1,32 @@ +const exportableModels = new Map(); +const exportableService = new Map() + +/** + * Decorator that marks a model as exportable and registers its metadata. + * @param metadata Model metadata configuration for export + */ +export function ExportableModel() { + return function (target: any) { + const modelName = target.name; + exportableModels.set(modelName, true); + }; +} + +export function ExportableService({ name }: { name: string }) { + return function (target: any) { + exportableService.set(name, target); + }; +} + +/** + * Gets the registered exportable model metadata + * @param modelName Name of the model class + */ +export function getExportableModelMeta(modelName: string): boolean | undefined { + return exportableModels.get(modelName); +} + + +export function getExportableService(modelName: string) { + return exportableService.get(modelName); +} \ No newline at end of file diff --git a/packages/server/src/modules/Import/_utils.ts b/packages/server/src/modules/Import/_utils.ts index 43c80c912..a43d26737 100644 --- a/packages/server/src/modules/Import/_utils.ts +++ b/packages/server/src/modules/Import/_utils.ts @@ -20,9 +20,9 @@ import { } from 'lodash'; import pluralize from 'pluralize'; import { ResourceMetaFieldsMap } from './interfaces'; -import { IModelMetaField, IModelMetaField2 } from '@/interfaces'; -import { ServiceError } from '@/exceptions'; import { multiNumberParse } from '@/utils/multi-number-parse'; +import { ServiceError } from '../Items/ServiceError'; +import { IModelMetaField, IModelMetaField2 } from '@/interfaces/Model'; export const ERRORS = { RESOURCE_NOT_IMPORTABLE: 'RESOURCE_NOT_IMPORTABLE', @@ -336,7 +336,7 @@ export const valueParser = * @param {string} key - Mapped key path. formats: `group.key` or `key`. * @returns {string} */ -export const parseKey: R.Curry = R.curry( +export const parseKey = R.curry( (fields: { [key: string]: IModelMetaField2 }, key: string) => { const fieldKey = getFieldKey(key); const field = fields[fieldKey]; diff --git a/packages/server/src/modules/Import/models/Import.ts b/packages/server/src/modules/Import/models/Import.ts index 2d9d4f468..a34468005 100644 --- a/packages/server/src/modules/Import/models/Import.ts +++ b/packages/server/src/modules/Import/models/Import.ts @@ -8,6 +8,7 @@ export class Import extends BaseModel { mapping!: string; columns!: string; params!: string; + importId!: string; /** * Table name. diff --git a/packages/server/src/modules/ItemCategories/ItemCategoriesExportable.ts b/packages/server/src/modules/ItemCategories/ItemCategoriesExportable.ts index 3b0d16fd4..2b19d02ca 100644 --- a/packages/server/src/modules/ItemCategories/ItemCategoriesExportable.ts +++ b/packages/server/src/modules/ItemCategories/ItemCategoriesExportable.ts @@ -1,29 +1,29 @@ -// import { Inject, Service } from 'typedi'; -// import { Exportable } from '../Export/Exportable'; -// import { IAccountsFilter, IAccountsStructureType } from '@/interfaces'; -// import ItemCategoriesService from './ItemCategoriesService'; +import { Injectable } from '@nestjs/common'; +import { Exportable } from '../Export/Exportable'; +import { ItemCategoryApplication } from './ItemCategory.application'; +import { IItemCategoriesFilter } from './ItemCategory.interfaces'; +import { ExportableService } from '../Export/decorators/ExportableModel.decorator'; +import { ItemCategory } from './models/ItemCategory.model'; -// @Service() -// export class ItemCategoriesExportable extends Exportable { -// @Inject() -// private itemCategoriesApplication: ItemCategoriesService; +@Injectable() +@ExportableService({ name: ItemCategory.name }) +export class ItemCategoriesExportable extends Exportable { + constructor(private readonly itemCategoryApp: ItemCategoryApplication) { + super(); + } -// /** -// * Retrieves the accounts data to exportable sheet. -// * @param {number} tenantId -// * @returns -// */ -// public exportable(tenantId: number, query: IAccountsFilter) { -// const parsedQuery = { -// sortOrder: 'desc', -// columnSortBy: 'created_at', -// inactiveMode: false, -// ...query, -// structure: IAccountsStructureType.Flat, -// } as IAccountsFilter; + /** + * Retrieves the accounts data to exportable sheet. + * @param {number} tenantId + * @returns + */ + public exportable(query: Partial) { + const parsedQuery = { + ...query + } as IItemCategoriesFilter; -// return this.itemCategoriesApplication -// .getItemCategoriesList(tenantId, parsedQuery, {}) -// .then((output) => output.itemCategories); -// } -// } + return this.itemCategoryApp + .getItemCategories(parsedQuery) + .then((output) => output.itemCategories); + } +} diff --git a/packages/server/src/modules/ItemCategories/ItemCategory.module.ts b/packages/server/src/modules/ItemCategories/ItemCategory.module.ts index f78e46145..233ba1506 100644 --- a/packages/server/src/modules/ItemCategories/ItemCategory.module.ts +++ b/packages/server/src/modules/ItemCategories/ItemCategory.module.ts @@ -11,6 +11,7 @@ import { TransformerInjectable } from '../Transformer/TransformerInjectable.serv import { TenancyContext } from '../Tenancy/TenancyContext.service'; import { GetItemCategoriesService } from './queries/GetItemCategories.service'; import { DynamicListModule } from '../DynamicListing/DynamicList.module'; +import { ItemCategoriesExportable } from './ItemCategoriesExportable'; @Module({ imports: [TenancyDatabaseModule, DynamicListModule], @@ -23,6 +24,7 @@ import { DynamicListModule } from '../DynamicListing/DynamicList.module'; DeleteItemCategoryService, ItemCategoryApplication, CommandItemCategoryValidatorService, + ItemCategoriesExportable, TransformerInjectable, TenancyContext, ], diff --git a/packages/server/src/modules/ItemCategories/models/ItemCategory.model.ts b/packages/server/src/modules/ItemCategories/models/ItemCategory.model.ts index cb57c6d68..8fbfafbbb 100644 --- a/packages/server/src/modules/ItemCategories/models/ItemCategory.model.ts +++ b/packages/server/src/modules/ItemCategories/models/ItemCategory.model.ts @@ -1,6 +1,8 @@ +import { ExportableModel } from '@/modules/Export/decorators/ExportableModel.decorator'; import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel'; import { Model } from 'objection'; +@ExportableModel() export class ItemCategory extends TenantBaseModel { name!: string; description!: string; diff --git a/packages/server/src/modules/Items/models/Item.ts b/packages/server/src/modules/Items/models/Item.ts index 4a9960d97..3b7f33cd4 100644 --- a/packages/server/src/modules/Items/models/Item.ts +++ b/packages/server/src/modules/Items/models/Item.ts @@ -1,7 +1,9 @@ import { Warehouse } from '@/modules/Warehouses/models/Warehouse.model'; import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel'; import { Model } from 'objection'; +import { ExportableModel } from '@/modules/Export/decorators/ExportableModel.decorator'; +@ExportableModel() export class Item extends TenantBaseModel { public readonly quantityOnHand: number; public readonly name: string; diff --git a/packages/server/src/modules/ManualJournals/ManualJournals.module.ts b/packages/server/src/modules/ManualJournals/ManualJournals.module.ts index 112e513cf..bf217d88e 100644 --- a/packages/server/src/modules/ManualJournals/ManualJournals.module.ts +++ b/packages/server/src/modules/ManualJournals/ManualJournals.module.ts @@ -15,6 +15,7 @@ import { GetManualJournal } from './queries/GetManualJournal.service'; import { ManualJournalWriteGLSubscriber } from './commands/ManualJournalGLEntriesSubscriber'; import { ManualJournalGLEntries } from './commands/ManualJournalGLEntries'; import { LedgerModule } from '../Ledger/Ledger.module'; +import { ManualJournalsExportable } from './commands/ManualJournalExportable'; @Module({ imports: [BranchesModule, LedgerModule], @@ -33,7 +34,8 @@ import { LedgerModule } from '../Ledger/Ledger.module'; ManualJournalsApplication, GetManualJournal, ManualJournalGLEntries, - ManualJournalWriteGLSubscriber + ManualJournalWriteGLSubscriber, + ManualJournalsExportable ], }) export class ManualJournalsModule {} diff --git a/packages/server/src/modules/ManualJournals/ManualJournalsApplication.service.ts b/packages/server/src/modules/ManualJournals/ManualJournalsApplication.service.ts index 49ba23a93..a19a8f153 100644 --- a/packages/server/src/modules/ManualJournals/ManualJournalsApplication.service.ts +++ b/packages/server/src/modules/ManualJournals/ManualJournalsApplication.service.ts @@ -4,8 +4,12 @@ import { EditManualJournal } from './commands/EditManualJournal.service'; import { PublishManualJournal } from './commands/PublishManualJournal.service'; import { GetManualJournal } from './queries/GetManualJournal.service'; import { DeleteManualJournalService } from './commands/DeleteManualJournal.service'; -import { IManualJournalDTO, } from './types/ManualJournals.types'; -import { CreateManualJournalDto, EditManualJournalDto } from './dtos/ManualJournal.dto'; +import { IManualJournalsFilter } from './types/ManualJournals.types'; +import { + CreateManualJournalDto, + EditManualJournalDto, +} from './dtos/ManualJournal.dto'; +import { GetManualJournals } from './queries/GetManualJournals.service'; // import { GetManualJournals } from './queries/GetManualJournals'; @Injectable() @@ -16,7 +20,7 @@ export class ManualJournalsApplication { private deleteManualJournalService: DeleteManualJournalService, private publishManualJournalService: PublishManualJournal, private getManualJournalService: GetManualJournal, - // private getManualJournalsService: GetManualJournals, + private getManualJournalsService: GetManualJournals, ) {} /** @@ -50,9 +54,7 @@ export class ManualJournalsApplication { * @return {Promise} */ public deleteManualJournal = (manualJournalId: number) => { - return this.deleteManualJournalService.deleteManualJournal( - manualJournalId, - ); + return this.deleteManualJournalService.deleteManualJournal(manualJournalId); }; /** @@ -68,23 +70,16 @@ export class ManualJournalsApplication { /** * Retrieves the specific manual journal. * @param {number} manualJournalId - * @returns */ public getManualJournal = (manualJournalId: number) => { - return this.getManualJournalService.getManualJournal( - manualJournalId, - ); + return this.getManualJournalService.getManualJournal(manualJournalId); }; /** * Retrieves the paginated manual journals. - * @param {number} tenantId * @param {IManualJournalsFilter} filterDTO - * @returns */ - // public getManualJournals = ( - // filterDTO: IManualJournalsFilter, - // ) => { - // // return this.getManualJournalsService.getManualJournals(filterDTO); - // }; + public getManualJournals = (filterDTO: IManualJournalsFilter) => { + return this.getManualJournalsService.getManualJournals(filterDTO); + }; } diff --git a/packages/server/src/modules/ManualJournals/commands/ManualJournalExportable.ts b/packages/server/src/modules/ManualJournals/commands/ManualJournalExportable.ts index a91eee5b9..dc96bf0cd 100644 --- a/packages/server/src/modules/ManualJournals/commands/ManualJournalExportable.ts +++ b/packages/server/src/modules/ManualJournals/commands/ManualJournalExportable.ts @@ -1,30 +1,31 @@ -// import { Inject, Service } from 'typedi'; -// import { IManualJournalsFilter } from '@/interfaces'; -// import { Exportable } from '../../Export/Exportable'; -// import { ManualJournalsApplication } from '../ManualJournalsApplication'; -// import { EXPORT_SIZE_LIMIT } from '../../Export/constants'; +import { Exportable } from '../../Export/Exportable'; +import { EXPORT_SIZE_LIMIT } from '../../Export/constants'; +import { Injectable } from '@nestjs/common'; +import { IManualJournalsFilter } from '../types/ManualJournals.types'; +import { ManualJournalsApplication } from '../ManualJournalsApplication.service'; -// @Service() -// export class ManualJournalsExportable extends Exportable { -// @Inject() -// private manualJournalsApplication: ManualJournalsApplication; +@Injectable() +export class ManualJournalsExportable extends Exportable { + constructor( + private readonly manualJournalsApplication: ManualJournalsApplication, + ) { + super(); + } -// /** -// * Retrieves the manual journals data to exportable sheet. -// * @param {number} tenantId -// * @returns -// */ -// public exportable(tenantId: number, query: IManualJournalsFilter) { -// const parsedQuery = { -// sortOrder: 'desc', -// columnSortBy: 'created_at', -// ...query, -// page: 1, -// pageSize: EXPORT_SIZE_LIMIT, -// } as IManualJournalsFilter; + /** + * Retrieves the manual journals data to exportable sheet. + */ + public exportable(query: IManualJournalsFilter) { + const parsedQuery = { + sortOrder: 'desc', + columnSortBy: 'created_at', + ...query, + page: 1, + pageSize: EXPORT_SIZE_LIMIT, + } as IManualJournalsFilter; -// return this.manualJournalsApplication -// .getManualJournals(tenantId, parsedQuery) -// .then((output) => output.manualJournals); -// } -// } + return this.manualJournalsApplication + .getManualJournals(parsedQuery) + .then((output) => output.manualJournals); + } +} diff --git a/packages/server/src/modules/ManualJournals/models/ManualJournal.ts b/packages/server/src/modules/ManualJournals/models/ManualJournal.ts index c7892eed3..e9e1b1077 100644 --- a/packages/server/src/modules/ManualJournals/models/ManualJournal.ts +++ b/packages/server/src/modules/ManualJournals/models/ManualJournal.ts @@ -9,7 +9,9 @@ import { Model, mixin } from 'objection'; import { ManualJournalEntry } from './ManualJournalEntry'; import { Document } from '@/modules/ChromiumlyTenancy/models/Document'; import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel'; +import { ExportableModel } from '@/modules/Export/decorators/ExportableModel.decorator'; +@ExportableModel() export class ManualJournal extends TenantBaseModel { date: Date; journalNumber: string; diff --git a/packages/server/src/modules/PaymentReceived/PaymentsReceived.module.ts b/packages/server/src/modules/PaymentReceived/PaymentsReceived.module.ts index d9709dd14..c6292691f 100644 --- a/packages/server/src/modules/PaymentReceived/PaymentsReceived.module.ts +++ b/packages/server/src/modules/PaymentReceived/PaymentsReceived.module.ts @@ -34,6 +34,7 @@ import { MailModule } from '../Mail/Mail.module'; import { SendPaymentReceivedMailProcessor } from './processors/PaymentReceivedMailNotification.processor'; import { BullModule } from '@nestjs/bull'; import { SEND_PAYMENT_RECEIVED_MAIL_QUEUE } from './constants'; +import { PaymentsReceivedExportable } from './commands/PaymentsReceivedExportable'; @Module({ controllers: [PaymentReceivesController], @@ -59,6 +60,7 @@ import { SEND_PAYMENT_RECEIVED_MAIL_QUEUE } from './constants'; GetPaymentsReceivedService, SendPaymentReceiveMailNotification, SendPaymentReceivedMailProcessor, + PaymentsReceivedExportable ], exports: [ PaymentReceivesApplication, diff --git a/packages/server/src/modules/PaymentReceived/commands/PaymentsReceivedExportable.ts b/packages/server/src/modules/PaymentReceived/commands/PaymentsReceivedExportable.ts index fdac2fda6..abdd81a95 100644 --- a/packages/server/src/modules/PaymentReceived/commands/PaymentsReceivedExportable.ts +++ b/packages/server/src/modules/PaymentReceived/commands/PaymentsReceivedExportable.ts @@ -1,39 +1,34 @@ -// import { Inject, Service } from 'typedi'; -// import { IAccountsStructureType, IPaymentsReceivedFilter } from '@/interfaces'; -// import { Exportable } from '@/services/Export/Exportable'; -// import { PaymentReceivesApplication } from './PaymentReceived.application'; -// import { EXPORT_SIZE_LIMIT } from '@/services/Export/constants'; +import { Injectable } from '@nestjs/common'; +import { PaymentReceivesApplication } from '../PaymentReceived.application'; +import { IPaymentsReceivedFilter } from '../types/PaymentReceived.types'; +import { EXPORT_SIZE_LIMIT } from '@/modules/Export/constants'; +import { Exportable } from '@/modules/Export/Exportable'; -// @Service() -// export class PaymentsReceivedExportable extends Exportable { -// @Inject() -// private paymentReceivedApp: PaymentReceivesApplication; +@Injectable() +export class PaymentsReceivedExportable extends Exportable { + constructor(private readonly paymentReceivedApp: PaymentReceivesApplication) { + super(); + } -// /** -// * Retrieves the accounts data to exportable sheet. -// * @param {number} tenantId -// * @param {IPaymentsReceivedFilter} query - -// * @returns -// */ -// public exportable(tenantId: number, query: IPaymentsReceivedFilter) { -// const filterQuery = (builder) => { -// builder.withGraphFetched('entries.invoice'); -// builder.withGraphFetched('branch'); -// }; - -// const parsedQuery = { -// sortOrder: 'desc', -// columnSortBy: 'created_at', -// inactiveMode: false, -// ...query, -// structure: IAccountsStructureType.Flat, -// page: 1, -// pageSize: EXPORT_SIZE_LIMIT, -// filterQuery, -// } as IPaymentsReceivedFilter; - -// return this.paymentReceivedApp -// .getPaymentReceives(tenantId, parsedQuery) -// .then((output) => output.paymentReceives); -// } -// } + /** + * Retrieves the accounts data to exportable sheet. + * @param {number} tenantId + * @param {IPaymentsReceivedFilter} query - + * @returns + */ + public exportable(query: IPaymentsReceivedFilter) { + const filterQuery = (builder) => { + builder.withGraphFetched('entries.invoice'); + builder.withGraphFetched('branch'); + }; + const parsedQuery = { + page: 1, + pageSize: EXPORT_SIZE_LIMIT, + filterQuery, + ...query + }; + return this.paymentReceivedApp + .getPaymentsReceived(parsedQuery) + .then((output) => output.paymentReceives); + } +} diff --git a/packages/server/src/modules/PaymentReceived/models/PaymentReceived.ts b/packages/server/src/modules/PaymentReceived/models/PaymentReceived.ts index a3f82f5c2..181a910e4 100644 --- a/packages/server/src/modules/PaymentReceived/models/PaymentReceived.ts +++ b/packages/server/src/modules/PaymentReceived/models/PaymentReceived.ts @@ -1,7 +1,9 @@ import { Model } from 'objection'; import { PaymentReceivedEntry } from './PaymentReceivedEntry'; import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel'; +import { ExportableModel } from '@/modules/Export/decorators/ExportableModel.decorator'; +@ExportableModel() export class PaymentReceived extends TenantBaseModel { customerId: number; paymentDate: string; diff --git a/packages/server/src/modules/SaleEstimates/SaleEstimates.module.ts b/packages/server/src/modules/SaleEstimates/SaleEstimates.module.ts index 83a5e2bef..d310869ae 100644 --- a/packages/server/src/modules/SaleEstimates/SaleEstimates.module.ts +++ b/packages/server/src/modules/SaleEstimates/SaleEstimates.module.ts @@ -35,6 +35,7 @@ import { TemplateInjectableModule } from '../TemplateInjectable/TemplateInjectab import { SaleEstimatePdfTemplate } from '../SaleInvoices/queries/SaleEstimatePdfTemplate.service'; import { PdfTemplatesModule } from '../PdfTemplate/PdfTemplates.module'; import { SendSaleEstimateMailQueue } from './types/SaleEstimates.types'; +import { SaleEstimatesExportable } from './SaleEstimatesExportable'; @Module({ imports: [ @@ -74,7 +75,8 @@ import { SendSaleEstimateMailQueue } from './types/SaleEstimates.types'; SaleEstimatesApplication, SendSaleEstimateMail, GetSaleEstimatePdf, - SaleEstimatePdfTemplate + SaleEstimatePdfTemplate, + SaleEstimatesExportable ], }) export class SaleEstimatesModule {} diff --git a/packages/server/src/modules/SaleEstimates/SaleEstimatesExportable.ts b/packages/server/src/modules/SaleEstimates/SaleEstimatesExportable.ts index 889e7ca7a..4937223fe 100644 --- a/packages/server/src/modules/SaleEstimates/SaleEstimatesExportable.ts +++ b/packages/server/src/modules/SaleEstimates/SaleEstimatesExportable.ts @@ -1,35 +1,38 @@ -// import { Inject, Service } from 'typedi'; -// import { ISalesInvoicesFilter } from '@/interfaces'; -// import { Exportable } from '@/services/Export/Exportable'; -// import { SaleEstimatesApplication } from './SaleEstimates.application'; -// import { EXPORT_SIZE_LIMIT } from '@/services/Export/constants'; +import { Injectable } from '@nestjs/common'; +import { EXPORT_SIZE_LIMIT } from '../Export/constants'; +import { Exportable } from '../Export/Exportable'; +import { ISalesInvoicesFilter } from '../SaleInvoices/SaleInvoice.types'; +import { SaleEstimatesApplication } from './SaleEstimates.application'; +import { ISalesEstimatesFilter } from './types/SaleEstimates.types'; -// @Service() -// export class SaleEstimatesExportable extends Exportable { -// @Inject() -// private saleEstimatesApplication: SaleEstimatesApplication; +@Injectable() +export class SaleEstimatesExportable extends Exportable { + constructor( + private readonly saleEstimatesApplication: SaleEstimatesApplication, + ) { + super(); + } -// /** -// * Retrieves the accounts data to exportable sheet. -// * @param {number} tenantId -// * @returns -// */ -// public exportable(tenantId: number, query: ISalesInvoicesFilter) { -// const filterQuery = (query) => { -// query.withGraphFetched('branch'); -// query.withGraphFetched('warehouse'); -// }; -// const parsedQuery = { -// sortOrder: 'desc', -// columnSortBy: 'created_at', -// ...query, -// page: 1, -// pageSize: EXPORT_SIZE_LIMIT, -// filterQuery, -// } as ISalesInvoicesFilter; + /** + * Retrieves the accounts data to exportable sheet. + * @param {ISalesEstimatesFilter} query - + */ + public exportable(query: ISalesEstimatesFilter) { + const filterQuery = (query) => { + query.withGraphFetched('branch'); + query.withGraphFetched('warehouse'); + }; + const parsedQuery = { + sortOrder: 'desc', + columnSortBy: 'created_at', + ...query, + page: 1, + pageSize: EXPORT_SIZE_LIMIT, + filterQuery, + } as ISalesInvoicesFilter; -// return this.saleEstimatesApplication -// .getSaleEstimates(tenantId, parsedQuery) -// .then((output) => output.salesEstimates); -// } -// } + return this.saleEstimatesApplication + .getSaleEstimates(parsedQuery) + .then((output) => output.salesEstimates); + } +} diff --git a/packages/server/src/modules/SaleEstimates/models/SaleEstimate.ts b/packages/server/src/modules/SaleEstimates/models/SaleEstimate.ts index 611881f8f..c772eb544 100644 --- a/packages/server/src/modules/SaleEstimates/models/SaleEstimate.ts +++ b/packages/server/src/modules/SaleEstimates/models/SaleEstimate.ts @@ -2,8 +2,9 @@ import * as moment from 'moment'; import { Model } from 'objection'; import { Injectable } from '@nestjs/common'; import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel'; +import { ExportableModel } from '@/modules/Export/decorators/ExportableModel.decorator'; -@Injectable() +@ExportableModel() export class SaleEstimate extends TenantBaseModel { exchangeRate!: number; amount!: number; diff --git a/packages/server/src/modules/SaleInvoices/SaleInvoices.module.ts b/packages/server/src/modules/SaleInvoices/SaleInvoices.module.ts index a4ac13327..3c5bcbfe3 100644 --- a/packages/server/src/modules/SaleInvoices/SaleInvoices.module.ts +++ b/packages/server/src/modules/SaleInvoices/SaleInvoices.module.ts @@ -56,6 +56,7 @@ import { SaleInvoiceCostGLEntries } from './SaleInvoiceCostGLEntries'; import { InvoicePaymentsGLEntriesRewrite } from './InvoicePaymentsGLRewrite'; import { PaymentsReceivedModule } from '../PaymentReceived/PaymentsReceived.module'; import { SaleInvoicesCost } from './SalesInvoicesCost'; +import { SaleInvoicesExportable } from './commands/SaleInvoicesExportable'; @Module({ imports: [ @@ -118,6 +119,7 @@ import { SaleInvoicesCost } from './SalesInvoicesCost'; SaleInvoiceWriteInventoryTransactionsSubscriber, InvoicePaymentsGLEntriesRewrite, SaleInvoicesCost, + SaleInvoicesExportable ], exports: [GetSaleInvoice, SaleInvoicesCost, SaleInvoicePdf], }) diff --git a/packages/server/src/modules/SaleInvoices/commands/SaleInvoicesExportable.ts b/packages/server/src/modules/SaleInvoices/commands/SaleInvoicesExportable.ts index 319c1d801..4d8df9c25 100644 --- a/packages/server/src/modules/SaleInvoices/commands/SaleInvoicesExportable.ts +++ b/packages/server/src/modules/SaleInvoices/commands/SaleInvoicesExportable.ts @@ -1,35 +1,39 @@ -// import { Inject, Service } from 'typedi'; -// import { ISalesInvoicesFilter } from '@/interfaces'; -// import { SaleInvoiceApplication } from './SaleInvoices.application'; -// import { Exportable } from '@/services/Export/Exportable'; -// import { EXPORT_SIZE_LIMIT } from '@/services/Export/constants'; +import { Exportable } from '@/modules/Export/Exportable'; +import { Injectable } from '@nestjs/common'; +import { SaleInvoiceApplication } from '../SaleInvoices.application'; +import { ISalesInvoicesFilter } from '../SaleInvoice.types'; +import { EXPORT_SIZE_LIMIT } from '@/modules/Export/constants'; +import { ExportableService } from '@/modules/Export/decorators/ExportableModel.decorator'; +import { SaleInvoice } from '../models/SaleInvoice'; -// @Service() -// export class SaleInvoicesExportable extends Exportable { -// @Inject() -// private saleInvoicesApplication: SaleInvoiceApplication; +@Injectable() +@ExportableService({ name: SaleInvoice.name }) +export class SaleInvoicesExportable extends Exportable{ + constructor( + private readonly saleInvoicesApplication: SaleInvoiceApplication, + ) { + super(); + } -// /** -// * Retrieves the accounts data to exportable sheet. -// * @param {number} tenantId -// * @returns -// */ -// public exportable(tenantId: number, query: ISalesInvoicesFilter) { -// const filterQuery = (query) => { -// query.withGraphFetched('branch'); -// query.withGraphFetched('warehouse'); -// }; -// const parsedQuery = { -// sortOrder: 'desc', -// columnSortBy: 'created_at', -// ...query, -// page: 1, -// pageSize: EXPORT_SIZE_LIMIT, -// filterQuery, -// } as ISalesInvoicesFilter; + /** + * Retrieves the accounts data to exportable sheet. + */ + public exportable(query: ISalesInvoicesFilter) { + const filterQuery = (query) => { + query.withGraphFetched('branch'); + query.withGraphFetched('warehouse'); + }; + const parsedQuery = { + sortOrder: 'desc', + columnSortBy: 'created_at', + ...query, + page: 1, + pageSize: EXPORT_SIZE_LIMIT, + filterQuery, + } as ISalesInvoicesFilter; -// return this.saleInvoicesApplication -// .getSaleInvoices(tenantId, parsedQuery) -// .then((output) => output.salesInvoices); -// } -// } + return this.saleInvoicesApplication + .getSaleInvoices(parsedQuery) + .then((output) => output.salesInvoices); + } +} diff --git a/packages/server/src/modules/SaleInvoices/models/SaleInvoice.ts b/packages/server/src/modules/SaleInvoices/models/SaleInvoice.ts index 3d64ba94b..c7d490eb8 100644 --- a/packages/server/src/modules/SaleInvoices/models/SaleInvoice.ts +++ b/packages/server/src/modules/SaleInvoices/models/SaleInvoice.ts @@ -14,8 +14,10 @@ import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel'; import { PaymentIntegrationTransactionLink } from '../SaleInvoice.types'; import { TransactionPaymentServiceEntry } from '@/modules/PaymentServices/models/TransactionPaymentServiceEntry.model'; import { InjectAttachable } from '@/modules/Attachments/decorators/InjectAttachable.decorator'; +import { ExportableModel } from '@/modules/Export/decorators/ExportableModel.decorator'; @InjectAttachable() +@ExportableModel() export class SaleInvoice extends TenantBaseModel{ public taxAmountWithheld: number; public balance: number; diff --git a/packages/server/src/modules/SaleReceipts/SaleReceipts.module.ts b/packages/server/src/modules/SaleReceipts/SaleReceipts.module.ts index 255be3d42..bda6a185c 100644 --- a/packages/server/src/modules/SaleReceipts/SaleReceipts.module.ts +++ b/packages/server/src/modules/SaleReceipts/SaleReceipts.module.ts @@ -35,6 +35,7 @@ import { MailNotificationModule } from '../MailNotification/MailNotification.mod import { SendSaleReceiptMailProcess } from './processes/SendSaleReceiptMail.process'; import { MailModule } from '../Mail/Mail.module'; import { SendSaleReceiptMailQueue } from './constants'; +import { SaleReceiptsExportable } from './commands/SaleReceiptsExportable'; @Module({ controllers: [SaleReceiptsController], @@ -75,6 +76,7 @@ import { SendSaleReceiptMailQueue } from './constants'; SaleReceiptInventoryTransactions, SaleReceiptInventoryTransactionsSubscriber, SendSaleReceiptMailProcess, + SaleReceiptsExportable ], }) export class SaleReceiptsModule {} diff --git a/packages/server/src/modules/SaleReceipts/commands/SaleReceiptsExportable.ts b/packages/server/src/modules/SaleReceipts/commands/SaleReceiptsExportable.ts index a8f91bea5..88d565f87 100644 --- a/packages/server/src/modules/SaleReceipts/commands/SaleReceiptsExportable.ts +++ b/packages/server/src/modules/SaleReceipts/commands/SaleReceiptsExportable.ts @@ -1,35 +1,35 @@ -// import { Inject, Service } from 'typedi'; -// import { ISalesReceiptsFilter } from '@/interfaces'; -// import { Exportable } from '@/services/Export/Exportable'; -// import { SaleReceiptApplication } from './SaleReceiptApplication'; -// import { EXPORT_SIZE_LIMIT } from '@/services/Export/constants'; +import { Exportable } from '@/modules/Export/Exportable'; +import { Injectable } from '@nestjs/common'; +import { SaleReceiptApplication } from '../SaleReceiptApplication.service'; +import { ISalesReceiptsFilter } from '../types/SaleReceipts.types'; +import { EXPORT_SIZE_LIMIT } from '@/modules/Export/constants'; -// @Service() -// export class SaleReceiptsExportable extends Exportable { -// @Inject() -// private saleReceiptsApp: SaleReceiptApplication; +@Injectable() +export class SaleReceiptsExportable extends Exportable { + constructor(private readonly saleReceiptsApp: SaleReceiptApplication) { + super(); + } -// /** -// * Retrieves the accounts data to exportable sheet. -// * @param {number} tenantId -// * @returns -// */ -// public exportable(tenantId: number, query: ISalesReceiptsFilter) { -// const filterQuery = (query) => { -// query.withGraphFetched('branch'); -// query.withGraphFetched('warehouse'); -// }; -// const parsedQuery = { -// sortOrder: 'desc', -// columnSortBy: 'created_at', -// ...query, -// page: 1, -// pageSize: EXPORT_SIZE_LIMIT, -// filterQuery, -// } as ISalesReceiptsFilter; + /** + * Retrieves the accounts data to exportable sheet. + * @param {ISalesReceiptsFilter} query - + */ + public exportable(query: ISalesReceiptsFilter) { + const filterQuery = (query) => { + query.withGraphFetched('branch'); + query.withGraphFetched('warehouse'); + }; + const parsedQuery = { + sortOrder: 'desc', + columnSortBy: 'created_at', + ...query, + page: 1, + pageSize: EXPORT_SIZE_LIMIT, + filterQuery, + } as ISalesReceiptsFilter; -// return this.saleReceiptsApp -// .getSaleReceipts(tenantId, parsedQuery) -// .then((output) => output.data); -// } -// } + return this.saleReceiptsApp + .getSaleReceipts(parsedQuery) + .then((output) => output.data); + } +} diff --git a/packages/server/src/modules/SaleReceipts/models/SaleReceipt.ts b/packages/server/src/modules/SaleReceipts/models/SaleReceipt.ts index 9102075b9..80b880398 100644 --- a/packages/server/src/modules/SaleReceipts/models/SaleReceipt.ts +++ b/packages/server/src/modules/SaleReceipts/models/SaleReceipt.ts @@ -12,6 +12,7 @@ import { MetadataModelMixin } from '@/modules/DynamicListing/models/MetadataMode import { ResourceableModelMixin } from '@/modules/Resource/models/ResourcableModel'; import { CustomViewBaseModelMixin } from '@/modules/CustomViews/CustomViewBaseModel'; import { SearchableBaseModelMixin } from '@/modules/DynamicListing/models/SearchableBaseModel'; +import { ExportableModel } from '@/modules/Export/decorators/ExportableModel.decorator'; const ExtendedModel = R.pipe( CustomViewBaseModelMixin, @@ -20,6 +21,7 @@ const ExtendedModel = R.pipe( MetadataModelMixin, )(BaseModel); +@ExportableModel() export class SaleReceipt extends ExtendedModel { public amount!: number; public exchangeRate!: number; diff --git a/packages/server/src/modules/TaxRates/TaxRate.module.ts b/packages/server/src/modules/TaxRates/TaxRate.module.ts index 97d62856f..38f886255 100644 --- a/packages/server/src/modules/TaxRates/TaxRate.module.ts +++ b/packages/server/src/modules/TaxRates/TaxRate.module.ts @@ -21,6 +21,7 @@ import { WriteTaxTransactionsItemEntries } from './WriteTaxTransactionsItemEntri import { SyncItemTaxRateOnEditTaxRate } from './SyncItemTaxRateOnEditTaxRate'; import { RegisterTenancyModel } from '../Tenancy/TenancyModels/Tenancy.module'; import { TaxRateTransaction } from './models/TaxRateTransaction.model'; +import { TaxRatesExportable } from './TaxRatesExportable'; const models = [RegisterTenancyModel(TaxRateTransaction)]; @@ -47,6 +48,7 @@ const models = [RegisterTenancyModel(TaxRateTransaction)]; SyncItemTaxRateOnEditTaxSubscriber, WriteTaxTransactionsItemEntries, SyncItemTaxRateOnEditTaxRate, + TaxRatesExportable ], exports: [ItemEntriesTaxTransactions, ...models], }) diff --git a/packages/server/src/modules/TaxRates/TaxRatesExportable.ts b/packages/server/src/modules/TaxRates/TaxRatesExportable.ts index 079a09637..ed2509840 100644 --- a/packages/server/src/modules/TaxRates/TaxRatesExportable.ts +++ b/packages/server/src/modules/TaxRates/TaxRatesExportable.ts @@ -1,18 +1,20 @@ -// import { Inject, Service } from 'typedi'; -// import { Exportable } from '../Export/Exportable'; -// import { TaxRatesApplication } from './TaxRate.application'; +import { ExportableService } from '../Export/decorators/ExportableModel.decorator'; +import { Exportable } from '../Export/Exportable'; +import { TaxRateModel } from './models/TaxRate.model'; +import { TaxRatesApplication } from './TaxRate.application'; +import { Injectable } from '@nestjs/common'; -// @Service() -// export class TaxRatesExportable extends Exportable { -// @Inject() -// private taxRatesApplication: TaxRatesApplication; +@Injectable() +@ExportableService({ name: TaxRateModel.name }) +export class TaxRatesExportable extends Exportable { + constructor(private readonly taxRatesApplication: TaxRatesApplication) { + super(); + } -// /** -// * Retrieves the accounts data to exportable sheet. -// * @param {number} tenantId -// * @returns -// */ -// public exportable(tenantId: number) { -// return this.taxRatesApplication.getTaxRates(tenantId); -// } -// } + /** + * Retrieves the accounts data to exportable sheet. + */ + public exportable() { + return this.taxRatesApplication.getTaxRates(); + } +} diff --git a/packages/server/src/modules/TaxRates/models/TaxRate.model.ts b/packages/server/src/modules/TaxRates/models/TaxRate.model.ts index 4bdd9bab4..1442e7920 100644 --- a/packages/server/src/modules/TaxRates/models/TaxRate.model.ts +++ b/packages/server/src/modules/TaxRates/models/TaxRate.model.ts @@ -5,7 +5,9 @@ import { mixin, Model, raw } from 'objection'; // import TaxRateMeta from './TaxRate.settings'; // import ModelSetting from './ModelSetting'; import { BaseModel } from '@/models/Model'; +import { ExportableModel } from '@/modules/Export/decorators/ExportableModel.decorator'; +@ExportableModel() export class TaxRateModel extends BaseModel { active!: boolean; code!: string; diff --git a/packages/server/src/modules/VendorCredit/VendorCredits.module.ts b/packages/server/src/modules/VendorCredit/VendorCredits.module.ts index d7d81c3ec..915119f4a 100644 --- a/packages/server/src/modules/VendorCredit/VendorCredits.module.ts +++ b/packages/server/src/modules/VendorCredit/VendorCredits.module.ts @@ -25,6 +25,7 @@ import { VendorCreditInventoryTransactions } from './commands/VendorCreditInvent import { GetVendorCreditsService } from './queries/GetVendorCredits.service'; import { DynamicListModule } from '../DynamicListing/DynamicList.module'; import { InventoryCostModule } from '../InventoryCost/InventoryCost.module'; +import { VendorCreditsExportable } from './commands/VendorCreditsExportable'; @Module({ imports: [ @@ -54,7 +55,8 @@ import { InventoryCostModule } from '../InventoryCost/InventoryCost.module'; VendorCreditGLEntries, VendorCreditGlEntriesSubscriber, VendorCreditInventoryTransactions, - VendorCreditInventoryTransactionsSubscriber + VendorCreditInventoryTransactionsSubscriber, + VendorCreditsExportable ], exports: [ CreateVendorCreditService, diff --git a/packages/server/src/modules/VendorCredit/commands/VendorCreditsExportable.ts b/packages/server/src/modules/VendorCredit/commands/VendorCreditsExportable.ts index 39a688896..84291d10c 100644 --- a/packages/server/src/modules/VendorCredit/commands/VendorCreditsExportable.ts +++ b/packages/server/src/modules/VendorCredit/commands/VendorCreditsExportable.ts @@ -1,36 +1,38 @@ -// import { Inject, Service } from 'typedi'; -// import { IVendorCreditsQueryDTO } from '@/interfaces'; -// import ListVendorCredits from '../queries/ListVendorCredits'; -// import { Exportable } from '@/services/Export/Exportable'; -// import { QueryBuilder } from 'knex'; +import { Injectable } from '@nestjs/common'; +import { VendorCreditsApplicationService } from '../VendorCreditsApplication.service'; +import { Exportable } from '@/modules/Export/Exportable'; +import { IVendorCreditsQueryDTO } from '../types/VendorCredit.types'; +import { ExportableService } from '@/modules/Export/decorators/ExportableModel.decorator'; +import { VendorCredit } from '../models/VendorCredit'; -// @Service() -// export class VendorCreditsExportable extends Exportable { -// @Inject() -// private getVendorCredits: ListVendorCredits; +@Injectable() +@ExportableService({ name: VendorCredit.name }) +export class VendorCreditsExportable extends Exportable { + constructor( + private readonly vendorCreditsApp: VendorCreditsApplicationService, + ) { + super(); + } -// /** -// * Retrieves the vendor credits data to exportable sheet. -// * @param {number} tenantId - -// * @param {IVendorCreditsQueryDTO} query - -// * @returns {} -// */ -// public exportable(tenantId: number, query: IVendorCreditsQueryDTO) { -// const filterQuery = (query) => { -// query.withGraphFetched('branch'); -// query.withGraphFetched('warehouse'); -// }; -// const parsedQuery = { -// sortOrder: 'desc', -// columnSortBy: 'created_at', -// ...query, -// page: 1, -// pageSize: 12000, -// filterQuery, -// } as IVendorCreditsQueryDTO; + /** + * Retrieves the vendor credits data to exportable sheet. + */ + public exportable(query: IVendorCreditsQueryDTO) { + const filterQuery = (query) => { + query.withGraphFetched('branch'); + query.withGraphFetched('warehouse'); + }; + const parsedQuery = { + sortOrder: 'desc', + columnSortBy: 'created_at', + ...query, + page: 1, + pageSize: 12000, + filterQuery, + } as IVendorCreditsQueryDTO; -// return this.getVendorCredits -// .getVendorCredits(tenantId, parsedQuery) -// .then((output) => output.vendorCredits); -// } -// } + return this.vendorCreditsApp + .getVendorCredits(parsedQuery) + .then((output) => output.vendorCredits); + } +} diff --git a/packages/server/src/modules/VendorCredit/models/VendorCredit.ts b/packages/server/src/modules/VendorCredit/models/VendorCredit.ts index bb6f5754d..1dfbbac29 100644 --- a/packages/server/src/modules/VendorCredit/models/VendorCredit.ts +++ b/packages/server/src/modules/VendorCredit/models/VendorCredit.ts @@ -5,7 +5,9 @@ import { Branch } from '@/modules/Branches/models/Branch.model'; import { ItemEntry } from '@/modules/TransactionItemEntry/models/ItemEntry'; import { DiscountType } from '@/common/types/Discount'; import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel'; +import { ExportableModel } from '@/modules/Export/decorators/ExportableModel.decorator'; +@ExportableModel() export class VendorCredit extends TenantBaseModel { vendorId: number; amount: number; diff --git a/packages/server/src/modules/Vendors/Vendors.module.ts b/packages/server/src/modules/Vendors/Vendors.module.ts index 456fbe87e..88cf6efa0 100644 --- a/packages/server/src/modules/Vendors/Vendors.module.ts +++ b/packages/server/src/modules/Vendors/Vendors.module.ts @@ -14,6 +14,7 @@ import { TenancyContext } from '../Tenancy/TenancyContext.service'; import { VendorsController } from './Vendors.controller'; import { GetVendorsService } from './queries/GetVendors.service'; import { DynamicListModule } from '../DynamicListing/DynamicList.module'; +import { VendorsExportable } from './VendorsExportable'; @Module({ imports: [TenancyDatabaseModule, DynamicListModule], @@ -31,6 +32,7 @@ import { DynamicListModule } from '../DynamicListing/DynamicList.module'; VendorsApplication, TransformerInjectable, TenancyContext, + VendorsExportable ], }) export class VendorsModule {} diff --git a/packages/server/src/modules/Vendors/VendorsExportable.ts b/packages/server/src/modules/Vendors/VendorsExportable.ts index 4db7de1bd..9f9913954 100644 --- a/packages/server/src/modules/Vendors/VendorsExportable.ts +++ b/packages/server/src/modules/Vendors/VendorsExportable.ts @@ -1,30 +1,34 @@ -// import { Inject, Service } from 'typedi'; -// import { IItemsFilter } from '@/interfaces'; -// import { Exportable } from '@/services/Export/Exportable'; -// import { VendorsApplication } from './VendorsApplication'; -// import { EXPORT_SIZE_LIMIT } from '@/services/Export/constants'; +import { Injectable } from '@nestjs/common'; +import { VendorsApplication } from './VendorsApplication.service'; +import { Exportable } from '../Export/Exportable'; +import { IVendorsFilter } from './types/Vendors.types'; +import { EXPORT_SIZE_LIMIT } from '../Export/constants'; +import { ExportableService } from '../Export/decorators/ExportableModel.decorator'; +import { Vendor } from './models/Vendor'; -// @Service() -// export class VendorsExportable extends Exportable { -// @Inject() -// private vendorsApplication: VendorsApplication; +@Injectable() +@ExportableService({ name: Vendor.name }) +export class VendorsExportable extends Exportable { + constructor( + private readonly vendorsApplication: VendorsApplication, + ) { + super(); + } -// /** -// * Retrieves the accounts data to exportable sheet. -// * @param {number} tenantId -// * @returns -// */ -// public exportable(tenantId: number, query: IItemsFilter) { -// const parsedQuery = { -// sortOrder: 'DESC', -// columnSortBy: 'created_at', -// ...query, -// page: 1, -// pageSize: EXPORT_SIZE_LIMIT, -// } as IItemsFilter; + /** + * Retrieves the vendors data to exportable sheet. + */ + public exportable(query: IVendorsFilter) { + const parsedQuery = { + sortOrder: 'DESC', + columnSortBy: 'created_at', + ...query, + page: 1, + pageSize: EXPORT_SIZE_LIMIT, + } as IVendorsFilter; -// return this.vendorsApplication -// .getVendors(tenantId, parsedQuery) -// .then((output) => output.vendors); -// } -// } + return this.vendorsApplication + .getVendors(parsedQuery) + .then((output) => output.vendors); + } +} diff --git a/packages/server/src/modules/Vendors/models/Vendor.ts b/packages/server/src/modules/Vendors/models/Vendor.ts index 0005a00db..194912df4 100644 --- a/packages/server/src/modules/Vendors/models/Vendor.ts +++ b/packages/server/src/modules/Vendors/models/Vendor.ts @@ -8,6 +8,7 @@ import { Model, mixin } from 'objection'; // import ModelSearchable from './ModelSearchable'; import { BaseModel } from '@/models/Model'; import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel'; +import { ExportableModel } from '@/modules/Export/decorators/ExportableModel.decorator'; // class VendorQueryBuilder extends PaginationQueryBuilder { // constructor(...args) { @@ -21,6 +22,7 @@ import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel'; // } // } +@ExportableModel() export class Vendor extends TenantBaseModel { contactService: string; contactType: string; diff --git a/packages/server/src/utils/multi-number-parse.ts b/packages/server/src/utils/multi-number-parse.ts new file mode 100644 index 000000000..72c3a291f --- /dev/null +++ b/packages/server/src/utils/multi-number-parse.ts @@ -0,0 +1,131 @@ +// @ts-nocheck +const validGrouping = (integerPart, sep) => + integerPart.split(sep).reduce((acc, group, idx) => { + if (idx > 0) { + return acc && group.length === 3; + } + + return acc && group.length; + }, true); + +export const multiNumberParse = (number: number | string, standardDecSep = '.') => { + // if it's a number already, this is going to be easy... + if (typeof number === 'number') { + return number; + } + + // check validity of parameters + if (!number || typeof number !== 'string') { + throw new TypeError('number must be a string'); + } + + if (typeof standardDecSep !== 'string' || standardDecSep.length !== 1) { + throw new TypeError('standardDecSep must be a single character string'); + } + + // check if negative + const negative = number[0] === '-'; + + // strip unnecessary chars + const stripped = number + // get rid of trailing non-numbers + .replace(/[^\d]+$/, '') + // get rid of the signal + .slice(negative ? 1 : 0); + + // analyze separators + const separators = (stripped.match(/[^\d]/g) || []).reduce( + (acc, sep, idx) => { + const sepChr = `str_${sep.codePointAt(0)}`; + const cnt = ((acc[sepChr] || {}).cnt || 0) + 1; + + return { + ...acc, + [sepChr]: { + sep, + cnt, + lastIdx: idx, + }, + }; + }, + {} + ); + + // check correctness of separators + const sepKeys = Object.keys(separators); + + if (!sepKeys.length) { + // no separator, that's easy-peasy + return parseInt(stripped, 10) * (negative ? -1 : 1); + } + + if (sepKeys.length > 2) { + // there's more than 2 separators, that's wrong + return Number.NaN; + } + + if (sepKeys.length > 1) { + // there's two separators, that's ok by now + let sep1 = separators[sepKeys[0]]; + let sep2 = separators[sepKeys[1]]; + + if (sep1.lastIdx > sep2.lastIdx) { + // swap + [sep1, sep2] = [sep2, sep1]; + } + + // if more than one separator appears more than once, that's wrong + if (sep1.cnt > 1 && sep2.cnt > 1) { + return Number.NaN; + } + + // check if the last separator is the single one + if (sep2.cnt > 1) { + return Number.NaN; + } + + // check the groupings + const [integerPart] = stripped.split(sep2.sep); + + if (!validGrouping(integerPart, sep1.sep)) { + return Number.NaN; + } + + // ok, we got here! let's handle it + return ( + parseFloat(stripped.split(sep1.sep).join('').replace(sep2.sep, '.')) * + (negative ? -1 : 1) + ); + } + + // ok, only one separator, which is nice + const sep = separators[sepKeys[0]]; + + if (sep.cnt > 1) { + // there's more than one separator, which means it's integer + // let's check the groupings + if (!validGrouping(stripped, sep.sep)) { + return Number.NaN; + } + + // it's valid, let's return an integer + return parseInt(stripped.split(sep.sep).join(''), 10) * (negative ? -1 : 1); + } + + // just one separator, let's check last group + const groups = stripped.split(sep.sep); + + if (groups[groups.length - 1].length === 3) { + // ok, we're in ambiguous territory here + + if (sep.sep !== standardDecSep) { + // it's an integer + return ( + parseInt(stripped.split(sep.sep).join(''), 10) * (negative ? -1 : 1) + ); + } + } + + // well, it looks like it's a simple float + return parseFloat(stripped.replace(sep.sep, '.')) * (negative ? -1 : 1); +}; \ No newline at end of file From e8f1fedf35aab6ca00acdf863c412a5e39aa9ed3 Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Tue, 8 Apr 2025 22:44:24 +0200 Subject: [PATCH 2/5] refactor(nestjs): exportable modules --- .../Accounts/AccountsImportable.service.ts | 80 +++++++------ .../BankingCategorize.module.ts | 2 + .../src/modules/Customers/Customers.module.ts | 4 +- .../modules/Customers/CustomersImportable.ts | 62 +++++----- .../src/modules/Expenses/Expenses.module.ts | 4 +- .../modules/Expenses/ExpensesImportable.ts | 79 ++++++------- .../ItemCategoriesImportable.ts | 64 +++++------ .../ItemCategory.application.ts | 4 +- .../ItemCategories/ItemCategory.module.ts | 2 + .../ManualJournals/ManualJournals.module.ts | 4 +- .../commands/ManualJournalsImport.ts | 107 +++++++++--------- .../PaymentsReceived.module.ts | 4 +- .../commands/PaymentsReceivedImportable.ts | 83 +++++++------- .../SaleEstimates/SaleEstimates.module.ts | 4 +- .../SaleEstimates/SaleEstimatesImportable.ts | 82 +++++++------- .../SaleReceipts/SaleReceipts.module.ts | 4 +- .../commands/SaleReceiptsImportable.ts | 81 +++++++------ .../src/modules/TaxRates/TaxRate.module.ts | 4 +- .../modules/TaxRates/TaxRatesImportable.ts | 78 ++++++------- .../src/modules/Vendors/Vendors.module.ts | 4 +- .../src/modules/Vendors/VendorsImportable.ts | 60 +++++----- 21 files changed, 408 insertions(+), 408 deletions(-) diff --git a/packages/server/src/modules/Accounts/AccountsImportable.service.ts b/packages/server/src/modules/Accounts/AccountsImportable.service.ts index 3e4a61859..84a8fcd5b 100644 --- a/packages/server/src/modules/Accounts/AccountsImportable.service.ts +++ b/packages/server/src/modules/Accounts/AccountsImportable.service.ts @@ -1,45 +1,43 @@ -// import { Inject, Service } from 'typedi'; -// import { Knex } from 'knex'; -// import { IAccountCreateDTO } from '@/interfaces'; -// import { CreateAccount } from './CreateAccount.service'; -// import { Importable } from '../Import/Importable'; -// import { AccountsSampleData } from './AccountsImportable.SampleData'; +import { Knex } from 'knex'; +import { Injectable } from '@nestjs/common'; +import { Importable } from '../Import/Importable'; +import { AccountsSampleData } from './AccountsImportable.SampleData'; +import { CreateAccountDTO } from './CreateAccount.dto'; +import { CreateAccountService } from './CreateAccount.service'; -// @Service() -// export class AccountsImportable extends Importable { -// @Inject() -// private createAccountService: CreateAccount; +@Injectable() +export class AccountsImportable extends Importable { + constructor(private readonly createAccountService: CreateAccountService) { + super(); + } -// /** -// * Importing to account service. -// * @param {number} tenantId -// * @param {IAccountCreateDTO} createAccountDTO -// * @returns -// */ -// public importable( -// tenantId: number, -// createAccountDTO: IAccountCreateDTO, -// trx?: Knex.Transaction -// ) { -// return this.createAccountService.createAccount( -// tenantId, -// createAccountDTO, -// trx -// ); -// } + /** + * Importing to account service. + * @param {CreateAccountDTO} createAccountDTO - Create account dto. + * @returns + */ + public importable( + createAccountDTO: CreateAccountDTO, + trx?: Knex.Transaction, + ) { + return this.createAccountService.createAccount( + createAccountDTO, + trx, + ); + } -// /** -// * Concurrrency controlling of the importing process. -// * @returns {number} -// */ -// public get concurrency() { -// return 1; -// } + /** + * Concurrrency controlling of the importing process. + * @returns {number} + */ + public get concurrency() { + return 1; + } -// /** -// * Retrieves the sample data that used to download accounts sample sheet. -// */ -// public sampleData(): any[] { -// return AccountsSampleData; -// } -// } + /** + * Retrieves the sample data that used to download accounts sample sheet. + */ + public sampleData(): any[] { + return AccountsSampleData; + } +} diff --git a/packages/server/src/modules/BankingCategorize/BankingCategorize.module.ts b/packages/server/src/modules/BankingCategorize/BankingCategorize.module.ts index a737b38d6..42c4cbf12 100644 --- a/packages/server/src/modules/BankingCategorize/BankingCategorize.module.ts +++ b/packages/server/src/modules/BankingCategorize/BankingCategorize.module.ts @@ -3,12 +3,14 @@ import { CreateUncategorizedTransactionService } from './commands/CreateUncatego import { CategorizeTransactionAsExpense } from './commands/CategorizeTransactionAsExpense'; import { BankingTransactionsModule } from '../BankingTransactions/BankingTransactions.module'; import { ExpensesModule } from '../Expenses/Expenses.module'; +import { UncategorizedTransactionsImportable } from './commands/UncategorizedTransactionsImportable'; @Module({ imports: [BankingTransactionsModule, ExpensesModule], providers: [ CreateUncategorizedTransactionService, CategorizeTransactionAsExpense, + UncategorizedTransactionsImportable ], exports: [ CreateUncategorizedTransactionService, diff --git a/packages/server/src/modules/Customers/Customers.module.ts b/packages/server/src/modules/Customers/Customers.module.ts index 192e68d69..7531ae9b6 100644 --- a/packages/server/src/modules/Customers/Customers.module.ts +++ b/packages/server/src/modules/Customers/Customers.module.ts @@ -13,6 +13,7 @@ import { CustomersController } from './Customers.controller'; import { CustomersApplication } from './CustomersApplication.service'; import { DeleteCustomer } from './commands/DeleteCustomer.service'; import { CustomersExportable } from './CustomersExportable'; +import { CustomersImportable } from './CustomersImportable'; @Module({ imports: [TenancyDatabaseModule], @@ -31,7 +32,8 @@ import { CustomersExportable } from './CustomersExportable'; TenancyContext, TransformerInjectable, GetCustomerService, - CustomersExportable + CustomersExportable, + CustomersImportable ], }) export class CustomersModule {} diff --git a/packages/server/src/modules/Customers/CustomersImportable.ts b/packages/server/src/modules/Customers/CustomersImportable.ts index b3a7eeb59..2996fac1b 100644 --- a/packages/server/src/modules/Customers/CustomersImportable.ts +++ b/packages/server/src/modules/Customers/CustomersImportable.ts @@ -1,34 +1,34 @@ -// import { Inject, Service } from 'typedi'; -// import { Importable } from '@/services/Import/Importable'; -// import { CreateCustomer } from './CRUD/CreateCustomer'; -// import { Knex } from 'knex'; -// import { ICustomer, ICustomerNewDTO } from '@/interfaces'; -// import { CustomersSampleData } from './_SampleData'; +import { Knex } from 'knex'; +import { CustomersSampleData } from './_SampleData'; +import { Injectable } from '@nestjs/common'; +import { Importable } from '../Import/Importable'; +import { CreateCustomer } from './commands/CreateCustomer.service'; +import { CreateCustomerDto } from './dtos/CreateCustomer.dto'; -// @Service() -// export class CustomersImportable extends Importable { -// @Inject() -// private createCustomerService: CreateCustomer; +@Injectable() +export class CustomersImportable extends Importable { + constructor(private readonly createCustomerService: CreateCustomer) { + super(); + } -// /** -// * Mapps the imported data to create a new customer service. -// * @param {number} tenantId -// * @param {ICustomerNewDTO} createDTO -// * @param {Knex.Transaction} trx -// * @returns {Promise} -// */ -// public async importable( -// tenantId: number, -// createDTO: ICustomerNewDTO, -// trx?: Knex.Transaction -// ): Promise { -// await this.createCustomerService.createCustomer(tenantId, createDTO, trx); -// } + /** + * Mapps the imported data to create a new customer service. + * @param {number} tenantId + * @param {ICustomerNewDTO} createDTO + * @param {Knex.Transaction} trx + * @returns {Promise} + */ + public async importable( + createDTO: CreateCustomerDto, + trx?: Knex.Transaction, + ): Promise { + await this.createCustomerService.createCustomer(createDTO, trx); + } -// /** -// * Retrieves the sample data of customers used to download sample sheet. -// */ -// public sampleData(): any[] { -// return CustomersSampleData; -// } -// } + /** + * Retrieves the sample data of customers used to download sample sheet. + */ + public sampleData(): any[] { + return CustomersSampleData; + } +} diff --git a/packages/server/src/modules/Expenses/Expenses.module.ts b/packages/server/src/modules/Expenses/Expenses.module.ts index 3c6cb10cd..60278857e 100644 --- a/packages/server/src/modules/Expenses/Expenses.module.ts +++ b/packages/server/src/modules/Expenses/Expenses.module.ts @@ -18,6 +18,7 @@ import { BranchesModule } from '../Branches/Branches.module'; import { GetExpensesService } from './queries/GetExpenses.service'; import { DynamicListModule } from '../DynamicListing/DynamicList.module'; import { ExpensesExportable } from './ExpensesExportable'; +import { ExpensesImportable } from './ExpensesImportable'; @Module({ imports: [LedgerModule, BranchesModule, DynamicListModule], @@ -38,7 +39,8 @@ import { ExpensesExportable } from './ExpensesExportable'; ExpenseGLEntriesStorageService, ExpenseGLEntriesService, GetExpensesService, - ExpensesExportable + ExpensesExportable, + ExpensesImportable ], }) export class ExpensesModule {} diff --git a/packages/server/src/modules/Expenses/ExpensesImportable.ts b/packages/server/src/modules/Expenses/ExpensesImportable.ts index fabacf1f4..3bc85b90f 100644 --- a/packages/server/src/modules/Expenses/ExpensesImportable.ts +++ b/packages/server/src/modules/Expenses/ExpensesImportable.ts @@ -1,46 +1,41 @@ -// import { Inject, Service } from 'typedi'; -// import { Knex } from 'knex'; -// import { IExpenseCreateDTO } from '@/interfaces'; -// import { Importable } from '../Import/Importable'; -// import { CreateExpense } from './CRUD/CreateExpense.service'; -// import { ExpensesSampleData } from './constants'; +import { Knex } from 'knex'; +import { Importable } from '../Import/Importable'; +import { ExpensesSampleData } from './constants'; +import { Injectable } from '@nestjs/common'; +import { CreateExpense } from './commands/CreateExpense.service'; +import { CreateExpenseDto } from './dtos/Expense.dto'; -// @Service() -// export class ExpensesImportable extends Importable { -// @Inject() -// private createExpenseService: CreateExpense; +@Injectable() +export class ExpensesImportable extends Importable { + constructor(private readonly createExpenseService: CreateExpense) { + super(); + } -// /** -// * Importing to account service. -// * @param {number} tenantId -// * @param {IAccountCreateDTO} createAccountDTO -// * @returns -// */ -// public importable( -// tenantId: number, -// createAccountDTO: IExpenseCreateDTO, -// trx?: Knex.Transaction -// ) { -// return this.createExpenseService.newExpense( -// tenantId, -// createAccountDTO, -// {}, -// trx -// ); -// } + /** + * Importing to account service. + * @param {number} tenantId + * @param {IAccountCreateDTO} createAccountDTO + * @returns + */ + public importable( + createAccountDTO: CreateExpenseDto, + trx?: Knex.Transaction, + ) { + return this.createExpenseService.newExpense(createAccountDTO, trx); + } -// /** -// * Concurrrency controlling of the importing process. -// * @returns {number} -// */ -// public get concurrency() { -// return 1; -// } + /** + * Concurrrency controlling of the importing process. + * @returns {number} + */ + public get concurrency() { + return 1; + } -// /** -// * Retrieves the sample data that used to download accounts sample sheet. -// */ -// public sampleData(): any[] { -// return ExpensesSampleData; -// } -// } + /** + * Retrieves the sample data that used to download accounts sample sheet. + */ + public sampleData(): any[] { + return ExpensesSampleData; + } +} diff --git a/packages/server/src/modules/ItemCategories/ItemCategoriesImportable.ts b/packages/server/src/modules/ItemCategories/ItemCategoriesImportable.ts index b1540ba72..d65c55e70 100644 --- a/packages/server/src/modules/ItemCategories/ItemCategoriesImportable.ts +++ b/packages/server/src/modules/ItemCategories/ItemCategoriesImportable.ts @@ -1,38 +1,32 @@ -// import { Inject, Service } from 'typedi'; -// import ItemCategoriesService from './ItemCategoriesService'; -// import { Importable } from '../Import/Importable'; -// import { Knex } from 'knex'; -// import { IItemCategoryOTD } from '@/interfaces'; -// import { ItemCategoriesSampleData } from './constants'; +import { Importable } from '../Import/Importable'; +import { Knex } from 'knex'; +import { ItemCategoriesSampleData } from './constants'; +import { Injectable } from '@nestjs/common'; +import { CreateItemCategoryDto } from './dtos/ItemCategory.dto'; +import { ItemCategoryApplication } from './ItemCategory.application'; -// @Service() -// export class ItemCategoriesImportable extends Importable { -// @Inject() -// private itemCategoriesService: ItemCategoriesService; +@Injectable() +export class ItemCategoriesImportable extends Importable { + constructor(private readonly itemCategoriesApp: ItemCategoryApplication) { + super(); + } -// /** -// * Importing to create new item category service. -// * @param {number} tenantId -// * @param {any} createDTO -// * @param {Knex.Transaction} trx -// */ -// public async importable( -// tenantId: number, -// createDTO: IItemCategoryOTD, -// trx?: Knex.Transaction -// ) { -// await this.itemCategoriesService.newItemCategory( -// tenantId, -// createDTO, -// {}, -// trx -// ); -// } + /** + * Importing to create new item category service. + * @param {CreateItemCategoryDto} createDTO + * @param {Knex.Transaction} trx + */ + public async importable( + createDTO: CreateItemCategoryDto, + trx?: Knex.Transaction, + ) { + await this.itemCategoriesApp.createItemCategory(createDTO, trx); + } -// /** -// * Item categories sample data used to download sample sheet file. -// */ -// public sampleData(): any[] { -// return ItemCategoriesSampleData; -// } -// } + /** + * Item categories sample data used to download sample sheet file. + */ + public sampleData(): any[] { + return ItemCategoriesSampleData; + } +} diff --git a/packages/server/src/modules/ItemCategories/ItemCategory.application.ts b/packages/server/src/modules/ItemCategories/ItemCategory.application.ts index 7bb7c6aec..09b54789d 100644 --- a/packages/server/src/modules/ItemCategories/ItemCategory.application.ts +++ b/packages/server/src/modules/ItemCategories/ItemCategory.application.ts @@ -9,6 +9,7 @@ import { EditItemCategoryService } from './commands/EditItemCategory.service'; import { GetItemCategoryService } from './queries/GetItemCategory.service'; import { GetItemCategoriesService } from './queries/GetItemCategories.service'; import { CreateItemCategoryDto, EditItemCategoryDto } from './dtos/ItemCategory.dto'; +import { Knex } from 'knex'; @Injectable() export class ItemCategoryApplication { @@ -33,8 +34,9 @@ export class ItemCategoryApplication { */ public createItemCategory( itemCategoryDTO: CreateItemCategoryDto, + trx?: Knex.Transaction, ) { - return this.createItemCategoryService.newItemCategory(itemCategoryDTO); + return this.createItemCategoryService.newItemCategory(itemCategoryDTO, trx); } /** diff --git a/packages/server/src/modules/ItemCategories/ItemCategory.module.ts b/packages/server/src/modules/ItemCategories/ItemCategory.module.ts index 233ba1506..b9919a0ee 100644 --- a/packages/server/src/modules/ItemCategories/ItemCategory.module.ts +++ b/packages/server/src/modules/ItemCategories/ItemCategory.module.ts @@ -12,6 +12,7 @@ import { TenancyContext } from '../Tenancy/TenancyContext.service'; import { GetItemCategoriesService } from './queries/GetItemCategories.service'; import { DynamicListModule } from '../DynamicListing/DynamicList.module'; import { ItemCategoriesExportable } from './ItemCategoriesExportable'; +import { ItemCategoriesImportable } from './ItemCategoriesImportable'; @Module({ imports: [TenancyDatabaseModule, DynamicListModule], @@ -27,6 +28,7 @@ import { ItemCategoriesExportable } from './ItemCategoriesExportable'; ItemCategoriesExportable, TransformerInjectable, TenancyContext, + ItemCategoriesImportable ], }) export class ItemCategoryModule {} diff --git a/packages/server/src/modules/ManualJournals/ManualJournals.module.ts b/packages/server/src/modules/ManualJournals/ManualJournals.module.ts index bf217d88e..1ca42131c 100644 --- a/packages/server/src/modules/ManualJournals/ManualJournals.module.ts +++ b/packages/server/src/modules/ManualJournals/ManualJournals.module.ts @@ -16,6 +16,7 @@ import { ManualJournalWriteGLSubscriber } from './commands/ManualJournalGLEntrie import { ManualJournalGLEntries } from './commands/ManualJournalGLEntries'; import { LedgerModule } from '../Ledger/Ledger.module'; import { ManualJournalsExportable } from './commands/ManualJournalExportable'; +import { ManualJournalImportable } from './commands/ManualJournalsImport'; @Module({ imports: [BranchesModule, LedgerModule], @@ -35,7 +36,8 @@ import { ManualJournalsExportable } from './commands/ManualJournalExportable'; GetManualJournal, ManualJournalGLEntries, ManualJournalWriteGLSubscriber, - ManualJournalsExportable + ManualJournalsExportable, + ManualJournalImportable ], }) export class ManualJournalsModule {} diff --git a/packages/server/src/modules/ManualJournals/commands/ManualJournalsImport.ts b/packages/server/src/modules/ManualJournals/commands/ManualJournalsImport.ts index 377c3b2ae..7e4ed8ff3 100644 --- a/packages/server/src/modules/ManualJournals/commands/ManualJournalsImport.ts +++ b/packages/server/src/modules/ManualJournals/commands/ManualJournalsImport.ts @@ -1,60 +1,57 @@ -// import { Inject } from 'typedi'; -// import { Knex } from 'knex'; -// import * as Yup from 'yup'; -// import { Importable } from '../../Import/Importable'; -// import { CreateManualJournalService } from './CreateManualJournal.service'; -// import { IManualJournalDTO } from '@/interfaces'; -// import { ImportableContext } from '../../Import/interfaces'; -// import { ManualJournalsSampleData } from '../constants'; +import { Knex } from 'knex'; +import * as Yup from 'yup'; +import { Importable } from '../../Import/Importable'; +import { CreateManualJournalService } from './CreateManualJournal.service'; +import { ImportableContext } from '../../Import/interfaces'; +import { ManualJournalsSampleData } from '../constants'; +import { CreateManualJournalDto } from '../dtos/ManualJournal.dto'; -// export class ManualJournalImportable extends Importable { -// @Inject() -// private createManualJournalService: CreateManualJournalService; +export class ManualJournalImportable extends Importable { + constructor( + private readonly createManualJournalService: CreateManualJournalService, + ) { + super(); + } -// /** -// * Importing to account service. -// * @param {number} tenantId -// * @param {IAccountCreateDTO} createAccountDTO -// * @returns -// */ -// public importable( -// tenantId: number, -// createJournalDTO: IManualJournalDTO, -// trx?: Knex.Transaction -// ) { -// return this.createManualJournalService.makeJournalEntries( -// tenantId, -// createJournalDTO, -// {}, -// trx -// ); -// } + /** + * Importing to account service. + * @param {CreateManualJournalDto} createAccountDTO + */ + public importable( + createJournalDTO: CreateManualJournalDto, + trx?: Knex.Transaction, + ) { + return this.createManualJournalService.makeJournalEntries( + createJournalDTO, + trx, + ); + } -// /** -// * Transformes the DTO before passing it to importable and validation. -// * @param {Record} createDTO -// * @param {ImportableContext} context -// * @returns {Record} -// */ -// public transform(createDTO: Record, context: ImportableContext) { -// return createDTO; -// } + /** + * Transformes the DTO before passing it to importable and validation. + * @param {Record} createDTO + * @param {ImportableContext} context + * @returns {Record} + */ + public transform(createDTO: Record, context: ImportableContext) { + return createDTO; + } -// /** -// * Params validation schema. -// * @returns {ValidationSchema[]} -// */ -// public paramsValidationSchema() { -// return Yup.object().shape({ -// autoIncrement: Yup.boolean(), -// }); -// } + /** + * Params validation schema. + * @returns {ValidationSchema[]} + */ + public paramsValidationSchema() { + return Yup.object().shape({ + autoIncrement: Yup.boolean(), + }); + } -// /** -// * Retrieves the sample data of manual journals that used to download sample sheet. -// * @returns {Record} -// */ -// public sampleData(): Record[] { -// return ManualJournalsSampleData; -// } -// } + /** + * Retrieves the sample data of manual journals that used to download sample sheet. + * @returns {Record} + */ + public sampleData(): Record[] { + return ManualJournalsSampleData; + } +} diff --git a/packages/server/src/modules/PaymentReceived/PaymentsReceived.module.ts b/packages/server/src/modules/PaymentReceived/PaymentsReceived.module.ts index c6292691f..45010c89e 100644 --- a/packages/server/src/modules/PaymentReceived/PaymentsReceived.module.ts +++ b/packages/server/src/modules/PaymentReceived/PaymentsReceived.module.ts @@ -35,6 +35,7 @@ import { SendPaymentReceivedMailProcessor } from './processors/PaymentReceivedMa import { BullModule } from '@nestjs/bull'; import { SEND_PAYMENT_RECEIVED_MAIL_QUEUE } from './constants'; import { PaymentsReceivedExportable } from './commands/PaymentsReceivedExportable'; +import { PaymentsReceivedImportable } from './commands/PaymentsReceivedImportable'; @Module({ controllers: [PaymentReceivesController], @@ -60,7 +61,8 @@ import { PaymentsReceivedExportable } from './commands/PaymentsReceivedExportabl GetPaymentsReceivedService, SendPaymentReceiveMailNotification, SendPaymentReceivedMailProcessor, - PaymentsReceivedExportable + PaymentsReceivedExportable, + PaymentsReceivedImportable ], exports: [ PaymentReceivesApplication, diff --git a/packages/server/src/modules/PaymentReceived/commands/PaymentsReceivedImportable.ts b/packages/server/src/modules/PaymentReceived/commands/PaymentsReceivedImportable.ts index 2b220af3d..d215273fc 100644 --- a/packages/server/src/modules/PaymentReceived/commands/PaymentsReceivedImportable.ts +++ b/packages/server/src/modules/PaymentReceived/commands/PaymentsReceivedImportable.ts @@ -1,46 +1,45 @@ -// import { Inject, Service } from 'typedi'; -// import { Knex } from 'knex'; -// import { IPaymentReceivedCreateDTO } from '@/interfaces'; -// import { Importable } from '@/services/Import/Importable'; -// import { CreatePaymentReceived } from './commands/CreatePaymentReceived.serivce'; -// import { PaymentsReceiveSampleData } from './constants'; +import { Knex } from 'knex'; +import { CreatePaymentReceivedDto } from '../dtos/PaymentReceived.dto'; +import { Injectable } from '@nestjs/common'; +import { PaymentsReceiveSampleData } from '../constants'; +import { CreatePaymentReceivedService } from './CreatePaymentReceived.serivce'; +import { Importable } from '@/modules/Import/Importable'; -// @Service() -// export class PaymentsReceivedImportable extends Importable { -// @Inject() -// private createPaymentReceiveService: CreatePaymentReceived; +@Injectable() +export class PaymentsReceivedImportable extends Importable { + constructor( + private readonly createPaymentReceiveService: CreatePaymentReceivedService, + ) { + super(); + } -// /** -// * Importing to account service. -// * @param {number} tenantId -// * @param {IAccountCreateDTO} createAccountDTO -// * @returns -// */ -// public importable( -// tenantId: number, -// createPaymentDTO: IPaymentReceivedCreateDTO, -// trx?: Knex.Transaction -// ) { -// return this.createPaymentReceiveService.createPaymentReceived( -// tenantId, -// createPaymentDTO, -// {}, -// trx -// ); -// } + /** + * Importing to account service. + * @param {CreatePaymentReceivedDto} createAccountDTO + * @returns + */ + public importable( + createPaymentDTO: CreatePaymentReceivedDto, + trx?: Knex.Transaction, + ) { + return this.createPaymentReceiveService.createPaymentReceived( + createPaymentDTO, + trx, + ); + } -// /** -// * Concurrrency controlling of the importing process. -// * @returns {number} -// */ -// public get concurrency() { -// return 1; -// } + /** + * Concurrrency controlling of the importing process. + * @returns {number} + */ + public get concurrency() { + return 1; + } -// /** -// * Retrieves the sample data that used to download accounts sample sheet. -// */ -// public sampleData(): any[] { -// return PaymentsReceiveSampleData; -// } -// } + /** + * Retrieves the sample data that used to download accounts sample sheet. + */ + public sampleData(): any[] { + return PaymentsReceiveSampleData; + } +} diff --git a/packages/server/src/modules/SaleEstimates/SaleEstimates.module.ts b/packages/server/src/modules/SaleEstimates/SaleEstimates.module.ts index d310869ae..43184d0f4 100644 --- a/packages/server/src/modules/SaleEstimates/SaleEstimates.module.ts +++ b/packages/server/src/modules/SaleEstimates/SaleEstimates.module.ts @@ -36,6 +36,7 @@ import { SaleEstimatePdfTemplate } from '../SaleInvoices/queries/SaleEstimatePdf import { PdfTemplatesModule } from '../PdfTemplate/PdfTemplates.module'; import { SendSaleEstimateMailQueue } from './types/SaleEstimates.types'; import { SaleEstimatesExportable } from './SaleEstimatesExportable'; +import { SaleEstimatesImportable } from './SaleEstimatesImportable'; @Module({ imports: [ @@ -76,7 +77,8 @@ import { SaleEstimatesExportable } from './SaleEstimatesExportable'; SendSaleEstimateMail, GetSaleEstimatePdf, SaleEstimatePdfTemplate, - SaleEstimatesExportable + SaleEstimatesExportable, + SaleEstimatesImportable ], }) export class SaleEstimatesModule {} diff --git a/packages/server/src/modules/SaleEstimates/SaleEstimatesImportable.ts b/packages/server/src/modules/SaleEstimates/SaleEstimatesImportable.ts index d5ed0b6c9..2ba4fca79 100644 --- a/packages/server/src/modules/SaleEstimates/SaleEstimatesImportable.ts +++ b/packages/server/src/modules/SaleEstimates/SaleEstimatesImportable.ts @@ -1,45 +1,45 @@ -// import { Inject, Service } from 'typedi'; -// import { Knex } from 'knex'; -// import { ISaleEstimateDTO } from '@/interfaces'; -// import { CreateSaleEstimate } from './commands/CreateSaleEstimate.service'; -// import { Importable } from '@/services/Import/Importable'; -// import { SaleEstimatesSampleData } from './constants'; +import { Knex } from 'knex'; +import { CreateSaleEstimate } from './commands/CreateSaleEstimate.service'; +import { SaleEstimatesSampleData } from './constants'; +import { Injectable } from '@nestjs/common'; +import { CreateSaleEstimateDto } from './dtos/SaleEstimate.dto'; +import { Importable } from '../Import/Importable'; -// @Service() -// export class SaleEstimatesImportable extends Importable { -// @Inject() -// private createEstimateService: CreateSaleEstimate; +@Injectable() +export class SaleEstimatesImportable extends Importable{ + constructor( + private readonly createEstimateService: CreateSaleEstimate + ) { + super(); + } -// /** -// * Importing to account service. -// * @param {number} tenantId -// * @param {IAccountCreateDTO} createAccountDTO -// * @returns -// */ -// public importable( -// tenantId: number, -// createEstimateDTO: ISaleEstimateDTO, -// trx?: Knex.Transaction -// ) { -// return this.createEstimateService.createEstimate( -// tenantId, -// createEstimateDTO, -// trx -// ); -// } + /** + * Importing to account service. + * @param {CreateSaleEstimateDto} createAccountDTO + * @returns + */ + public importable( + createEstimateDTO: CreateSaleEstimateDto, + trx?: Knex.Transaction + ) { + return this.createEstimateService.createEstimate( + createEstimateDTO, + trx + ); + } -// /** -// * Concurrrency controlling of the importing process. -// * @returns {number} -// */ -// public get concurrency() { -// return 1; -// } + /** + * Concurrrency controlling of the importing process. + * @returns {number} + */ + public get concurrency() { + return 1; + } -// /** -// * Retrieves the sample data that used to download accounts sample sheet. -// */ -// public sampleData(): any[] { -// return SaleEstimatesSampleData; -// } -// } + /** + * Retrieves the sample data that used to download accounts sample sheet. + */ + public sampleData(): any[] { + return SaleEstimatesSampleData; + } +} diff --git a/packages/server/src/modules/SaleReceipts/SaleReceipts.module.ts b/packages/server/src/modules/SaleReceipts/SaleReceipts.module.ts index bda6a185c..ceaf6e0a4 100644 --- a/packages/server/src/modules/SaleReceipts/SaleReceipts.module.ts +++ b/packages/server/src/modules/SaleReceipts/SaleReceipts.module.ts @@ -36,6 +36,7 @@ import { SendSaleReceiptMailProcess } from './processes/SendSaleReceiptMail.proc import { MailModule } from '../Mail/Mail.module'; import { SendSaleReceiptMailQueue } from './constants'; import { SaleReceiptsExportable } from './commands/SaleReceiptsExportable'; +import { SaleReceiptsImportable } from './commands/SaleReceiptsImportable'; @Module({ controllers: [SaleReceiptsController], @@ -76,7 +77,8 @@ import { SaleReceiptsExportable } from './commands/SaleReceiptsExportable'; SaleReceiptInventoryTransactions, SaleReceiptInventoryTransactionsSubscriber, SendSaleReceiptMailProcess, - SaleReceiptsExportable + SaleReceiptsExportable, + SaleReceiptsImportable, ], }) export class SaleReceiptsModule {} diff --git a/packages/server/src/modules/SaleReceipts/commands/SaleReceiptsImportable.ts b/packages/server/src/modules/SaleReceipts/commands/SaleReceiptsImportable.ts index 601f96a3f..0b3674d8a 100644 --- a/packages/server/src/modules/SaleReceipts/commands/SaleReceiptsImportable.ts +++ b/packages/server/src/modules/SaleReceipts/commands/SaleReceiptsImportable.ts @@ -1,45 +1,44 @@ -// import { Inject, Service } from 'typedi'; -// import { Knex } from 'knex'; -// import { IAccountCreateDTO, ISaleReceiptDTO } from '@/interfaces'; -// import { CreateSaleReceipt } from './commands/CreateSaleReceipt.service'; -// import { Importable } from '@/services/Import/Importable'; -// import { SaleReceiptsSampleData } from './constants'; +import { Injectable } from '@nestjs/common'; +import { Knex } from 'knex'; +import { CreateSaleReceipt } from './CreateSaleReceipt.service'; +import { Importable } from '@/modules/Import/Importable'; +import { CreateSaleReceiptDto } from '../dtos/SaleReceipt.dto'; +import { SaleReceiptsSampleData } from '../constants'; -// @Service() -// export class SaleReceiptsImportable extends Importable { -// @Inject() -// private createReceiptService: CreateSaleReceipt; +@Injectable() +export class SaleReceiptsImportable extends Importable { + constructor(private readonly createReceiptService: CreateSaleReceipt) { + super(); + } -// /** -// * Importing to sale receipts service. -// * @param {number} tenantId -// * @param {IAccountCreateDTO} createAccountDTO -// * @returns -// */ -// public importable( -// tenantId: number, -// createAccountDTO: ISaleReceiptDTO, -// trx?: Knex.Transaction -// ) { -// return this.createReceiptService.createSaleReceipt( -// tenantId, -// createAccountDTO, -// trx -// ); -// } + /** + * Importing to sale receipts service. + * @param {number} tenantId + * @param {IAccountCreateDTO} createAccountDTO + * @returns + */ + public importable( + createAccountDTO: CreateSaleReceiptDto, + trx?: Knex.Transaction, + ) { + return this.createReceiptService.createSaleReceipt( + createAccountDTO, + trx, + ); + } -// /** -// * Concurrrency controlling of the importing process. -// * @returns {number} -// */ -// public get concurrency() { -// return 1; -// } + /** + * Concurrrency controlling of the importing process. + * @returns {number} + */ + public get concurrency() { + return 1; + } -// /** -// * Retrieves the sample data that used to download accounts sample sheet. -// */ -// public sampleData(): any[] { -// return SaleReceiptsSampleData; -// } -// } + /** + * Retrieves the sample data that used to download accounts sample sheet. + */ + public sampleData(): any[] { + return SaleReceiptsSampleData; + } +} diff --git a/packages/server/src/modules/TaxRates/TaxRate.module.ts b/packages/server/src/modules/TaxRates/TaxRate.module.ts index 38f886255..e14da028f 100644 --- a/packages/server/src/modules/TaxRates/TaxRate.module.ts +++ b/packages/server/src/modules/TaxRates/TaxRate.module.ts @@ -22,6 +22,7 @@ import { SyncItemTaxRateOnEditTaxRate } from './SyncItemTaxRateOnEditTaxRate'; import { RegisterTenancyModel } from '../Tenancy/TenancyModels/Tenancy.module'; import { TaxRateTransaction } from './models/TaxRateTransaction.model'; import { TaxRatesExportable } from './TaxRatesExportable'; +import { TaxRatesImportable } from './TaxRatesImportable'; const models = [RegisterTenancyModel(TaxRateTransaction)]; @@ -48,7 +49,8 @@ const models = [RegisterTenancyModel(TaxRateTransaction)]; SyncItemTaxRateOnEditTaxSubscriber, WriteTaxTransactionsItemEntries, SyncItemTaxRateOnEditTaxRate, - TaxRatesExportable + TaxRatesExportable, + TaxRatesImportable ], exports: [ItemEntriesTaxTransactions, ...models], }) diff --git a/packages/server/src/modules/TaxRates/TaxRatesImportable.ts b/packages/server/src/modules/TaxRates/TaxRatesImportable.ts index eebb3c7c0..b54ec7749 100644 --- a/packages/server/src/modules/TaxRates/TaxRatesImportable.ts +++ b/packages/server/src/modules/TaxRates/TaxRatesImportable.ts @@ -1,46 +1,40 @@ -// import { Inject, Service } from 'typedi'; -// import { Knex } from 'knex'; -// import { ICreateTaxRateDTO } from '@/interfaces'; -// import { CreateTaxRate } from './commands/CreateTaxRate.service'; -// import { Importable } from '../Import/Importable'; -// import { TaxRatesSampleData } from './TaxRatesImportable.SampleData'; +import { Knex } from 'knex'; +import { CreateTaxRate } from './commands/CreateTaxRate.service'; +import { Importable } from '../Import/Importable'; +import { TaxRatesSampleData } from './TaxRatesImportable.SampleData'; +import { CreateTaxRateDto } from './dtos/TaxRate.dto'; +import { Injectable } from '@nestjs/common'; -// @Service() -// export class TaxRatesImportable extends Importable { -// @Inject() -// private createTaxRateService: CreateTaxRate; +@Injectable() +export class TaxRatesImportable extends Importable { + constructor(private readonly createTaxRateService: CreateTaxRate) { + super(); + } -// /** -// * Importing to tax rate creating service. -// * @param {number} tenantId - -// * @param {ICreateTaxRateDTO} ICreateTaxRateDTO - -// * @param {Knex.Transaction} trx - -// * @returns -// */ -// public importable( -// tenantId: number, -// createAccountDTO: ICreateTaxRateDTO, -// trx?: Knex.Transaction -// ) { -// return this.createTaxRateService.createTaxRate( -// tenantId, -// createAccountDTO, -// trx -// ); -// } + /** + * Importing to tax rate creating service. + * @param {CreateTaxRateDto} ICreateTaxRateDTO - + * @param {Knex.Transaction} trx - + */ + public importable( + createAccountDTO: CreateTaxRateDto, + trx?: Knex.Transaction, + ) { + return this.createTaxRateService.createTaxRate(createAccountDTO, trx); + } -// /** -// * Concurrrency controlling of the importing process. -// * @returns {number} -// */ -// public get concurrency() { -// return 1; -// } + /** + * Concurrrency controlling of the importing process. + * @returns {number} + */ + public get concurrency() { + return 1; + } -// /** -// * Retrieves the sample data that used to download accounts sample sheet. -// */ -// public sampleData(): any[] { -// return TaxRatesSampleData; -// } -// } + /** + * Retrieves the sample data that used to download accounts sample sheet. + */ + public sampleData(): any[] { + return TaxRatesSampleData; + } +} diff --git a/packages/server/src/modules/Vendors/Vendors.module.ts b/packages/server/src/modules/Vendors/Vendors.module.ts index 88cf6efa0..b014f8535 100644 --- a/packages/server/src/modules/Vendors/Vendors.module.ts +++ b/packages/server/src/modules/Vendors/Vendors.module.ts @@ -15,6 +15,7 @@ import { VendorsController } from './Vendors.controller'; import { GetVendorsService } from './queries/GetVendors.service'; import { DynamicListModule } from '../DynamicListing/DynamicList.module'; import { VendorsExportable } from './VendorsExportable'; +import { VendorsImportable } from './VendorsImportable'; @Module({ imports: [TenancyDatabaseModule, DynamicListModule], @@ -32,7 +33,8 @@ import { VendorsExportable } from './VendorsExportable'; VendorsApplication, TransformerInjectable, TenancyContext, - VendorsExportable + VendorsExportable, + VendorsImportable ], }) export class VendorsModule {} diff --git a/packages/server/src/modules/Vendors/VendorsImportable.ts b/packages/server/src/modules/Vendors/VendorsImportable.ts index 5836bb1c2..e8d31ba06 100644 --- a/packages/server/src/modules/Vendors/VendorsImportable.ts +++ b/packages/server/src/modules/Vendors/VendorsImportable.ts @@ -1,32 +1,34 @@ -// import { Importable } from '@/services/Import/Importable'; -// import { CreateVendor } from './CRUD/CreateVendor.service'; -// import { Knex } from 'knex'; -// import { Inject, Service } from 'typedi'; -// import { VendorsSampleData } from './_SampleData'; +import { Knex } from 'knex'; +import { VendorsSampleData } from './_SampleData'; +import { Injectable } from '@nestjs/common'; +import { Importable } from '../Import/Importable'; +import { CreateVendorService } from './commands/CreateVendor.service'; +import { CreateVendorDto } from './dtos/CreateVendor.dto'; -// @Service() -// export class VendorsImportable extends Importable { -// @Inject() -// private createVendorService: CreateVendor; +@Injectable() +export class VendorsImportable extends Importable { + constructor( + private readonly createVendorService: CreateVendorService, + ) { + super(); + } -// /** -// * Maps the imported data to create a new vendor service. -// * @param {number} tenantId -// * @param {} createDTO -// * @param {Knex.Transaction} trx -// */ -// public async importable( -// tenantId: number, -// createDTO: any, -// trx?: Knex.Transaction -// ): Promise { -// await this.createVendorService.createVendor(tenantId, createDTO, trx); -// } + /** + * Maps the imported data to create a new vendor service. + * @param {CreateVendorDto} createDTO + * @param {Knex.Transaction} trx + */ + public async importable( + createDTO: CreateVendorDto, + trx?: Knex.Transaction + ): Promise { + await this.createVendorService.createVendor(createDTO, trx); + } -// /** -// * Retrieves the sample data of vendors sample sheet. -// */ -// public sampleData(): any[] { -// return VendorsSampleData; -// } -// } + /** + * Retrieves the sample data of vendors sample sheet. + */ + public sampleData(): any[] { + return VendorsSampleData; + } +} From d851e5b646e7f2f3287fa7bb4d7088cb63b325cd Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Wed, 9 Apr 2025 10:39:08 +0200 Subject: [PATCH 3/5] refactor(nestjs): import module --- packages/server/src/interfaces/Model.ts | 1 + .../BillPaymentsApplication.service.ts | 4 +- .../queries/BillPaymentsExportable.ts | 2 +- .../modules/Bills/commands/BillsImportable.ts | 84 +++++++++---------- .../server/src/modules/Export/ExportAls.ts | 2 +- .../src/modules/Export/ExportService.ts | 7 +- .../src/modules/Import/Import.module.ts | 28 ++++++- .../src/modules/Import/ImportFileCommon.ts | 8 +- .../src/modules/Import/ImportFileMapping.ts | 19 +++-- .../src/modules/Import/ImportFileMeta.ts | 21 +++-- .../src/modules/Import/ImportFilePreview.ts | 10 ++- .../src/modules/Import/ImportFileProcess.ts | 51 +++++------ .../modules/Import/ImportFileProcessCommit.ts | 16 ++-- .../src/modules/Import/ImportFileUpload.ts | 29 +++---- .../Import/ImportRemoveExpiredFiles.ts | 22 ++--- packages/server/src/modules/Import/_utils.ts | 1 + .../server/src/modules/Import/interfaces.ts | 10 ++- .../src/modules/Import/models/Import.ts | 10 +-- 18 files changed, 192 insertions(+), 133 deletions(-) diff --git a/packages/server/src/interfaces/Model.ts b/packages/server/src/interfaces/Model.ts index 3230dddb3..4746f1fbd 100644 --- a/packages/server/src/interfaces/Model.ts +++ b/packages/server/src/interfaces/Model.ts @@ -164,6 +164,7 @@ export interface IModelMetaRelationField2 { } export type IModelMetaField2 = IModelMetaFieldCommon2 & + IModelMetaFieldWithFields & ( | IModelMetaFieldText | IModelMetaFieldNumber diff --git a/packages/server/src/modules/BillPayments/BillPaymentsApplication.service.ts b/packages/server/src/modules/BillPayments/BillPaymentsApplication.service.ts index 29a551ad2..0d8f50bae 100644 --- a/packages/server/src/modules/BillPayments/BillPaymentsApplication.service.ts +++ b/packages/server/src/modules/BillPayments/BillPaymentsApplication.service.ts @@ -59,8 +59,8 @@ export class BillPaymentsApplication { /** * Retrieves bill payments list. */ - public getBillPayments(filterDTO: IBillPaymentsFilter) { - return this.getBillPaymentsService.getBillPayments(filterDTO); + public getBillPayments() { + // return this.getBillPaymentsService.getBillPayments(filterDTO); } /** diff --git a/packages/server/src/modules/BillPayments/queries/BillPaymentsExportable.ts b/packages/server/src/modules/BillPayments/queries/BillPaymentsExportable.ts index 970730b75..cdf1ec3cb 100644 --- a/packages/server/src/modules/BillPayments/queries/BillPaymentsExportable.ts +++ b/packages/server/src/modules/BillPayments/queries/BillPaymentsExportable.ts @@ -19,7 +19,7 @@ export class BillPaymentsExportable extends Exportable { * @param {number} tenantId * @returns */ - public exportable(query: any) { + public async exportable(query: any) { const filterQuery = (builder) => { builder.withGraphFetched('entries.bill'); builder.withGraphFetched('branch'); diff --git a/packages/server/src/modules/Bills/commands/BillsImportable.ts b/packages/server/src/modules/Bills/commands/BillsImportable.ts index 5eb138b50..f9d172a28 100644 --- a/packages/server/src/modules/Bills/commands/BillsImportable.ts +++ b/packages/server/src/modules/Bills/commands/BillsImportable.ts @@ -1,46 +1,46 @@ -// import { Inject, Service } from 'typedi'; -// import { Knex } from 'knex'; -// import { Importable } from '@/services/Import/Importable'; -// import { CreateBill } from './CreateBill.service'; -// import { IBillDTO } from '@/interfaces'; -// import { BillsSampleData } from '../Bills.constants'; +import { Knex } from 'knex'; +import { CreateBill } from './CreateBill.service'; +import { BillsSampleData } from '../Bills.constants'; +import { Injectable } from '@nestjs/common'; +import { Importable } from '@/modules/Import/Importable'; +import { CreateBillDto } from '../dtos/Bill.dto'; -// @Service() -// export class BillsImportable extends Importable { -// @Inject() -// private createBillService: CreateBill; +@Injectable() +export class BillsImportable extends Importable { + constructor( + private readonly createBillService: CreateBill, + ) { + super(); + } -// /** -// * Importing to account service. -// * @param {number} tenantId -// * @param {IAccountCreateDTO} createAccountDTO -// * @returns -// */ -// public importable( -// tenantId: number, -// createAccountDTO: IBillDTO, -// trx?: Knex.Transaction -// ) { -// return this.createBillService.createBill( -// tenantId, -// createAccountDTO, -// {}, -// trx -// ); -// } + /** + * Importing to account service. + * @param {number} tenantId + * @param {IAccountCreateDTO} createAccountDTO + * @returns + */ + public importable( + createBillDto: CreateBillDto, + trx?: Knex.Transaction + ) { + return this.createBillService.createBill( + createBillDto, + trx + ); + } -// /** -// * Concurrrency controlling of the importing process. -// * @returns {number} -// */ -// public get concurrency() { -// return 1; -// } + /** + * Concurrrency controlling of the importing process. + * @returns {number} + */ + public get concurrency() { + return 1; + } -// /** -// * Retrieves the sample data that used to download accounts sample sheet. -// */ -// public sampleData(): any[] { -// return BillsSampleData; -// } -// } + /** + * Retrieves the sample data that used to download accounts sample sheet. + */ + public sampleData(): any[] { + return BillsSampleData; + } +} diff --git a/packages/server/src/modules/Export/ExportAls.ts b/packages/server/src/modules/Export/ExportAls.ts index eb940a3a2..ecc027f95 100644 --- a/packages/server/src/modules/Export/ExportAls.ts +++ b/packages/server/src/modules/Export/ExportAls.ts @@ -15,7 +15,7 @@ export class ExportAls { * @returns The result of the callback function. */ public run(callback: () => T): T { - return this.als.run(new Map(), () => { + return this.als.run(new Map(), () => { this.markAsExport(); return callback(); diff --git a/packages/server/src/modules/Export/ExportService.ts b/packages/server/src/modules/Export/ExportService.ts index a7b659172..0dc465d28 100644 --- a/packages/server/src/modules/Export/ExportService.ts +++ b/packages/server/src/modules/Export/ExportService.ts @@ -1,16 +1,15 @@ -// @ts-nocheck +import { Injectable } from '@nestjs/common'; import xlsx from 'xlsx'; import * as R from 'ramda'; import { get } from 'lodash'; import { sanitizeResourceName } from '../Import/_utils'; import { ExportableResources } from './ExportResources'; -import { ServiceError } from '@/exceptions'; import { Errors, ExportFormat } from './common'; -import { IModelMeta, IModelMetaColumn } from '@/interfaces'; import { flatDataCollections, getDataAccessor } from './utils'; import { ExportPdf } from './ExportPdf'; import { ExportAls } from './ExportAls'; -import { Injectable } from '@nestjs/common'; +import { IModelMeta, IModelMetaColumn } from '@/interfaces/Model'; +import { ServiceError } from '../Items/ServiceError'; @Injectable() export class ExportResourceService { diff --git a/packages/server/src/modules/Import/Import.module.ts b/packages/server/src/modules/Import/Import.module.ts index 6e007f702..953f6ce4f 100644 --- a/packages/server/src/modules/Import/Import.module.ts +++ b/packages/server/src/modules/Import/Import.module.ts @@ -1,8 +1,34 @@ import { Module } from '@nestjs/common'; import { ImportAls } from './ImportALS'; +import { ImportSampleService } from './ImportSample'; +import { ImportResourceApplication } from './ImportResourceApplication'; +import { ImportDeleteExpiredFiles } from './ImportRemoveExpiredFiles'; +import { ImportFileUploadService } from './ImportFileUpload'; +import { ImportFileProcessCommit } from './ImportFileProcessCommit'; +import { ImportFileProcess } from './ImportFileProcess'; +import { ImportFilePreview } from './ImportFilePreview'; +import { ImportFileMeta } from './ImportFileMeta'; +import { ImportFileMapping } from './ImportFileMapping'; +import { ImportFileDataValidator } from './ImportFileDataValidator'; +import { ImportFileDataTransformer } from './ImportFileDataTransformer'; +import { ImportFileCommon } from './ImportFileCommon'; @Module({ - providers: [ImportAls], + providers: [ + ImportAls, + ImportSampleService, + ImportResourceApplication, + ImportDeleteExpiredFiles, + ImportFileUploadService, + ImportFileProcessCommit, + ImportFileProcess, + ImportFilePreview, + ImportFileMeta, + ImportFileMapping, + ImportFileDataValidator, + ImportFileDataTransformer, + ImportFileCommon + ], exports: [ImportAls], }) export class ImportModule {} diff --git a/packages/server/src/modules/Import/ImportFileCommon.ts b/packages/server/src/modules/Import/ImportFileCommon.ts index 6e0ebe6b2..7423ab771 100644 --- a/packages/server/src/modules/Import/ImportFileCommon.ts +++ b/packages/server/src/modules/Import/ImportFileCommon.ts @@ -12,9 +12,9 @@ import { import { getUniqueImportableValue, trimObject } from './_utils'; import { ImportableResources } from './ImportableResources'; import { ResourceService } from '../Resource/ResourceService'; -import { Import } from '@/system/models'; import { Injectable } from '@nestjs/common'; import { ServiceError } from '../Items/ServiceError'; +import { ImportModelShape } from './models/Import'; @Injectable() export class ImportFileCommon { @@ -32,7 +32,7 @@ export class ImportFileCommon { * @returns {Promise<[ImportOperSuccess[], ImportOperError[]]>} */ public async import( - importFile: Import, + importFile: ImportModelShape, parsedData: Record[], trx?: Knex.Transaction, ): Promise<[ImportOperSuccess[], ImportOperError[]]> { @@ -68,7 +68,6 @@ export class ImportFileCommon { try { // Run the importable function and listen to the errors. const data = await importable.importable( - tenantId, transformedDTO, trx, ); @@ -135,14 +134,13 @@ export class ImportFileCommon { * @param {Record} params */ public async validateParams( - tenantId: number, resourceName: string, params: Record, ) { const ImportableRegistry = this.importable.registry; const importable = ImportableRegistry.getImportable(resourceName); - await importable.validateParams(tenantId, params); + await importable.validateParams(params); } /** diff --git a/packages/server/src/modules/Import/ImportFileMapping.ts b/packages/server/src/modules/Import/ImportFileMapping.ts index c4edc856c..da97bdcdb 100644 --- a/packages/server/src/modules/Import/ImportFileMapping.ts +++ b/packages/server/src/modules/Import/ImportFileMapping.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@nestjs/common'; +import { Inject, Injectable } from '@nestjs/common'; import { fromPairs, isUndefined } from 'lodash'; import { ImportDateFormats, @@ -8,15 +8,19 @@ import { import { ResourceService } from '../Resource/ResourceService'; import { ServiceError } from '../Items/ServiceError'; import { ERRORS } from './_utils'; -import { Import } from './models/Import'; +import { ImportModel } from './models/Import'; @Injectable() export class ImportFileMapping { - constructor(private readonly resource: ResourceService) {} + constructor( + private readonly resource: ResourceService, + + @Inject(ImportModel.name) + private readonly importModel: () => typeof ImportModel, + ) {} /** * Mapping the excel sheet columns with resource columns. - * @param {number} tenantId * @param {number} importId * @param {ImportMappingAttr} maps */ @@ -24,7 +28,8 @@ export class ImportFileMapping { importId: string, maps: ImportMappingAttr[], ): Promise { - const importFile = await Import.query() + const importFile = await this.importModel() + .query() .findOne('filename', importId) .throwIfNotFound(); @@ -41,7 +46,7 @@ export class ImportFileMapping { const mappingStringified = JSON.stringify(maps); - await Import.query().findById(importFile.id).patch({ + await this.importModel().query().findById(importFile.id).patch({ mapping: mappingStringified, }); return { @@ -54,7 +59,6 @@ export class ImportFileMapping { /** * Validate the mapping attributes. - * @param {number} tenantId - * @param {} importFile - * @param {ImportMappingAttr[]} maps * @throws {ServiceError(ERRORS.INVALID_MAP_ATTRS)} @@ -116,7 +120,6 @@ export class ImportFileMapping { /** * Validates the date format mapping. - * @param {number} tenantId * @param {string} resource * @param {ImportMappingAttr[]} maps */ diff --git a/packages/server/src/modules/Import/ImportFileMeta.ts b/packages/server/src/modules/Import/ImportFileMeta.ts index 462721753..e92cac775 100644 --- a/packages/server/src/modules/Import/ImportFileMeta.ts +++ b/packages/server/src/modules/Import/ImportFileMeta.ts @@ -1,20 +1,29 @@ -import { Import } from './models/Import'; +import { ImportModel } from './models/Import'; import { ImportFileMetaTransformer } from './ImportFileMetaTransformer'; -import { Injectable } from '@nestjs/common'; +import { Inject, Injectable } from '@nestjs/common'; import { TransformerInjectable } from '../Transformer/TransformerInjectable.service'; +import { TenancyContext } from '../Tenancy/TenancyContext.service'; @Injectable() export class ImportFileMeta { - constructor(private readonly transformer: TransformerInjectable) {} + constructor( + private readonly transformer: TransformerInjectable, + private readonly tenancyContext: TenancyContext, + + @Inject(ImportModel.name) + private readonly importModel: () => typeof ImportModel, + ) {} /** * Retrieves the import meta of the given import model id. - * @param {number} tenantId * @param {number} importId - * @returns {} */ async getImportMeta(importId: string) { - const importFile = await Import.query() + const tenant = await this.tenancyContext.getTenant(); + const tenantId = tenant.id; + + const importFile = await this.importModel() + .query() .where('tenantId', tenantId) .findOne('importId', importId); diff --git a/packages/server/src/modules/Import/ImportFilePreview.ts b/packages/server/src/modules/Import/ImportFilePreview.ts index 3dcd788f3..345c74ff5 100644 --- a/packages/server/src/modules/Import/ImportFilePreview.ts +++ b/packages/server/src/modules/Import/ImportFilePreview.ts @@ -1,13 +1,18 @@ +import { Knex } from 'knex'; +import { Inject, Injectable } from '@nestjs/common'; import { ImportFilePreviewPOJO } from './interfaces'; import { ImportFileProcess } from './ImportFileProcess'; import { ImportAls } from './ImportALS'; -import { Injectable } from '@nestjs/common'; +import { TENANCY_DB_CONNECTION } from '../Tenancy/TenancyDB/TenancyDB.constants'; @Injectable() export class ImportFilePreview { constructor( private readonly importFile: ImportFileProcess, private readonly importAls: ImportAls, + + @Inject(TENANCY_DB_CONNECTION) + private readonly tenantKnex: () => Knex ) {} /** @@ -27,8 +32,7 @@ export class ImportFilePreview { * @returns {Promise} */ public async previewAlsRun(importId: string): Promise { - const knex = this.tenancy.knex(tenantId); - const trx = await knex.transaction({ isolationLevel: 'read uncommitted' }); + const trx = await this.tenantKnex().transaction({ isolationLevel: 'read uncommitted' }); const meta = await this.importFile.import(importId, trx); diff --git a/packages/server/src/modules/Import/ImportFileProcess.ts b/packages/server/src/modules/Import/ImportFileProcess.ts index eda670be8..736247405 100644 --- a/packages/server/src/modules/Import/ImportFileProcess.ts +++ b/packages/server/src/modules/Import/ImportFileProcess.ts @@ -1,14 +1,16 @@ import { chain } from 'lodash'; import { Knex } from 'knex'; +import { Inject, Injectable } from '@nestjs/common'; import { ERRORS, getUnmappedSheetColumns, readImportFile } from './_utils'; import { ImportFileCommon } from './ImportFileCommon'; import { ImportFileDataTransformer } from './ImportFileDataTransformer'; import { ImportFilePreviewPOJO } from './interfaces'; import { parseSheetData } from './sheet_utils'; -import { Injectable } from '@nestjs/common'; import { ResourceService } from '../Resource/ResourceService'; import { UnitOfWork } from '../Tenancy/TenancyDB/UnitOfWork.service'; import { ServiceError } from '../Items/ServiceError'; +import { ImportModel } from './models/Import'; +import { TenancyContext } from '../Tenancy/TenancyContext.service'; @Injectable() export class ImportFileProcess { @@ -17,6 +19,10 @@ export class ImportFileProcess { private readonly importCommon: ImportFileCommon, private readonly importParser: ImportFileDataTransformer, private readonly uow: UnitOfWork, + private readonly tenancyContext: TenancyContext, + + @Inject(ImportModel.name) + private readonly importModel: typeof ImportModel, ) {} /** @@ -29,7 +35,11 @@ export class ImportFileProcess { importId: string, trx?: Knex.Transaction, ): Promise { - const importFile = await Import.query() + const tenant = await this.tenancyContext.getTenant(); + const tenantId = tenant.id; + + const importFile = await this.importModel + .query() .findOne('importId', importId) .where('tenantId', tenantId) .throwIfNotFound(); @@ -48,28 +58,21 @@ export class ImportFileProcess { // Runs the importing operation with ability to return errors that will happen. const [successedImport, failedImport, allData] = - await this.uow.withTransaction( - tenantId, - async (trx: Knex.Transaction) => { - // Prases the sheet json data. - const parsedData = await this.importParser.parseSheetData( - tenantId, - importFile, - resourceFields, - sheetData, - trx, - ); - const [successedImport, failedImport] = - await this.importCommon.import( - tenantId, - importFile, - parsedData, - trx, - ); - return [successedImport, failedImport, parsedData]; - }, - trx, - ); + await this.uow.withTransaction(async (trx: Knex.Transaction) => { + // Prases the sheet json data. + const parsedData = await this.importParser.parseSheetData( + importFile, + resourceFields, + sheetData, + trx, + ); + const [successedImport, failedImport] = await this.importCommon.import( + importFile, + parsedData, + trx, + ); + return [successedImport, failedImport, parsedData]; + }, trx); const mapping = importFile.mappingParsed; const errors = chain(failedImport) .map((oper) => oper.error) diff --git a/packages/server/src/modules/Import/ImportFileProcessCommit.ts b/packages/server/src/modules/Import/ImportFileProcessCommit.ts index ad7dd798a..e51b2632b 100644 --- a/packages/server/src/modules/Import/ImportFileProcessCommit.ts +++ b/packages/server/src/modules/Import/ImportFileProcessCommit.ts @@ -1,9 +1,11 @@ -import { ImportFilePreviewPOJO } from './interfaces'; +import { Knex } from 'knex'; +import { EventEmitter2 } from '@nestjs/event-emitter'; +import { IImportFileCommitedEventPayload, ImportFilePreviewPOJO } from './interfaces'; import { ImportFileProcess } from './ImportFileProcess'; import { ImportAls } from './ImportALS'; -import { Injectable } from '@nestjs/common'; -import { EventEmitter2 } from '@nestjs/event-emitter'; +import { Inject, Injectable } from '@nestjs/common'; import { events } from '@/common/events/events'; +import { TENANCY_DB_CONNECTION } from '../Tenancy/TenancyDB/TenancyDB.constants'; @Injectable() export class ImportFileProcessCommit { @@ -11,6 +13,9 @@ export class ImportFileProcessCommit { private readonly importFile: ImportFileProcess, private readonly importAls: ImportAls, private readonly eventEmitter: EventEmitter2, + + @Inject(TENANCY_DB_CONNECTION) + private readonly tenantKnex: () => Knex, ) {} /** @@ -30,8 +35,9 @@ export class ImportFileProcessCommit { * @returns {Promise} */ public async commitAlsRun(importId: string): Promise { - const trx = await knex.transaction({ isolationLevel: 'read uncommitted' }); - + const trx = await this.tenantKnex().transaction({ + isolationLevel: 'read uncommitted', + }); const meta = await this.importFile.import(importId, trx); // Commit the successed transaction. diff --git a/packages/server/src/modules/Import/ImportFileUpload.ts b/packages/server/src/modules/Import/ImportFileUpload.ts index 6d33811a7..5d4926f20 100644 --- a/packages/server/src/modules/Import/ImportFileUpload.ts +++ b/packages/server/src/modules/Import/ImportFileUpload.ts @@ -9,9 +9,10 @@ import { ResourceService } from '../Resource/ResourceService'; import { ImportFileCommon } from './ImportFileCommon'; import { ImportFileDataValidator } from './ImportFileDataValidator'; import { ImportFileUploadPOJO } from './interfaces'; -import { Import } from '@/system/models'; import { parseSheetData } from './sheet_utils'; -import { Injectable } from '@nestjs/common'; +import { Inject, Injectable } from '@nestjs/common'; +import { ImportModel } from './models/Import'; +import { TenancyContext } from '../Tenancy/TenancyContext.service'; @Injectable() export class ImportFileUploadService { @@ -19,6 +20,10 @@ export class ImportFileUploadService { private resourceService: ResourceService, private importFileCommon: ImportFileCommon, private importValidator: ImportFileDataValidator, + private tenancyContext: TenancyContext, + + @Inject(ImportModel.name) + private readonly importModel: typeof ImportModel, ) {} /** @@ -36,12 +41,7 @@ export class ImportFileUploadService { params: Record, ): Promise { try { - return await this.importUnhandled( - tenantId, - resourceName, - filename, - params, - ); + return await this.importUnhandled(resourceName, filename, params); } catch (err) { deleteImportFile(filename); throw err; @@ -81,15 +81,18 @@ export class ImportFileUploadService { await this.importFileCommon.validateParamsSchema(resource, params); // Validates importable params asyncly. - await this.importFileCommon.validateParams(tenantId, resource, params); + await this.importFileCommon.validateParams(resource, params); } catch (error) { throw error; } const _params = this.importFileCommon.transformParams(resource, params); const paramsStringified = JSON.stringify(_params); + const tenant = await this.tenancyContext.getTenant(); + const tenantId = tenant.id; + // Store the import model with related metadata. - const importFile = await Import.query().insert({ + const importFile = await this.importModel.query().insert({ filename, resource, tenantId, @@ -97,10 +100,8 @@ export class ImportFileUploadService { columns: coumnsStringified, params: paramsStringified, }); - const resourceColumnsMap = this.resourceService.getResourceFields2( - tenantId, - resource, - ); + const resourceColumnsMap = + this.resourceService.getResourceFields2(resource); const resourceColumns = getResourceColumns(resourceColumnsMap); return { diff --git a/packages/server/src/modules/Import/ImportRemoveExpiredFiles.ts b/packages/server/src/modules/Import/ImportRemoveExpiredFiles.ts index d89f46db6..bce8d926e 100644 --- a/packages/server/src/modules/Import/ImportRemoveExpiredFiles.ts +++ b/packages/server/src/modules/Import/ImportRemoveExpiredFiles.ts @@ -1,34 +1,36 @@ import * as moment from 'moment'; import bluebird from 'bluebird'; import { deleteImportFile } from './_utils'; -import { Injectable } from '@nestjs/common'; -import { Import } from './models/Import'; +import { Inject, Injectable } from '@nestjs/common'; +import { ImportModel } from './models/Import'; @Injectable() export class ImportDeleteExpiredFiles { + constructor( + @Inject(ImportModel.name) + private readonly importModel: typeof ImportModel, + ) {} /** * Delete expired files. */ async deleteExpiredFiles() { const yesterday = moment().subtract(1, 'hour').format('YYYY-MM-DD HH:mm'); - const expiredImports = await Import.query().where( - 'createdAt', - '<', - yesterday - ); + const expiredImports = await this.importModel + .query() + .where('createdAt', '<', yesterday); await bluebird.map( expiredImports, async (expiredImport) => { await deleteImportFile(expiredImport.filename); }, - { concurrency: 10 } + { concurrency: 10 }, ); const expiredImportsIds = expiredImports.map( - (expiredImport) => expiredImport.id + (expiredImport) => expiredImport.id, ); if (expiredImportsIds.length > 0) { - await Import.query().whereIn('id', expiredImportsIds).delete(); + await this.importModel.query().whereIn('id', expiredImportsIds).delete(); } } } diff --git a/packages/server/src/modules/Import/_utils.ts b/packages/server/src/modules/Import/_utils.ts index a43d26737..33f270705 100644 --- a/packages/server/src/modules/Import/_utils.ts +++ b/packages/server/src/modules/Import/_utils.ts @@ -111,6 +111,7 @@ export const convertFieldsToYupValidation = (fields: ResourceMetaFieldsMap) => { } else if (field.fieldType === 'url') { fieldSchema = fieldSchema.url(); } else if (field.fieldType === 'collection') { + // @ts-expect-error const nestedFieldShema = convertFieldsToYupValidation(field.fields); fieldSchema = Yup.array().label(field.name); diff --git a/packages/server/src/modules/Import/interfaces.ts b/packages/server/src/modules/Import/interfaces.ts index 1bdcf0fbb..3c597d1dd 100644 --- a/packages/server/src/modules/Import/interfaces.ts +++ b/packages/server/src/modules/Import/interfaces.ts @@ -1,5 +1,5 @@ import { IModelMetaField2 } from "@/interfaces/Model"; -import { Import } from "./models/Import"; +import { ImportModelShape } from "./models/Import"; export interface ImportMappingAttr { from: string; @@ -65,7 +65,7 @@ export interface ImportOperError { } export interface ImportableContext { - import: Import; + import: ImportModelShape; rowIndex: number; } @@ -75,3 +75,9 @@ export const ImportDateFormats = [ 'MM/dd/yy', 'dd/MMM/yyyy', ]; + + +export interface IImportFileCommitedEventPayload { + importId: string; + meta: ImportFilePreviewPOJO; +} \ No newline at end of file diff --git a/packages/server/src/modules/Import/models/Import.ts b/packages/server/src/modules/Import/models/Import.ts index a34468005..680ad8584 100644 --- a/packages/server/src/modules/Import/models/Import.ts +++ b/packages/server/src/modules/Import/models/Import.ts @@ -1,10 +1,10 @@ import { Model, ModelObject } from 'objection'; -// import SystemModel from './SystemModel'; import { BaseModel } from '@/models/Model'; -export class Import extends BaseModel { - resource: string; - tenantId: number; +export class ImportModel extends BaseModel { + resource!: string; + tenantId!: number; + filename!: string; mapping!: string; columns!: string; params!: string; @@ -85,4 +85,4 @@ export class Import extends BaseModel { } } -export type ImportShape = ModelObject; +export type ImportModelShape = ModelObject; From ab49113d5a772491b678435d98e1a9872fa9ad6f Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Wed, 9 Apr 2025 18:35:17 +0200 Subject: [PATCH 4/5] refactor(nestjs): export and import module --- .../src/modules/Accounts/Accounts.module.ts | 10 +- .../Accounts/AccountsExportable.service.ts | 3 +- .../modules/Accounts/models/Account.meta.ts | 199 +++++++++ .../modules/Accounts/models/Account.model.ts | 8 +- packages/server/src/modules/App/App.module.ts | 4 +- .../BillPayments/BillPayments.module.ts | 2 + .../src/modules/Bills/models/Bill.meta.ts | 286 ++++++++++++ .../server/src/modules/Bills/models/Bill.ts | 7 +- .../modules/Branches/models/Branch.meta.ts | 11 + .../modules/Branches/models/Branch.model.ts | 3 + .../src/modules/Customers/Customers.module.ts | 7 +- .../modules/Customers/models/Customer.meta.ts | 422 ++++++++++++++++++ .../src/modules/Customers/models/Customer.ts | 3 + .../src/modules/Export/Export.module.ts | 27 +- .../server/src/modules/Export/Export.utils.ts | 1 + .../src/modules/Export/ExportResources.ts | 56 --- .../src/modules/Export/ExportService.ts | 46 +- .../modules/Export/dtos/ExportQuery.dto.ts | 4 - .../src/modules/Import/Import.module.ts | 8 +- .../src/modules/Import/ImportableResources.ts | 2 +- packages/server/src/modules/Import/_utils.ts | 30 +- .../models/ItemCategory.meta.ts | 64 +++ .../models/ItemCategory.model.ts | 5 +- .../src/modules/Items/models/Item.meta.ts | 309 +++++++++++++ .../server/src/modules/Items/models/Item.ts | 3 + .../ManualJournals/ManualJournals.module.ts | 5 +- .../models/ManualJournal.meta.ts | 230 ++++++++++ .../ManualJournals/models/ManualJournal.ts | 3 + .../src/modules/Resource/Resource.module.ts | 5 + .../src/modules/Resource/ResourceService.ts | 4 +- .../server/src/modules/Resource/_utils.ts | 2 +- .../SaleInvoices/models/SaleInvoice.meta.ts | 316 +++++++++++++ .../SaleInvoices/models/SaleInvoice.ts | 4 +- .../Tenancy/TenancyModels/Tenancy.module.ts | 1 + .../decorators/InjectModelMeta.decorator.ts | 18 + .../src/modules/Vendors/models/Vendor.meta.ts | 407 +++++++++++++++++ .../src/modules/Vendors/models/Vendor.ts | 3 + .../modules/Warehouses/Warehouses.module.ts | 2 +- 38 files changed, 2403 insertions(+), 117 deletions(-) create mode 100644 packages/server/src/modules/Accounts/models/Account.meta.ts create mode 100644 packages/server/src/modules/Bills/models/Bill.meta.ts create mode 100644 packages/server/src/modules/Branches/models/Branch.meta.ts create mode 100644 packages/server/src/modules/Customers/models/Customer.meta.ts delete mode 100644 packages/server/src/modules/Export/ExportResources.ts create mode 100644 packages/server/src/modules/ItemCategories/models/ItemCategory.meta.ts create mode 100644 packages/server/src/modules/Items/models/Item.meta.ts create mode 100644 packages/server/src/modules/ManualJournals/models/ManualJournal.meta.ts create mode 100644 packages/server/src/modules/SaleInvoices/models/SaleInvoice.meta.ts create mode 100644 packages/server/src/modules/Tenancy/TenancyModels/decorators/InjectModelMeta.decorator.ts create mode 100644 packages/server/src/modules/Vendors/models/Vendor.meta.ts diff --git a/packages/server/src/modules/Accounts/Accounts.module.ts b/packages/server/src/modules/Accounts/Accounts.module.ts index 41ae6bc11..6017a3189 100644 --- a/packages/server/src/modules/Accounts/Accounts.module.ts +++ b/packages/server/src/modules/Accounts/Accounts.module.ts @@ -18,7 +18,6 @@ import { BankAccount } from '../BankingTransactions/models/BankAccount'; import { GetAccountsService } from './GetAccounts.service'; import { DynamicListModule } from '../DynamicListing/DynamicList.module'; import { AccountsExportable } from './AccountsExportable.service'; -// import { GetAccountsService } from './GetAccounts.service'; const models = [RegisterTenancyModel(BankAccount)]; @@ -39,8 +38,13 @@ const models = [RegisterTenancyModel(BankAccount)]; GetAccountTypesService, GetAccountTransactionsService, GetAccountsService, - AccountsExportable + AccountsExportable, + ], + exports: [ + AccountRepository, + CreateAccountService, + ...models, + AccountsExportable, ], - exports: [AccountRepository, CreateAccountService, ...models], }) export class AccountsModule {} diff --git a/packages/server/src/modules/Accounts/AccountsExportable.service.ts b/packages/server/src/modules/Accounts/AccountsExportable.service.ts index e05c2db0d..2931916c6 100644 --- a/packages/server/src/modules/Accounts/AccountsExportable.service.ts +++ b/packages/server/src/modules/Accounts/AccountsExportable.service.ts @@ -2,12 +2,13 @@ import { AccountsApplication } from './AccountsApplication.service'; import { Exportable } from '../Export/Exportable'; import { EXPORT_SIZE_LIMIT } from '../Export/constants'; import { IAccountsFilter, IAccountsStructureType } from './Accounts.types'; -import { Injectable } from '@nestjs/common'; +import { Global, Injectable } from '@nestjs/common'; import { ExportableService } from '../Export/decorators/ExportableModel.decorator'; import { Account } from './models/Account.model'; @Injectable() @ExportableService({ name: Account.name }) +@Global() export class AccountsExportable extends Exportable { /** * @param {AccountsApplication} accountsApplication diff --git a/packages/server/src/modules/Accounts/models/Account.meta.ts b/packages/server/src/modules/Accounts/models/Account.meta.ts new file mode 100644 index 000000000..37314928c --- /dev/null +++ b/packages/server/src/modules/Accounts/models/Account.meta.ts @@ -0,0 +1,199 @@ +import { ACCOUNT_TYPES } from "../Accounts.constants"; + +export const AccountMeta = { + defaultFilterField: 'name', + defaultSort: { + sortOrder: 'DESC', + sortField: 'name', + }, + importable: true, + exportable: true, + print: { + pageTitle: 'Chart of Accounts', + }, + fields: { + name: { + name: 'account.field.name', + column: 'name', + fieldType: 'text', + }, + description: { + name: 'account.field.description', + column: 'description', + fieldType: 'text', + }, + slug: { + name: 'account.field.slug', + column: 'slug', + fieldType: 'text', + columnable: false, + filterable: false, + }, + code: { + name: 'account.field.code', + column: 'code', + fieldType: 'text', + }, + root_type: { + name: 'account.field.root_type', + fieldType: 'enumeration', + options: [ + { key: 'asset', label: 'Asset' }, + { key: 'liability', label: 'Liability' }, + { key: 'equity', label: 'Equity' }, + { key: 'Income', label: 'Income' }, + { key: 'expense', label: 'Expense' }, + ], + filterCustomQuery: RootTypeFieldFilterQuery, + sortable: false, + }, + normal: { + name: 'account.field.normal', + fieldType: 'enumeration', + options: [ + { key: 'debit', label: 'account.field.normal.debit' }, + { key: 'credit', label: 'account.field.normal.credit' }, + ], + filterCustomQuery: NormalTypeFieldFilterQuery, + sortable: false, + }, + type: { + name: 'account.field.type', + column: 'account_type', + fieldType: 'enumeration', + options: ACCOUNT_TYPES.map((accountType) => ({ + label: accountType.label, + key: accountType.key, + })), + }, + active: { + name: 'account.field.active', + column: 'active', + fieldType: 'boolean', + filterable: false, + }, + balance: { + name: 'account.field.balance', + column: 'amount', + fieldType: 'number', + }, + currency: { + name: 'account.field.currency', + column: 'currency_code', + fieldType: 'text', + filterable: false, + }, + created_at: { + name: 'account.field.created_at', + column: 'created_at', + fieldType: 'date', + }, + }, + columns: { + name: { + name: 'account.field.name', + type: 'text', + }, + code: { + name: 'account.field.code', + type: 'text', + }, + rootType: { + name: 'account.field.root_type', + type: 'text', + accessor: 'accountRootType', + }, + accountType: { + name: 'account.field.type', + accessor: 'accountTypeLabel', + type: 'text', + }, + accountNormal: { + name: 'account.field.normal', + accessor: 'accountNormalFormatted', + }, + currencyCode: { + name: 'account.field.currency', + type: 'text', + }, + bankBalance: { + name: 'account.field.bank_balance', + accessor: 'bankBalanceFormatted', + type: 'text', + exportable: true, + }, + balance: { + name: 'account.field.balance', + accessor: 'formattedAmount', + }, + description: { + name: 'account.field.description', + type: 'text', + }, + active: { + name: 'account.field.active', + type: 'boolean', + }, + createdAt: { + name: 'account.field.created_at', + printable: false, + }, + }, + fields2: { + name: { + name: 'account.field.name', + fieldType: 'text', + unique: true, + required: true, + }, + description: { + name: 'account.field.description', + fieldType: 'text', + }, + code: { + name: 'account.field.code', + fieldType: 'text', + minLength: 3, + maxLength: 6, + unique: true, + importHint: 'Unique number to identify the account.', + }, + accountType: { + name: 'account.field.type', + fieldType: 'enumeration', + options: ACCOUNT_TYPES.map((accountType) => ({ + label: accountType.label, + key: accountType.key, + })), + required: true, + }, + active: { + name: 'account.field.active', + fieldType: 'boolean', + }, + currencyCode: { + name: 'account.field.currency', + fieldType: 'text', + }, + parentAccountId: { + name: 'account.field.parent_account', + fieldType: 'relation', + relationModel: 'Account', + relationImportMatch: ['name', 'code'], + }, + }, +}; + +/** + * Filter query of root type field . + */ +function RootTypeFieldFilterQuery(query, role) { + query.modify('filterByRootType', role.value); +} + +/** + * Filter query of normal field . + */ +function NormalTypeFieldFilterQuery(query, role) { + query.modify('filterByAccountNormal', role.value); +} \ No newline at end of file diff --git a/packages/server/src/modules/Accounts/models/Account.model.ts b/packages/server/src/modules/Accounts/models/Account.model.ts index 40f127ec5..e7429581b 100644 --- a/packages/server/src/modules/Accounts/models/Account.model.ts +++ b/packages/server/src/modules/Accounts/models/Account.model.ts @@ -1,27 +1,27 @@ /* eslint-disable global-require */ -// import { mixin, Model } from 'objection'; import { castArray } from 'lodash'; +import { Model } from 'objection'; import DependencyGraph from '@/libs/dependency-graph'; import { ACCOUNT_TYPES, getAccountsSupportsMultiCurrency, } from '@/constants/accounts'; -import { TenantModel } from '@/modules/System/models/TenantModel'; // import { SearchableModel } from '@/modules/Search/SearchableMdel'; // import { CustomViewBaseModel } from '@/modules/CustomViews/CustomViewBaseModel'; // import { ModelSettings } from '@/modules/Settings/ModelSettings'; 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 { flatToNestedArray } from '@/utils/flat-to-nested-array'; import { ExportableModel } from '../../Export/decorators/ExportableModel.decorator'; +import { AccountMeta } from './Account.meta'; +import { InjectModelMeta } from '@/modules/Tenancy/TenancyModels/decorators/InjectModelMeta.decorator'; // import AccountSettings from './Account.Settings'; // import { DEFAULT_VIEWS } from '@/modules/Accounts/constants'; // import { buildFilterQuery, buildSortColumnQuery } from '@/lib/ViewRolesBuilder'; -// import { flatToNestedArray } from 'utils'; @ExportableModel() +@InjectModelMeta(AccountMeta) export class Account extends TenantBaseModel { public name!: string; public slug!: string; diff --git a/packages/server/src/modules/App/App.module.ts b/packages/server/src/modules/App/App.module.ts index 0e0d0dc1c..28791abb3 100644 --- a/packages/server/src/modules/App/App.module.ts +++ b/packages/server/src/modules/App/App.module.ts @@ -80,6 +80,7 @@ import { LoopsModule } from '../Loops/Loops.module'; import { AttachmentsModule } from '../Attachments/Attachment.module'; import { S3Module } from '../S3/S3.module'; import { ExportModule } from '../Export/Export.module'; +import { ImportModule } from '../Import/Import.module'; @Module({ imports: [ @@ -194,7 +195,8 @@ import { ExportModule } from '../Export/Export.module'; LoopsModule, AttachmentsModule, S3Module, - ExportModule + ExportModule, + ImportModule ], controllers: [AppController], providers: [ diff --git a/packages/server/src/modules/BillPayments/BillPayments.module.ts b/packages/server/src/modules/BillPayments/BillPayments.module.ts index e9f01f6e7..9bd5f345f 100644 --- a/packages/server/src/modules/BillPayments/BillPayments.module.ts +++ b/packages/server/src/modules/BillPayments/BillPayments.module.ts @@ -17,6 +17,7 @@ import { BillPaymentGLEntriesSubscriber } from './subscribers/BillPaymentGLEntri import { LedgerModule } from '../Ledger/Ledger.module'; import { AccountsModule } from '../Accounts/Accounts.module'; import { BillPaymentsExportable } from './queries/BillPaymentsExportable'; +import { GetBillPayments } from '../Bills/queries/GetBillPayments'; @Module({ imports: [LedgerModule, AccountsModule], @@ -35,6 +36,7 @@ import { BillPaymentsExportable } from './queries/BillPaymentsExportable'; TenancyContext, BillPaymentGLEntries, BillPaymentGLEntriesSubscriber, + GetBillPayments, BillPaymentsExportable ], exports: [BillPaymentValidators, CreateBillPaymentService], diff --git a/packages/server/src/modules/Bills/models/Bill.meta.ts b/packages/server/src/modules/Bills/models/Bill.meta.ts new file mode 100644 index 000000000..b5313dbd9 --- /dev/null +++ b/packages/server/src/modules/Bills/models/Bill.meta.ts @@ -0,0 +1,286 @@ +import { Features } from "@/common/types/Features"; + +export const BillMeta = { + defaultFilterField: 'vendor', + defaultSort: { + sortOrder: 'DESC', + sortField: 'bill_date', + }, + importable: true, + exportFlattenOn: 'entries', + exportable: true, + importAggregator: 'group', + importAggregateOn: 'entries', + importAggregateBy: 'billNumber', + print: { + pageTitle: 'Bills', + }, + fields: { + vendor: { + name: 'bill.field.vendor', + column: 'vendor_id', + fieldType: 'relation', + + relationType: 'enumeration', + relationKey: 'vendor', + + relationEntityLabel: 'display_name', + relationEntityKey: 'id', + }, + bill_number: { + name: 'bill.field.bill_number', + column: 'bill_number', + columnable: true, + fieldType: 'text', + }, + bill_date: { + name: 'bill.field.bill_date', + column: 'bill_date', + columnable: true, + fieldType: 'date', + }, + due_date: { + name: 'bill.field.due_date', + column: 'due_date', + columnable: true, + fieldType: 'date', + }, + reference_no: { + name: 'bill.field.reference_no', + column: 'reference_no', + columnable: true, + fieldType: 'text', + }, + status: { + name: 'bill.field.status', + fieldType: 'enumeration', + columnable: true, + options: [ + { label: 'bill.field.status.paid', key: 'paid' }, + { label: 'bill.field.status.partially-paid', key: 'partially-paid' }, + { label: 'bill.field.status.overdue', key: 'overdue' }, + { label: 'bill.field.status.unpaid', key: 'unpaid' }, + { label: 'bill.field.status.opened', key: 'opened' }, + { label: 'bill.field.status.draft', key: 'draft' }, + ], + filterCustomQuery: StatusFieldFilterQuery, + sortCustomQuery: StatusFieldSortQuery, + }, + amount: { + name: 'bill.field.amount', + column: 'amount', + fieldType: 'number', + }, + payment_amount: { + name: 'bill.field.payment_amount', + column: 'payment_amount', + fieldType: 'number', + }, + note: { + name: 'bill.field.note', + column: 'note', + fieldType: 'text', + }, + created_at: { + name: 'bill.field.created_at', + column: 'created_at', + fieldType: 'date', + }, + }, + columns: { + billDate: { + name: 'Date', + accessor: 'formattedBillDate', + }, + billNumber: { + name: 'Bill No.', + type: 'text', + }, + referenceNo: { + name: 'Reference No.', + type: 'text', + }, + dueDate: { + name: 'Due Date', + type: 'date', + accessor: 'formattedDueDate', + }, + vendorId: { + name: 'Vendor', + accessor: 'vendor.displayName', + type: 'text', + }, + amount: { + name: 'Amount', + accessor: 'formattedAmount', + }, + exchangeRate: { + name: 'Exchange Rate', + type: 'number', + printable: false, + }, + currencyCode: { + name: 'Currency Code', + type: 'text', + printable: false, + }, + dueAmount: { + name: 'Due Amount', + accessor: 'formattedDueAmount', + }, + paidAmount: { + name: 'Paid Amount', + accessor: 'formattedPaymentAmount', + }, + note: { + name: 'Note', + type: 'text', + printable: false, + }, + open: { + name: 'Open', + type: 'boolean', + printable: false, + }, + entries: { + name: 'Entries', + accessor: 'entries', + type: 'collection', + collectionOf: 'object', + columns: { + itemName: { + name: 'Item Name', + accessor: 'item.name', + }, + rate: { + name: 'Item Rate', + accessor: 'rateFormatted', + }, + quantity: { + name: 'Item Quantity', + accessor: 'quantityFormatted', + }, + description: { + name: 'Item Description', + }, + amount: { + name: 'Item Amount', + accessor: 'totalFormatted', + }, + }, + }, + branch: { + name: 'Branch', + type: 'text', + accessor: 'branch.name', + features: [Features.BRANCHES], + }, + warehouse: { + name: 'Warehouse', + type: 'text', + accessor: 'warehouse.name', + features: [Features.BRANCHES], + }, + }, + fields2: { + billNumber: { + name: 'Bill No.', + fieldType: 'text', + required: true, + }, + referenceNo: { + name: 'Reference No.', + fieldType: 'text', + }, + billDate: { + name: 'Date', + fieldType: 'date', + required: true, + }, + dueDate: { + name: 'Due Date', + fieldType: 'date', + required: true, + }, + vendorId: { + name: 'Vendor', + fieldType: 'relation', + relationModel: 'Contact', + relationImportMatch: 'displayName', + required: true, + }, + exchangeRate: { + name: 'Exchange Rate', + fieldType: 'number', + }, + note: { + name: 'Note', + fieldType: 'text', + }, + open: { + name: 'Open', + fieldType: 'boolean', + }, + entries: { + name: 'Entries', + fieldType: 'collection', + collectionOf: 'object', + collectionMinLength: 1, + required: true, + fields: { + itemId: { + name: 'Item', + fieldType: 'relation', + relationModel: 'Item', + relationImportMatch: ['name', 'code'], + required: true, + importHint: 'Matches the item name or code.', + }, + rate: { + name: 'Rate', + fieldType: 'number', + required: true, + }, + quantity: { + name: 'Quantity', + fieldType: 'number', + required: true, + }, + description: { + name: 'Line Description', + fieldType: 'text', + }, + }, + }, + branchId: { + name: 'Branch', + fieldType: 'relation', + relationModel: 'Branch', + relationImportMatch: ['name', 'code'], + features: [Features.BRANCHES], + required: true, + }, + warehouseId: { + name: 'Warehouse', + fieldType: 'relation', + relationModel: 'Warehouse', + relationImportMatch: ['name', 'code'], + features: [Features.WAREHOUSES], + required: true, + }, + }, +}; + +/** + * Status field filter custom query. + */ +function StatusFieldFilterQuery(query, role) { + query.modify('statusFilter', role.value); +} + +/** + * Status field sort custom query. + */ +function StatusFieldSortQuery(query, role) { + query.modify('sortByStatus', role.order); +} \ No newline at end of file diff --git a/packages/server/src/modules/Bills/models/Bill.ts b/packages/server/src/modules/Bills/models/Bill.ts index 41da17fc3..9c665bf6f 100644 --- a/packages/server/src/modules/Bills/models/Bill.ts +++ b/packages/server/src/modules/Bills/models/Bill.ts @@ -1,4 +1,5 @@ -import { Model, raw, mixin } from 'objection'; +import type { Knex } from 'knex'; +import { Model, raw } from 'objection'; import { castArray, difference, defaultTo } from 'lodash'; import * as moment from 'moment'; import * as R from 'ramda'; @@ -12,11 +13,13 @@ import { BaseModel, PaginationQueryBuilderType } from '@/models/Model'; import { ItemEntry } from '@/modules/TransactionItemEntry/models/ItemEntry'; import { BillLandedCost } from '@/modules/BillLandedCosts/models/BillLandedCost'; import { DiscountType } from '@/common/types/Discount'; -import type { Knex, QueryBuilder } from 'knex'; import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel'; import { ExportableModel } from '@/modules/Export/decorators/ExportableModel.decorator'; +import { InjectModelMeta } from '@/modules/Tenancy/TenancyModels/decorators/InjectModelMeta.decorator'; +import { BillMeta } from './Bill.meta'; @ExportableModel() +@InjectModelMeta(BillMeta) export class Bill extends TenantBaseModel { public amount: number; public paymentAmount: number; diff --git a/packages/server/src/modules/Branches/models/Branch.meta.ts b/packages/server/src/modules/Branches/models/Branch.meta.ts new file mode 100644 index 000000000..0361d10bd --- /dev/null +++ b/packages/server/src/modules/Branches/models/Branch.meta.ts @@ -0,0 +1,11 @@ +export const BranchMeta = { + fields2: { + name: { + name: 'Name', + fieldType: 'text', + required: true, + }, + }, + columns: {}, + fields: {} +}; \ No newline at end of file diff --git a/packages/server/src/modules/Branches/models/Branch.model.ts b/packages/server/src/modules/Branches/models/Branch.model.ts index 20f3aa593..d09d30845 100644 --- a/packages/server/src/modules/Branches/models/Branch.model.ts +++ b/packages/server/src/modules/Branches/models/Branch.model.ts @@ -3,7 +3,10 @@ // import BranchMetadata from './Branch.settings'; // import ModelSetting from './ModelSetting'; import { BaseModel } from '@/models/Model'; +import { InjectModelMeta } from '@/modules/Tenancy/TenancyModels/decorators/InjectModelMeta.decorator'; +import { BranchMeta } from './Branch.meta'; +@InjectModelMeta(BranchMeta) export class Branch extends BaseModel{ name!: string; code!: string; diff --git a/packages/server/src/modules/Customers/Customers.module.ts b/packages/server/src/modules/Customers/Customers.module.ts index 7531ae9b6..434b7893a 100644 --- a/packages/server/src/modules/Customers/Customers.module.ts +++ b/packages/server/src/modules/Customers/Customers.module.ts @@ -14,9 +14,11 @@ import { CustomersApplication } from './CustomersApplication.service'; import { DeleteCustomer } from './commands/DeleteCustomer.service'; import { CustomersExportable } from './CustomersExportable'; import { CustomersImportable } from './CustomersImportable'; +import { GetCustomers } from './queries/GetCustomers.service'; +import { DynamicListModule } from '../DynamicListing/DynamicList.module'; @Module({ - imports: [TenancyDatabaseModule], + imports: [TenancyDatabaseModule, DynamicListModule], controllers: [CustomersController], providers: [ ActivateCustomer, @@ -33,7 +35,8 @@ import { CustomersImportable } from './CustomersImportable'; TransformerInjectable, GetCustomerService, CustomersExportable, - CustomersImportable + CustomersImportable, + GetCustomers ], }) export class CustomersModule {} diff --git a/packages/server/src/modules/Customers/models/Customer.meta.ts b/packages/server/src/modules/Customers/models/Customer.meta.ts new file mode 100644 index 000000000..4651a0ac4 --- /dev/null +++ b/packages/server/src/modules/Customers/models/Customer.meta.ts @@ -0,0 +1,422 @@ +export const CustomerMeta = { + importable: true, + exportable: true, + defaultFilterField: 'displayName', + defaultSort: { + sortOrder: 'DESC', + sortField: 'created_at', + }, + print: { + pageTitle: 'Customers', + }, + fields: { + first_name: { + name: 'vendor.field.first_name', + column: 'first_name', + fieldType: 'text', + }, + last_name: { + name: 'vendor.field.last_name', + column: 'last_name', + fieldType: 'text', + }, + display_name: { + name: 'vendor.field.display_name', + column: 'display_name', + fieldType: 'text', + }, + email: { + name: 'vendor.field.email', + column: 'email', + fieldType: 'text', + }, + work_phone: { + name: 'vendor.field.work_phone', + column: 'work_phone', + fieldType: 'text', + }, + personal_phone: { + name: 'vendor.field.personal_pone', + column: 'personal_phone', + fieldType: 'text', + }, + company_name: { + name: 'vendor.field.company_name', + column: 'company_name', + fieldType: 'text', + }, + website: { + name: 'vendor.field.website', + column: 'website', + fieldType: 'text', + }, + created_at: { + name: 'vendor.field.created_at', + column: 'created_at', + fieldType: 'date', + }, + balance: { + name: 'vendor.field.balance', + column: 'balance', + fieldType: 'number', + }, + opening_balance: { + name: 'vendor.field.opening_balance', + column: 'opening_balance', + fieldType: 'number', + }, + opening_balance_at: { + name: 'vendor.field.opening_balance_at', + column: 'opening_balance_at', + fieldType: 'date', + }, + currency_code: { + name: 'vendor.field.currency', + column: 'currency_code', + fieldType: 'text', + }, + status: { + name: 'vendor.field.status', + type: 'enumeration', + options: [ + { key: 'overdue', label: 'vendor.field.status.overdue' }, + { key: 'unpaid', label: 'vendor.field.status.unpaid' }, + ], + filterCustomQuery: (query, role) => { + switch (role.value) { + case 'overdue': + query.modify('overdue'); + break; + case 'unpaid': + query.modify('unpaid'); + break; + } + }, + }, + }, + columns: { + customerType: { + name: 'Customer Type', + type: 'text', + accessor: 'formattedCustomerType', + }, + firstName: { + name: 'vendor.field.first_name', + type: 'text', + }, + lastName: { + name: 'vendor.field.last_name', + type: 'text', + }, + displayName: { + name: 'vendor.field.display_name', + type: 'text', + }, + email: { + name: 'vendor.field.email', + type: 'text', + }, + workPhone: { + name: 'vendor.field.work_phone', + type: 'text', + }, + personalPhone: { + name: 'vendor.field.personal_phone', + type: 'text', + }, + companyName: { + name: 'vendor.field.company_name', + type: 'text', + }, + website: { + name: 'vendor.field.website', + type: 'text', + }, + balance: { + name: 'vendor.field.balance', + type: 'number', + accessor: 'formattedBalance', + }, + openingBalance: { + name: 'vendor.field.opening_balance', + type: 'number', + printable: false, + }, + openingBalanceAt: { + name: 'vendor.field.opening_balance_at', + type: 'date', + printable: false, + accessor: 'formattedOpeningBalanceAt' + }, + currencyCode: { + name: 'vendor.field.currency', + type: 'text', + printable: false, + }, + status: { + name: 'vendor.field.status', + printable: false, + }, + note: { + name: 'vendor.field.note', + printable: false, + }, + // Billing Address + billingAddress1: { + name: 'Billing Address 1', + column: 'billing_address1', + type: 'text', + printable: false, + }, + billingAddress2: { + name: 'Billing Address 2', + column: 'billing_address2', + type: 'text', + printable: false, + }, + billingAddressCity: { + name: 'Billing Address City', + column: 'billing_address_city', + type: 'text', + printable: false, + }, + billingAddressCountry: { + name: 'Billing Address Country', + column: 'billing_address_country', + type: 'text', + printable: false, + }, + billingAddressPostcode: { + name: 'Billing Address Postcode', + column: 'billing_address_postcode', + type: 'text', + printable: false, + }, + billingAddressState: { + name: 'Billing Address State', + column: 'billing_address_state', + type: 'text', + printable: false, + }, + billingAddressPhone: { + name: 'Billing Address Phone', + column: 'billing_address_phone', + type: 'text', + printable: false, + }, + // Shipping Address + shippingAddress1: { + name: 'Shipping Address 1', + column: 'shipping_address1', + type: 'text', + printable: false, + }, + shippingAddress2: { + name: 'Shipping Address 2', + column: 'shipping_address2', + type: 'text', + printable: false, + }, + shippingAddressCity: { + name: 'Shipping Address City', + column: 'shipping_address_city', + type: 'text', + printable: false, + }, + shippingAddressCountry: { + name: 'Shipping Address Country', + column: 'shipping_address_country', + type: 'text', + printable: false, + }, + shippingAddressPostcode: { + name: 'Shipping Address Postcode', + column: 'shipping_address_postcode', + type: 'text', + printable: false, + }, + shippingAddressPhone: { + name: 'Shipping Address Phone', + column: 'shipping_address_phone', + type: 'text', + printable: false, + }, + shippingAddressState: { + name: 'Shipping Address State', + column: 'shipping_address_state', + type: 'text', + printable: false, + }, + createdAt: { + name: 'vendor.field.created_at', + type: 'date', + printable: false, + }, + }, + fields2: { + customerType: { + name: 'Customer Type', + fieldType: 'enumeration', + options: [ + { key: 'business', label: 'Business' }, + { key: 'individual', label: 'Individual' }, + ], + required: true, + }, + firstName: { + name: 'customer.field.first_name', + column: 'first_name', + fieldType: 'text', + }, + lastName: { + name: 'customer.field.last_name', + column: 'last_name', + fieldType: 'text', + }, + displayName: { + name: 'customer.field.display_name', + column: 'display_name', + fieldType: 'text', + required: true, + }, + email: { + name: 'customer.field.email', + column: 'email', + fieldType: 'text', + }, + workPhone: { + name: 'customer.field.work_phone', + column: 'work_phone', + fieldType: 'text', + }, + personalPhone: { + name: 'customer.field.personal_phone', + column: 'personal_phone', + fieldType: 'text', + }, + companyName: { + name: 'customer.field.company_name', + column: 'company_name', + fieldType: 'text', + }, + website: { + name: 'customer.field.website', + column: 'website', + fieldType: 'url', + }, + openingBalance: { + name: 'customer.field.opening_balance', + column: 'opening_balance', + fieldType: 'number', + }, + openingBalanceAt: { + name: 'customer.field.opening_balance_at', + column: 'opening_balance_at', + filterable: false, + fieldType: 'date', + }, + openingBalanceExchangeRate: { + name: 'Opening Balance Ex. Rate', + column: 'opening_balance_exchange_rate', + fieldType: 'number', + }, + currencyCode: { + name: 'customer.field.currency', + column: 'currency_code', + fieldType: 'text', + }, + note: { + name: 'Note', + column: 'note', + fieldType: 'text', + }, + active: { + name: 'Active', + column: 'active', + fieldType: 'boolean', + }, + // Billing Address + billingAddress1: { + name: 'Billing Address 1', + column: 'billing_address1', + fieldType: 'text', + }, + billingAddress2: { + name: 'Billing Address 2', + column: 'billing_address2', + fieldType: 'text', + }, + billingAddressCity: { + name: 'Billing Address City', + column: 'billing_address_city', + fieldType: 'text', + }, + billingAddressCountry: { + name: 'Billing Address Country', + column: 'billing_address_country', + fieldType: 'text', + }, + billingAddressPostcode: { + name: 'Billing Address Postcode', + column: 'billing_address_postcode', + fieldType: 'text', + }, + billingAddressState: { + name: 'Billing Address State', + column: 'billing_address_state', + fieldType: 'text', + }, + billingAddressPhone: { + name: 'Billing Address Phone', + column: 'billing_address_phone', + fieldType: 'text', + }, + // Shipping Address + shippingAddress1: { + name: 'Shipping Address 1', + column: 'shipping_address1', + fieldType: 'text', + }, + shippingAddress2: { + name: 'Shipping Address 2', + column: 'shipping_address2', + fieldType: 'text', + }, + shippingAddressCity: { + name: 'Shipping Address City', + column: 'shipping_address_city', + fieldType: 'text', + }, + shippingAddressCountry: { + name: 'Shipping Address Country', + column: 'shipping_address_country', + fieldType: 'text', + }, + shippingAddressPostcode: { + name: 'Shipping Address Postcode', + column: 'shipping_address_postcode', + fieldType: 'text', + }, + shippingAddressPhone: { + name: 'Shipping Address Phone', + column: 'shipping_address_phone', + fieldType: 'text', + }, + shippingAddressState: { + name: 'Shipping Address State', + column: 'shipping_address_state', + fieldType: 'text', + }, + }, +}; + +function statusFieldFilterQuery(query, role) { + switch (role.value) { + case 'overdue': + query.modify('overdue'); + break; + case 'unpaid': + query.modify('unpaid'); + break; + } +} \ No newline at end of file diff --git a/packages/server/src/modules/Customers/models/Customer.ts b/packages/server/src/modules/Customers/models/Customer.ts index 1e720625a..ee86a5b81 100644 --- a/packages/server/src/modules/Customers/models/Customer.ts +++ b/packages/server/src/modules/Customers/models/Customer.ts @@ -1,6 +1,9 @@ import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel'; +import { InjectModelMeta } from '@/modules/Tenancy/TenancyModels/decorators/InjectModelMeta.decorator'; +import { CustomerMeta } from './Customer.meta'; +@InjectModelMeta(CustomerMeta) export class Customer extends TenantBaseModel{ contactService: string; contactType: string; diff --git a/packages/server/src/modules/Export/Export.module.ts b/packages/server/src/modules/Export/Export.module.ts index ca47b42cc..59e73e771 100644 --- a/packages/server/src/modules/Export/Export.module.ts +++ b/packages/server/src/modules/Export/Export.module.ts @@ -4,9 +4,34 @@ import { ExportResourceService } from './ExportService'; import { ExportPdf } from './ExportPdf'; import { ExportAls } from './ExportAls'; import { ExportApplication } from './ExportApplication'; +import { ResourceModule } from '../Resource/Resource.module'; +import { RegisterTenancyModel } from '../Tenancy/TenancyModels/Tenancy.module'; +import { ImportModel } from '../Import/models/Import'; +import { ExportableResources } from './ExportResources'; +import { ExportableRegistry } from './ExportRegistery'; +import { TemplateInjectableModule } from '../TemplateInjectable/TemplateInjectable.module'; +import { ChromiumlyTenancyModule } from '../ChromiumlyTenancy/ChromiumlyTenancy.module'; +import { AccountsModule } from '../Accounts/Accounts.module'; + +const models = [RegisterTenancyModel(ImportModel)]; @Module({ - providers: [ExportResourceService, ExportPdf, ExportAls, ExportApplication], + imports: [ + ...models, + ResourceModule, + TemplateInjectableModule, + ChromiumlyTenancyModule, + AccountsModule + ], + providers: [ + ExportResourceService, + ExportPdf, + ExportAls, + ExportApplication, + ExportableResources, + ExportableRegistry + ], + exports: [...models], controllers: [ExportController], }) export class ExportModule {} diff --git a/packages/server/src/modules/Export/Export.utils.ts b/packages/server/src/modules/Export/Export.utils.ts index 97b31125e..c902b6fe6 100644 --- a/packages/server/src/modules/Export/Export.utils.ts +++ b/packages/server/src/modules/Export/Export.utils.ts @@ -3,6 +3,7 @@ import { ExportFormat } from './common'; export const convertAcceptFormatToFormat = (accept: string): ExportFormat => { switch (accept) { + default: case ACCEPT_TYPE.APPLICATION_CSV: return ExportFormat.Csv; case ACCEPT_TYPE.APPLICATION_PDF: diff --git a/packages/server/src/modules/Export/ExportResources.ts b/packages/server/src/modules/Export/ExportResources.ts deleted file mode 100644 index 660b02829..000000000 --- a/packages/server/src/modules/Export/ExportResources.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { Injectable } from "@nestjs/common"; -import { ExportableRegistry } from "./ExportRegistery"; -import { AccountsExportable } from "../Accounts/AccountsExportable.service"; - -@Injectable() -export class ExportableResources { - constructor( - private readonly exportRegistry: ExportableRegistry, - ) { - this.boot(); - } - - /** - * Importable instances. - */ - private importables = [ - // { resource: 'Account', exportable: AccountsExportable }, - // { resource: 'Item', exportable: ItemsExportable }, - // { resource: 'ItemCategory', exportable: ItemCategoriesExportable }, - // { resource: 'Customer', exportable: CustomersExportable }, - // { resource: 'Vendor', exportable: VendorsExportable }, - // { resource: 'Expense', exportable: ExpensesExportable }, - // { resource: 'SaleInvoice', exportable: SaleInvoicesExportable }, - // { resource: 'SaleEstimate', exportable: SaleEstimatesExportable }, - // { resource: 'SaleReceipt', exportable: SaleReceiptsExportable }, - // { resource: 'Bill', exportable: BillsExportable }, - // { resource: 'PaymentReceive', exportable: PaymentsReceivedExportable }, - // { resource: 'BillPayment', exportable: BillPaymentExportable }, - // { resource: 'ManualJournal', exportable: ManualJournalsExportable }, - // { resource: 'CreditNote', exportable: CreditNotesExportable }, - // { resource: 'VendorCredit', exportable: VendorCreditsExportable }, - // { resource: 'TaxRate', exportable: TaxRatesExportable }, - ]; - - /** - * - */ - public get registry() { - return ExportableResources.registry; - } - - /** - * Boots all the registered importables. - */ - public boot() { - if (!ExportableResources.registry) { - const instance = ExportableRegistry.getInstance(); - - this.importables.forEach((importable) => { - const importableInstance = Container.get(importable.exportable); - instance.registerExportable(importable.resource, importableInstance); - }); - ExportableResources.registry = instance; - } - } -} diff --git a/packages/server/src/modules/Export/ExportService.ts b/packages/server/src/modules/Export/ExportService.ts index 0dc465d28..6e8e704e4 100644 --- a/packages/server/src/modules/Export/ExportService.ts +++ b/packages/server/src/modules/Export/ExportService.ts @@ -1,5 +1,5 @@ import { Injectable } from '@nestjs/common'; -import xlsx from 'xlsx'; +import * as xlsx from 'xlsx'; import * as R from 'ramda'; import { get } from 'lodash'; import { sanitizeResourceName } from '../Import/_utils'; @@ -10,6 +10,9 @@ import { ExportPdf } from './ExportPdf'; import { ExportAls } from './ExportAls'; import { IModelMeta, IModelMetaColumn } from '@/interfaces/Model'; import { ServiceError } from '../Items/ServiceError'; +import { ResourceService } from '../Resource/ResourceService'; +import { getExportableService } from './decorators/ExportableModel.decorator'; +import { ContextIdFactory, ModuleRef } from '@nestjs/core'; @Injectable() export class ExportResourceService { @@ -18,6 +21,7 @@ export class ExportResourceService { private readonly exportPdf: ExportPdf, private readonly exportableResources: ExportableResources, private readonly resourceService: ResourceService, + private readonly moduleRef: ModuleRef, ) {} /** @@ -27,11 +31,9 @@ export class ExportResourceService { */ public async export( resourceName: string, - format: ExportFormat = ExportFormat.Csv + format: ExportFormat = ExportFormat.Csv, ) { - return this.exportAls.run(() => - this.exportAlsRun(resourceName, format) - ); + return this.exportAls.run(() => this.exportAlsRun(resourceName, format)); } /** @@ -41,18 +43,19 @@ export class ExportResourceService { */ public async exportAlsRun( resourceName: string, - format: ExportFormat = ExportFormat.Csv + format: ExportFormat = ExportFormat.Csv, ) { const resource = sanitizeResourceName(resourceName); const resourceMeta = this.getResourceMeta(resource); - const resourceColumns = this.resourceService.getResourceColumns( - resource - ); + + const resourceColumns = this.resourceService.getResourceColumns(resource); this.validateResourceMeta(resourceMeta); const data = await this.getExportableData(resource); const transformed = this.transformExportedData(resource, data); + console.log(format); + // Returns the csv, xlsx format. if (format === ExportFormat.Csv || format === ExportFormat.Xlsx) { const exportableColumns = this.getExportableColumns(resourceColumns); @@ -66,7 +69,7 @@ export class ExportResourceService { return this.exportPdf.pdf( printableColumns, transformed, - resourceMeta?.print?.pageTitle + resourceMeta?.print?.pageTitle, ); } } @@ -102,14 +105,14 @@ export class ExportResourceService { */ private transformExportedData( resource: string, - data: Array> + data: Array>, ): Array> { const resourceMeta = this.getResourceMeta(resource); return R.when>, Array>>( R.always(Boolean(resourceMeta.exportFlattenOn)), (data) => flatDataCollections(data, resourceMeta.exportFlattenOn), - data + data, ); } /** @@ -119,10 +122,14 @@ export class ExportResourceService { * @returns A promise that resolves to the exportable data. */ private async getExportableData(resource: string) { - const exportable = - this.exportableResources.registry.getExportable(resource); - - return exportable.exportable({}); + const exportable = getExportableService(resource); + const contextId = ContextIdFactory.create(); + const exportableInstance = await this.moduleRef.resolve( + exportable, + contextId, + { strict: false }, + ); + return exportableInstance.exportable({}); } /** @@ -133,7 +140,7 @@ export class ExportResourceService { private getExportableColumns(resourceColumns: any) { const processColumns = ( columns: { [key: string]: IModelMetaColumn }, - parent = '' + parent = '', ) => { return Object.entries(columns) .filter(([_, value]) => value.exportable !== false) @@ -159,9 +166,10 @@ export class ExportResourceService { private getPrintableColumns(resourceMeta: IModelMeta) { const processColumns = ( columns: { [key: string]: IModelMetaColumn }, - parent = '' + parent = '', ) => { return Object.entries(columns) + // @ts-expect-error .filter(([_, value]) => value.printable !== false) .flatMap(([key, value]) => { if (value.type === 'collection' && value.collectionOf === 'object') { @@ -191,7 +199,7 @@ export class ExportResourceService { private createWorkbook(data: any[], exportableColumns: any[]) { const workbook = xlsx.utils.book_new(); const worksheetData = data.map((item) => - exportableColumns.map((col) => get(item, getDataAccessor(col))) + exportableColumns.map((col) => get(item, getDataAccessor(col))), ); worksheetData.unshift(exportableColumns.map((col) => col.name)); diff --git a/packages/server/src/modules/Export/dtos/ExportQuery.dto.ts b/packages/server/src/modules/Export/dtos/ExportQuery.dto.ts index 04d1eae67..da78d0869 100644 --- a/packages/server/src/modules/Export/dtos/ExportQuery.dto.ts +++ b/packages/server/src/modules/Export/dtos/ExportQuery.dto.ts @@ -4,8 +4,4 @@ export class ExportQuery { @IsString() @IsNotEmpty() resource: string; - - @IsString() - @IsNotEmpty() - format: string; } diff --git a/packages/server/src/modules/Import/Import.module.ts b/packages/server/src/modules/Import/Import.module.ts index 953f6ce4f..032e34508 100644 --- a/packages/server/src/modules/Import/Import.module.ts +++ b/packages/server/src/modules/Import/Import.module.ts @@ -12,11 +12,17 @@ import { ImportFileMapping } from './ImportFileMapping'; import { ImportFileDataValidator } from './ImportFileDataValidator'; import { ImportFileDataTransformer } from './ImportFileDataTransformer'; import { ImportFileCommon } from './ImportFileCommon'; +import { ImportableResources } from './ImportableResources'; +import { ResourceModule } from '../Resource/Resource.module'; +import { TenancyModule } from '../Tenancy/Tenancy.module'; +import { AccountsModule } from '../Accounts/Accounts.module'; @Module({ + imports: [ResourceModule, TenancyModule, AccountsModule], providers: [ ImportAls, ImportSampleService, + ImportableResources, ImportResourceApplication, ImportDeleteExpiredFiles, ImportFileUploadService, @@ -27,7 +33,7 @@ import { ImportFileCommon } from './ImportFileCommon'; ImportFileMapping, ImportFileDataValidator, ImportFileDataTransformer, - ImportFileCommon + ImportFileCommon, ], exports: [ImportAls], }) diff --git a/packages/server/src/modules/Import/ImportableResources.ts b/packages/server/src/modules/Import/ImportableResources.ts index 2a9bf0d35..a16c4306a 100644 --- a/packages/server/src/modules/Import/ImportableResources.ts +++ b/packages/server/src/modules/Import/ImportableResources.ts @@ -35,7 +35,7 @@ export class ImportableResources { // resource: 'UncategorizedCashflowTransaction', // importable: UncategorizedTransactionsImportable, // }, - // { resource: 'Customer', importable: CustomersImportable }, + // { resource: 'Customer', importable: CustomersImportable }, // { resource: 'Vendor', importable: VendorsImportable }, // { resource: 'Item', importable: ItemsImportable }, // { resource: 'ItemCategory', importable: ItemCategoriesImportable }, diff --git a/packages/server/src/modules/Import/_utils.ts b/packages/server/src/modules/Import/_utils.ts index 33f270705..63d58e25e 100644 --- a/packages/server/src/modules/Import/_utils.ts +++ b/packages/server/src/modules/Import/_utils.ts @@ -2,8 +2,8 @@ import * as Yup from 'yup'; import * as moment from 'moment'; import * as R from 'ramda'; import { Knex } from 'knex'; -import fs from 'fs/promises'; -import path from 'path'; +import * as fs from 'fs/promises'; +import * as path from 'path'; import { defaultTo, upperFirst, @@ -18,7 +18,7 @@ import { split, last, } from 'lodash'; -import pluralize from 'pluralize'; +import * as pluralize from 'pluralize'; import { ResourceMetaFieldsMap } from './interfaces'; import { multiNumberParse } from '@/utils/multi-number-parse'; import { ServiceError } from '../Items/ServiceError'; @@ -70,13 +70,13 @@ export const convertFieldsToYupValidation = (fields: ResourceMetaFieldsMap) => { if (!isUndefined(field.minLength)) { fieldSchema = fieldSchema.min( field.minLength, - `Minimum length is ${field.minLength} characters` + `Minimum length is ${field.minLength} characters`, ); } if (!isUndefined(field.maxLength)) { fieldSchema = fieldSchema.max( field.maxLength, - `Maximum length is ${field.maxLength} characters` + `Maximum length is ${field.maxLength} characters`, ); } } else if (field.fieldType === 'number') { @@ -106,7 +106,7 @@ export const convertFieldsToYupValidation = (fields: ResourceMetaFieldsMap) => { return true; } return moment(val, 'YYYY-MM-DD', true).isValid(); - } + }, ); } else if (field.fieldType === 'url') { fieldSchema = fieldSchema.url(); @@ -150,12 +150,12 @@ const parseFieldName = (fieldName: string, field: IModelMetaField) => { */ export const getUnmappedSheetColumns = (columns, mapping) => { return columns.filter( - (column) => !mapping.some((map) => map.from === column) + (column) => !mapping.some((map) => map.from === column), ); }; export const sanitizeResourceName = (resourceName: string) => { - return upperFirst(camelCase(pluralize.singular(resourceName))); + return upperFirst(camelCase(pluralize(resourceName, 1))); }; export const getSheetColumns = (sheetData: unknown[]) => { @@ -171,11 +171,11 @@ export const getSheetColumns = (sheetData: unknown[]) => { */ export const getUniqueImportableValue = ( importableFields: { [key: string]: IModelMetaField2 }, - objectDTO: Record + objectDTO: Record, ) => { const uniqueImportableValue = pickBy( importableFields, - (field) => field.unique + (field) => field.unique, ); const uniqueImportableKeys = Object.keys(uniqueImportableValue); const uniqueImportableKey = first(uniqueImportableKeys); @@ -255,7 +255,7 @@ export const getResourceColumns = (resourceColumns: { (group: string) => ([fieldKey, { name, importHint, required, order, ...field }]: [ string, - IModelMetaField2 + IModelMetaField2, ]) => { const extra: Record = {}; const key = fieldKey; @@ -300,7 +300,7 @@ export const valueParser = // Parses the enumeration value. } else if (field.fieldType === 'enumeration') { const option = get(field, 'options', []).find( - (option) => option.label?.toLowerCase() === value?.toLowerCase() + (option) => option.label?.toLowerCase() === value?.toLowerCase(), ); _value = get(option, 'key'); // Parses the numeric value. @@ -356,7 +356,7 @@ export const parseKey = R.curry( } } return _key; - } + }, ); /** @@ -399,11 +399,11 @@ export const getFieldKey = (input: string) => { export function aggregate( input: Array, comparatorAttr: string, - groupOn: string + groupOn: string, ): Array> { return input.reduce((acc, curr) => { const existingEntry = acc.find( - (entry) => entry[comparatorAttr] === curr[comparatorAttr] + (entry) => entry[comparatorAttr] === curr[comparatorAttr], ); if (existingEntry) { diff --git a/packages/server/src/modules/ItemCategories/models/ItemCategory.meta.ts b/packages/server/src/modules/ItemCategories/models/ItemCategory.meta.ts new file mode 100644 index 000000000..8d14fc9d1 --- /dev/null +++ b/packages/server/src/modules/ItemCategories/models/ItemCategory.meta.ts @@ -0,0 +1,64 @@ + + +export const ItemCategoryMeta = { + defaultFilterField: 'name', + defaultSort: { + sortField: 'name', + sortOrder: 'DESC', + }, + importable: true, + exportable: true, + fields: { + name: { + name: 'item_category.field.name', + column: 'name', + fieldType: 'text', + }, + description: { + name: 'item_category.field.description', + column: 'description', + fieldType: 'text', + }, + count: { + name: 'item_category.field.count', + column: 'count', + fieldType: 'number', + virtualColumn: true, + }, + created_at: { + name: 'item_category.field.created_at', + column: 'created_at', + columnType: 'date', + }, + }, + columns: { + name: { + name: 'item_category.field.name', + type: 'text', + }, + description: { + name: 'item_category.field.description', + type: 'text', + }, + count: { + name: 'item_category.field.count', + type: 'text', + }, + createdAt: { + name: 'item_category.field.created_at', + type: 'text', + }, + }, + fields2: { + name: { + name: 'item_category.field.name', + column: 'name', + fieldType: 'text', + }, + description: { + name: 'item_category.field.description', + column: 'description', + fieldType: 'text', + }, + }, +}; \ No newline at end of file diff --git a/packages/server/src/modules/ItemCategories/models/ItemCategory.model.ts b/packages/server/src/modules/ItemCategories/models/ItemCategory.model.ts index 8fbfafbbb..a75803403 100644 --- a/packages/server/src/modules/ItemCategories/models/ItemCategory.model.ts +++ b/packages/server/src/modules/ItemCategories/models/ItemCategory.model.ts @@ -1,8 +1,11 @@ +import { Model } from 'objection'; import { ExportableModel } from '@/modules/Export/decorators/ExportableModel.decorator'; import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel'; -import { Model } from 'objection'; +import { InjectModelMeta } from '@/modules/Tenancy/TenancyModels/decorators/InjectModelMeta.decorator'; +import { ItemCategoryMeta } from './ItemCategory.meta'; @ExportableModel() +@InjectModelMeta(ItemCategoryMeta) export class ItemCategory extends TenantBaseModel { name!: string; description!: string; diff --git a/packages/server/src/modules/Items/models/Item.meta.ts b/packages/server/src/modules/Items/models/Item.meta.ts new file mode 100644 index 000000000..d2aefb23e --- /dev/null +++ b/packages/server/src/modules/Items/models/Item.meta.ts @@ -0,0 +1,309 @@ +export const ItemMeta = { + importable: true, + exportable: true, + defaultFilterField: 'name', + defaultSort: { + sortField: 'name', + sortOrder: 'DESC', + }, + print: { + pageTitle: 'Items', + }, + fields: { + type: { + name: 'item.field.type', + column: 'type', + fieldType: 'enumeration', + options: [ + { key: 'inventory', label: 'item.field.type.inventory' }, + { key: 'service', label: 'item.field.type.service' }, + { key: 'non-inventory', label: 'item.field.type.non-inventory' }, + ], + }, + name: { + name: 'item.field.name', + column: 'name', + fieldType: 'text', + }, + code: { + name: 'item.field.code', + column: 'code', + fieldType: 'text', + }, + sellable: { + name: 'item.field.sellable', + column: 'sellable', + fieldType: 'boolean', + }, + purchasable: { + name: 'item.field.purchasable', + column: 'purchasable', + fieldType: 'boolean', + }, + sell_price: { + name: 'item.field.sell_price', + column: 'sell_price', + fieldType: 'number', + }, + cost_price: { + name: 'item.field.cost_price', + column: 'cost_price', + fieldType: 'number', + }, + cost_account: { + name: 'item.field.cost_account', + column: 'cost_account_id', + fieldType: 'relation', + + relationType: 'enumeration', + relationKey: 'costAccount', + + relationEntityLabel: 'name', + relationEntityKey: 'slug', + }, + sell_account: { + name: 'item.field.sell_account', + column: 'sell_account_id', + fieldType: 'relation', + + relationType: 'enumeration', + relationKey: 'sellAccount', + + relationEntityLabel: 'name', + relationEntityKey: 'slug', + }, + inventory_account: { + name: 'item.field.inventory_account', + column: 'inventory_account_id', + + relationType: 'enumeration', + relationKey: 'inventoryAccount', + + relationEntityLabel: 'name', + relationEntityKey: 'slug', + }, + sell_description: { + name: 'Sell description', + column: 'sell_description', + fieldType: 'text', + }, + purchase_description: { + name: 'Purchase description', + column: 'purchase_description', + fieldType: 'text', + }, + quantity_on_hand: { + name: 'item.field.quantity_on_hand', + column: 'quantity_on_hand', + fieldType: 'number', + }, + note: { + name: 'item.field.note', + column: 'note', + fieldType: 'text', + }, + category: { + name: 'item.field.category', + column: 'category_id', + + relationType: 'enumeration', + relationKey: 'category', + + relationEntityLabel: 'name', + relationEntityKey: 'id', + }, + active: { + name: 'item.field.active', + column: 'active', + fieldType: 'boolean', + filterable: false, + }, + created_at: { + name: 'item.field.created_at', + column: 'created_at', + columnType: 'date', + fieldType: 'date', + }, + }, + columns: { + type: { + name: 'item.field.type', + type: 'text', + exportable: true, + accessor: 'typeFormatted', + }, + name: { + name: 'item.field.name', + type: 'text', + exportable: true, + }, + code: { + name: 'item.field.code', + type: 'text', + exportable: true, + }, + sellable: { + name: 'item.field.sellable', + type: 'boolean', + exportable: true, + printable: false, + }, + purchasable: { + name: 'item.field.purchasable', + type: 'boolean', + exportable: true, + printable: false, + }, + sellPrice: { + name: 'item.field.sell_price', + type: 'number', + exportable: true, + }, + costPrice: { + name: 'item.field.cost_price', + type: 'number', + exportable: true, + }, + costAccount: { + name: 'item.field.cost_account', + type: 'text', + accessor: 'costAccount.name', + exportable: true, + printable: false, + }, + sellAccount: { + name: 'item.field.sell_account', + type: 'text', + accessor: 'sellAccount.name', + exportable: true, + printable: false, + }, + inventoryAccount: { + name: 'item.field.inventory_account', + type: 'text', + accessor: 'inventoryAccount.name', + exportable: true, + }, + sellDescription: { + name: 'Sell description', + type: 'text', + exportable: true, + printable: false, + }, + purchaseDescription: { + name: 'Purchase description', + type: 'text', + exportable: true, + printable: false, + }, + quantityOnHand: { + name: 'item.field.quantity_on_hand', + type: 'number', + exportable: true, + }, + note: { + name: 'item.field.note', + type: 'text', + exportable: true, + }, + category: { + name: 'item.field.category', + type: 'text', + accessor: 'category.name', + exportable: true, + }, + active: { + name: 'item.field.active', + fieldType: 'boolean', + exportable: true, + printable: false, + }, + createdAt: { + name: 'item.field.created_at', + type: 'date', + exportable: true, + printable: false, + }, + }, + fields2: { + type: { + name: 'item.field.type', + fieldType: 'enumeration', + options: [ + { key: 'inventory', label: 'item.field.type.inventory' }, + { key: 'service', label: 'item.field.type.service' }, + { key: 'non-inventory', label: 'item.field.type.non-inventory' }, + ], + required: true, + }, + name: { + name: 'item.field.name', + fieldType: 'text', + required: true, + }, + code: { + name: 'item.field.code', + fieldType: 'text', + }, + sellable: { + name: 'item.field.sellable', + fieldType: 'boolean', + }, + purchasable: { + name: 'item.field.purchasable', + fieldType: 'boolean', + }, + sellPrice: { + name: 'item.field.sell_price', + fieldType: 'number', + }, + costPrice: { + name: 'item.field.cost_price', + fieldType: 'number', + }, + costAccountId: { + name: 'item.field.cost_account', + fieldType: 'relation', + relationModel: 'Account', + relationImportMatch: ['name', 'code'], + importHint: 'Matches the account name or code.', + }, + sellAccountId: { + name: 'item.field.sell_account', + fieldType: 'relation', + relationModel: 'Account', + relationImportMatch: ['name', 'code'], + importHint: 'Matches the account name or code.', + }, + inventoryAccountId: { + name: 'item.field.inventory_account', + fieldType: 'relation', + relationModel: 'Account', + relationImportMatch: ['name', 'code'], + importHint: 'Matches the account name or code.', + }, + sellDescription: { + name: 'Sell Description', + fieldType: 'text', + }, + purchaseDescription: { + name: 'Purchase Description', + fieldType: 'text', + }, + note: { + name: 'item.field.note', + fieldType: 'text', + }, + categoryId: { + name: 'item.field.category', + fieldType: 'relation', + relationModel: 'ItemCategory', + relationImportMatch: ['name'], + importHint: 'Matches the category name.', + }, + active: { + name: 'item.field.active', + fieldType: 'boolean', + }, + }, +}; \ No newline at end of file diff --git a/packages/server/src/modules/Items/models/Item.ts b/packages/server/src/modules/Items/models/Item.ts index 3b7f33cd4..39227a0e0 100644 --- a/packages/server/src/modules/Items/models/Item.ts +++ b/packages/server/src/modules/Items/models/Item.ts @@ -2,8 +2,11 @@ import { Warehouse } from '@/modules/Warehouses/models/Warehouse.model'; import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel'; import { Model } from 'objection'; import { ExportableModel } from '@/modules/Export/decorators/ExportableModel.decorator'; +import { InjectModelMeta } from '@/modules/Tenancy/TenancyModels/decorators/InjectModelMeta.decorator'; +import { ItemMeta } from './Item.meta'; @ExportableModel() +@InjectModelMeta(ItemMeta) export class Item extends TenantBaseModel { public readonly quantityOnHand: number; public readonly name: string; diff --git a/packages/server/src/modules/ManualJournals/ManualJournals.module.ts b/packages/server/src/modules/ManualJournals/ManualJournals.module.ts index 1ca42131c..2b2a8c773 100644 --- a/packages/server/src/modules/ManualJournals/ManualJournals.module.ts +++ b/packages/server/src/modules/ManualJournals/ManualJournals.module.ts @@ -17,9 +17,11 @@ import { ManualJournalGLEntries } from './commands/ManualJournalGLEntries'; import { LedgerModule } from '../Ledger/Ledger.module'; import { ManualJournalsExportable } from './commands/ManualJournalExportable'; import { ManualJournalImportable } from './commands/ManualJournalsImport'; +import { GetManualJournals } from './queries/GetManualJournals.service'; +import { DynamicListModule } from '../DynamicListing/DynamicList.module'; @Module({ - imports: [BranchesModule, LedgerModule], + imports: [BranchesModule, LedgerModule, DynamicListModule], controllers: [ManualJournalsController], providers: [ TenancyContext, @@ -34,6 +36,7 @@ import { ManualJournalImportable } from './commands/ManualJournalsImport'; AutoIncrementOrdersService, ManualJournalsApplication, GetManualJournal, + GetManualJournals, ManualJournalGLEntries, ManualJournalWriteGLSubscriber, ManualJournalsExportable, diff --git a/packages/server/src/modules/ManualJournals/models/ManualJournal.meta.ts b/packages/server/src/modules/ManualJournals/models/ManualJournal.meta.ts new file mode 100644 index 000000000..352dccd26 --- /dev/null +++ b/packages/server/src/modules/ManualJournals/models/ManualJournal.meta.ts @@ -0,0 +1,230 @@ +export const ManualJournalMeta = { + defaultFilterField: 'date', + defaultSort: { + sortOrder: 'DESC', + sortField: 'name', + }, + importable: true, + exportFlattenOn: 'entries', + + exportable: true, + importAggregator: 'group', + importAggregateOn: 'entries', + importAggregateBy: 'journalNumber', + + print: { + pageTitle: 'Manual Journals', + }, + + fields: { + date: { + name: 'manual_journal.field.date', + column: 'date', + fieldType: 'date', + }, + journal_number: { + name: 'manual_journal.field.journal_number', + column: 'journal_number', + fieldType: 'text', + }, + reference: { + name: 'manual_journal.field.reference', + column: 'reference', + fieldType: 'text', + }, + journal_type: { + name: 'manual_journal.field.journal_type', + column: 'journal_type', + fieldType: 'text', + }, + amount: { + name: 'manual_journal.field.amount', + column: 'amount', + fieldType: 'number', + }, + description: { + name: 'manual_journal.field.description', + column: 'description', + fieldType: 'text', + }, + status: { + name: 'manual_journal.field.status', + column: 'status', + fieldType: 'enumeration', + options: [ + { key: 'draft', label: 'Draft' }, + { key: 'published', label: 'published' }, + ], + filterCustomQuery: StatusFieldFilterQuery, + sortCustomQuery: StatusFieldSortQuery, + }, + created_at: { + name: 'manual_journal.field.created_at', + column: 'created_at', + fieldType: 'date', + }, + }, + columns: { + date: { + name: 'manual_journal.field.date', + type: 'date', + accessor: 'formattedDate', + }, + journalNumber: { + name: 'manual_journal.field.journal_number', + type: 'text', + }, + reference: { + name: 'manual_journal.field.reference', + type: 'text', + }, + journalType: { + name: 'manual_journal.field.journal_type', + type: 'text', + }, + amount: { + name: 'Amount', + accessor: 'formattedAmount', + }, + currencyCode: { + name: 'manual_journal.field.currency', + type: 'text', + printable: false, + }, + exchangeRate: { + name: 'manual_journal.field.exchange_rate', + type: 'number', + printable: false, + }, + description: { + name: 'manual_journal.field.description', + type: 'text', + }, + entries: { + name: 'Entries', + type: 'collection', + collectionOf: 'object', + columns: { + credit: { + name: 'Credit', + type: 'text', + }, + debit: { + name: 'Debit', + type: 'text', + }, + account: { + name: 'Account', + accessor: 'account.name', + }, + contact: { + name: 'Contact', + accessor: 'contact.displayName', + }, + note: { + name: 'Note', + }, + }, + publish: { + name: 'Publish', + type: 'boolean', + printable: false, + }, + publishedAt: { + name: 'Published At', + printable: false, + }, + }, + createdAt: { + name: 'Created At', + accessor: 'formattedCreatedAt', + printable: false, + }, + }, + fields2: { + date: { + name: 'manual_journal.field.date', + fieldType: 'date', + required: true, + }, + journalNumber: { + name: 'manual_journal.field.journal_number', + fieldType: 'text', + required: true, + }, + reference: { + name: 'manual_journal.field.reference', + fieldType: 'text', + }, + journalType: { + name: 'manual_journal.field.journal_type', + fieldType: 'text', + }, + currencyCode: { + name: 'manual_journal.field.currency', + fieldType: 'text', + }, + exchange_rate: { + name: 'manual_journal.field.exchange_rate', + fieldType: 'number', + }, + description: { + name: 'manual_journal.field.description', + fieldType: 'text', + }, + entries: { + name: 'Entries', + fieldType: 'collection', + collectionOf: 'object', + collectionMinLength: 2, + required: true, + fields: { + credit: { + name: 'Credit', + fieldType: 'number', + required: true, + }, + debit: { + name: 'Debit', + fieldType: 'number', + required: true, + }, + accountId: { + name: 'Account', + fieldType: 'relation', + relationModel: 'Account', + relationImportMatch: ['name', 'code'], + required: true, + }, + contact: { + name: 'Contact', + fieldType: 'relation', + relationModel: 'Contact', + relationImportMatch: 'displayName', + }, + note: { + name: 'Note', + fieldType: 'text', + }, + }, + }, + publish: { + name: 'Publish', + fieldType: 'boolean', + }, + }, +}; + +/** + * Status field sorting custom query. + */ +function StatusFieldSortQuery(query, role) { + return query.modify('sortByStatus', role.order); +} + +/** + * Status field filter custom query. + */ +function StatusFieldFilterQuery(query, role) { + query.modify('filterByStatus', role.value); +} \ No newline at end of file diff --git a/packages/server/src/modules/ManualJournals/models/ManualJournal.ts b/packages/server/src/modules/ManualJournals/models/ManualJournal.ts index e9e1b1077..a8c0e78ef 100644 --- a/packages/server/src/modules/ManualJournals/models/ManualJournal.ts +++ b/packages/server/src/modules/ManualJournals/models/ManualJournal.ts @@ -10,8 +10,11 @@ import { ManualJournalEntry } from './ManualJournalEntry'; import { Document } from '@/modules/ChromiumlyTenancy/models/Document'; import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel'; import { ExportableModel } from '@/modules/Export/decorators/ExportableModel.decorator'; +import { InjectModelMeta } from '@/modules/Tenancy/TenancyModels/decorators/InjectModelMeta.decorator'; +import { ManualJournalMeta } from './ManualJournal.meta'; @ExportableModel() +@InjectModelMeta(ManualJournalMeta) export class ManualJournal extends TenantBaseModel { date: Date; journalNumber: string; diff --git a/packages/server/src/modules/Resource/Resource.module.ts b/packages/server/src/modules/Resource/Resource.module.ts index e4e3ae54f..297d27414 100644 --- a/packages/server/src/modules/Resource/Resource.module.ts +++ b/packages/server/src/modules/Resource/Resource.module.ts @@ -1,7 +1,12 @@ import { Module } from '@nestjs/common'; import { ResourceService } from './ResourceService'; +import { BranchesModule } from '../Branches/Branches.module'; +import { WarehousesModule } from '../Warehouses/Warehouses.module'; +import { AccountsExportable } from '../Accounts/AccountsExportable.service'; +import { AccountsModule } from '../Accounts/Accounts.module'; @Module({ + imports: [BranchesModule, WarehousesModule, AccountsModule], providers: [ResourceService], exports: [ResourceService], }) diff --git a/packages/server/src/modules/Resource/ResourceService.ts b/packages/server/src/modules/Resource/ResourceService.ts index a59fbb522..f45474648 100644 --- a/packages/server/src/modules/Resource/ResourceService.ts +++ b/packages/server/src/modules/Resource/ResourceService.ts @@ -28,7 +28,7 @@ export class ResourceService { */ public getResourceModel(inputModelName: string) { const modelName = resourceToModelName(inputModelName); - const resourceModel = this.moduleRef.get(modelName); + const resourceModel = this.moduleRef.get(modelName, { strict: false }); if (!resourceModel) { throw new ServiceError(ERRORS.RESOURCE_MODEL_NOT_FOUND); @@ -46,7 +46,7 @@ export class ResourceService { const resourceModel = this.getResourceModel(modelName); // Retrieve the resource meta. - const resourceMeta = resourceModel.getMeta(metakey); + const resourceMeta = resourceModel().getMeta(metakey); // Localization the fields names. return resourceMeta; diff --git a/packages/server/src/modules/Resource/_utils.ts b/packages/server/src/modules/Resource/_utils.ts index bd88a6a1c..b934433ea 100644 --- a/packages/server/src/modules/Resource/_utils.ts +++ b/packages/server/src/modules/Resource/_utils.ts @@ -1,5 +1,5 @@ import { camelCase, upperFirst } from 'lodash'; -import pluralize from 'pluralize'; +import * as pluralize from 'pluralize'; export const resourceToModelName = (resourceName: string): string => { return upperFirst(camelCase(pluralize.singular(resourceName))); diff --git a/packages/server/src/modules/SaleInvoices/models/SaleInvoice.meta.ts b/packages/server/src/modules/SaleInvoices/models/SaleInvoice.meta.ts new file mode 100644 index 000000000..8d48e5e21 --- /dev/null +++ b/packages/server/src/modules/SaleInvoices/models/SaleInvoice.meta.ts @@ -0,0 +1,316 @@ +import { Features } from "@/common/types/Features"; + +export const SaleInvoiceMeta = { + defaultFilterField: 'customer', + defaultSort: { + sortOrder: 'DESC', + sortField: 'created_at', + }, + exportable: true, + exportFlattenOn: 'entries', + + importable: true, + importAggregator: 'group', + importAggregateOn: 'entries', + importAggregateBy: 'invoiceNo', + + print: { + pageTitle: 'Sale invoices', + }, + fields: { + customer: { + name: 'invoice.field.customer', + column: 'customer_id', + fieldType: 'relation', + + relationType: 'enumeration', + relationKey: 'customer', + + relationEntityLabel: 'display_name', + relationEntityKey: 'id', + }, + invoice_date: { + name: 'invoice.field.invoice_date', + column: 'invoice_date', + fieldType: 'date', + }, + due_date: { + name: 'invoice.field.due_date', + column: 'due_date', + fieldType: 'date', + }, + invoice_no: { + name: 'invoice.field.invoice_no', + column: 'invoice_no', + fieldType: 'text', + }, + reference_no: { + name: 'invoice.field.reference_no', + column: 'reference_no', + fieldType: 'text', + }, + invoice_message: { + name: 'invoice.field.invoice_message', + column: 'invoice_message', + fieldType: 'text', + }, + terms_conditions: { + name: 'invoice.field.terms_conditions', + column: 'terms_conditions', + fieldType: 'text', + }, + amount: { + name: 'invoice.field.amount', + column: 'balance', + fieldType: 'number', + }, + payment_amount: { + name: 'invoice.field.payment_amount', + column: 'payment_amount', + fieldType: 'number', + }, + due_amount: { + // calculated. + name: 'invoice.field.due_amount', + column: 'due_amount', + fieldType: 'number', + virtualColumn: true, + }, + status: { + name: 'invoice.field.status', + fieldType: 'enumeration', + options: [ + { key: 'draft', label: 'invoice.field.status.draft' }, + { key: 'delivered', label: 'invoice.field.status.delivered' }, + { key: 'unpaid', label: 'invoice.field.status.unpaid' }, + { key: 'overdue', label: 'invoice.field.status.overdue' }, + { key: 'partially-paid', label: 'invoice.field.status.partially-paid' }, + { key: 'paid', label: 'invoice.field.status.paid' }, + ], + filterCustomQuery: StatusFieldFilterQuery, + sortCustomQuery: StatusFieldSortQuery, + }, + created_at: { + name: 'invoice.field.created_at', + column: 'created_at', + fieldType: 'date', + }, + }, + columns: { + invoiceDate: { + name: 'invoice.field.invoice_date', + type: 'date', + accessor: 'invoiceDateFormatted', + }, + dueDate: { + name: 'invoice.field.due_date', + type: 'date', + accessor: 'dueDateFormatted', + }, + referenceNo: { + name: 'invoice.field.reference_no', + type: 'text', + }, + invoiceNo: { + name: 'invoice.field.invoice_no', + type: 'text', + }, + customer: { + name: 'invoice.field.customer', + type: 'text', + accessor: 'customer.displayName', + }, + amount: { + name: 'invoice.field.amount', + type: 'text', + accessor: 'balanceAmountFormatted', + }, + exchangeRate: { + name: 'invoice.field.exchange_rate', + type: 'number', + printable: false, + }, + currencyCode: { + name: 'invoice.field.currency', + type: 'text', + printable: false, + }, + paidAmount: { + name: 'Paid Amount', + accessor: 'paymentAmountFormatted', + }, + dueAmount: { + name: 'Due Amount', + accessor: 'dueAmountFormatted', + }, + invoiceMessage: { + name: 'invoice.field.invoice_message', + type: 'text', + printable: false, + }, + termsConditions: { + name: 'invoice.field.terms_conditions', + type: 'text', + printable: false, + }, + delivered: { + name: 'invoice.field.delivered', + type: 'boolean', + printable: false, + accessor: 'isDelivered', + }, + entries: { + name: 'Entries', + accessor: 'entries', + type: 'collection', + collectionOf: 'object', + columns: { + itemName: { + name: 'Item Name', + accessor: 'item.name', + }, + rate: { + name: 'Item Rate', + accessor: 'rateFormatted', + }, + quantity: { + name: 'Item Quantity', + accessor: 'quantityFormatted', + }, + description: { + name: 'Item Description', + printable: false, + }, + amount: { + name: 'Item Amount', + accessor: 'totalFormatted', + }, + }, + }, + branch: { + name: 'Branch', + type: 'text', + accessor: 'branch.name', + features: [Features.BRANCHES], + }, + warehouse: { + name: 'Warehouse', + type: 'text', + accessor: 'warehouse.name', + features: [Features.BRANCHES], + }, + }, + fields2: { + invoiceDate: { + name: 'invoice.field.invoice_date', + fieldType: 'date', + required: true, + }, + dueDate: { + name: 'invoice.field.due_date', + fieldType: 'date', + required: true, + }, + referenceNo: { + name: 'invoice.field.reference_no', + fieldType: 'text', + }, + invoiceNo: { + name: 'invoice.field.invoice_no', + fieldType: 'text', + }, + customerId: { + name: 'invoice.field.customer', + fieldType: 'relation', + relationModel: 'Contact', + relationImportMatch: 'displayName', + required: true, + }, + exchangeRate: { + name: 'invoice.field.exchange_rate', + fieldType: 'number', + printable: false, + }, + currencyCode: { + name: 'invoice.field.currency', + fieldType: 'text', + printable: false, + }, + invoiceMessage: { + name: 'invoice.field.invoice_message', + fieldType: 'text', + printable: false, + }, + termsConditions: { + name: 'invoice.field.terms_conditions', + fieldType: 'text', + printable: false, + }, + entries: { + name: 'invoice.field.entries', + fieldType: 'collection', + collectionOf: 'object', + collectionMinLength: 1, + required: true, + fields: { + itemId: { + name: 'invoice.field.item_name', + fieldType: 'relation', + relationModel: 'Item', + relationImportMatch: ['name', 'code'], + required: true, + importHint: 'Matches the item name or code.', + }, + rate: { + name: 'invoice.field.rate', + fieldType: 'number', + required: true, + }, + quantity: { + name: 'invoice.field.quantity', + fieldType: 'number', + required: true, + }, + description: { + name: 'invoice.field.description', + fieldType: 'text', + }, + }, + }, + delivered: { + name: 'invoice.field.delivered', + fieldType: 'boolean', + printable: false, + }, + branchId: { + name: 'Branch', + fieldType: 'relation', + relationModel: 'Branch', + relationImportMatch: ['name', 'code'], + features: [Features.BRANCHES], + required: true, + }, + warehouseId: { + name: 'Warehouse', + fieldType: 'relation', + relationModel: 'Warehouse', + relationImportMatch: ['name', 'code'], + features: [Features.WAREHOUSES], + required: true, + }, + }, +}; + +/** + * Status field filter custom query. + */ +function StatusFieldFilterQuery(query, role) { + query.modify('statusFilter', role.value); +} + +/** + * Status field sort custom query. + */ +function StatusFieldSortQuery(query, role) { + query.modify('sortByStatus', role.order); +} \ No newline at end of file diff --git a/packages/server/src/modules/SaleInvoices/models/SaleInvoice.ts b/packages/server/src/modules/SaleInvoices/models/SaleInvoice.ts index c7d490eb8..ad3bbdd63 100644 --- a/packages/server/src/modules/SaleInvoices/models/SaleInvoice.ts +++ b/packages/server/src/modules/SaleInvoices/models/SaleInvoice.ts @@ -11,13 +11,15 @@ 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'; -import { PaymentIntegrationTransactionLink } from '../SaleInvoice.types'; import { TransactionPaymentServiceEntry } from '@/modules/PaymentServices/models/TransactionPaymentServiceEntry.model'; import { InjectAttachable } from '@/modules/Attachments/decorators/InjectAttachable.decorator'; import { ExportableModel } from '@/modules/Export/decorators/ExportableModel.decorator'; +import { InjectModelMeta } from '@/modules/Tenancy/TenancyModels/decorators/InjectModelMeta.decorator'; +import { SaleInvoiceMeta } from './SaleInvoice.meta'; @InjectAttachable() @ExportableModel() +@InjectModelMeta(SaleInvoiceMeta) export class SaleInvoice extends TenantBaseModel{ public taxAmountWithheld: number; public balance: number; diff --git a/packages/server/src/modules/Tenancy/TenancyModels/Tenancy.module.ts b/packages/server/src/modules/Tenancy/TenancyModels/Tenancy.module.ts index 66f3e1b40..66fa82478 100644 --- a/packages/server/src/modules/Tenancy/TenancyModels/Tenancy.module.ts +++ b/packages/server/src/modules/Tenancy/TenancyModels/Tenancy.module.ts @@ -82,6 +82,7 @@ const models = [ TenantUser, ]; + /** * Decorator factory that registers a model with the tenancy system. * @param model The model class to register diff --git a/packages/server/src/modules/Tenancy/TenancyModels/decorators/InjectModelMeta.decorator.ts b/packages/server/src/modules/Tenancy/TenancyModels/decorators/InjectModelMeta.decorator.ts new file mode 100644 index 000000000..9c0793be2 --- /dev/null +++ b/packages/server/src/modules/Tenancy/TenancyModels/decorators/InjectModelMeta.decorator.ts @@ -0,0 +1,18 @@ + +/** + * Decorator function that adds metadata to the model class. + * @param value - The metadata value to be added to the model. + * @returns A class decorator function. + */ +export function InjectModelMeta(value: any) { + return function(target: any) { + // Define a static getter for 'meta' on the target class + Object.defineProperty(target, 'meta', { + get: function() { + return value; + }, + enumerable: true, + configurable: true + }); + }; +} \ No newline at end of file diff --git a/packages/server/src/modules/Vendors/models/Vendor.meta.ts b/packages/server/src/modules/Vendors/models/Vendor.meta.ts new file mode 100644 index 000000000..90411934f --- /dev/null +++ b/packages/server/src/modules/Vendors/models/Vendor.meta.ts @@ -0,0 +1,407 @@ +export const VendorMeta = { + defaultFilterField: 'displayName', + defaultSort: { + sortOrder: 'DESC', + sortField: 'created_at', + }, + importable: true, + exportable: true, + fields: { + first_name: { + name: 'vendor.field.first_name', + column: 'first_name', + fieldType: 'text', + }, + last_name: { + name: 'vendor.field.last_name', + column: 'last_name', + fieldType: 'text', + }, + display_name: { + name: 'vendor.field.display_name', + column: 'display_name', + fieldType: 'text', + }, + email: { + name: 'vendor.field.email', + column: 'email', + fieldType: 'text', + }, + work_phone: { + name: 'vendor.field.work_phone', + column: 'work_phone', + fieldType: 'text', + }, + personal_phone: { + name: 'vendor.field.personal_phone', + column: 'personal_phone', + fieldType: 'text', + }, + company_name: { + name: 'vendor.field.company_name', + column: 'company_name', + fieldType: 'text', + }, + website: { + name: 'vendor.field.website', + column: 'website', + fieldType: 'text', + }, + created_at: { + name: 'vendor.field.created_at', + column: 'created_at', + fieldType: 'date', + }, + balance: { + name: 'vendor.field.balance', + column: 'balance', + fieldType: 'number', + }, + opening_balance: { + name: 'vendor.field.opening_balance', + column: 'opening_balance', + fieldType: 'number', + }, + opening_balance_at: { + name: 'vendor.field.opening_balance_at', + column: 'opening_balance_at', + fieldType: 'date', + }, + currency_code: { + name: 'vendor.field.currency', + column: 'currency_code', + fieldType: 'text', + }, + status: { + name: 'vendor.field.status', + type: 'enumeration', + options: [ + { key: 'overdue', label: 'vendor.field.status.overdue' }, + { key: 'unpaid', label: 'vendor.field.status.unpaid' }, + ], + filterCustomQuery: (query, role) => { + switch (role.value) { + case 'overdue': + query.modify('overdue'); + break; + case 'unpaid': + query.modify('unpaid'); + break; + } + }, + }, + }, + columns: { + firstName: { + name: 'vendor.field.first_name', + type: 'text', + }, + lastName: { + name: 'vendor.field.last_name', + type: 'text', + }, + displayName: { + name: 'vendor.field.display_name', + type: 'text', + }, + email: { + name: 'vendor.field.email', + type: 'text', + }, + workPhone: { + name: 'vendor.field.work_phone', + type: 'text', + }, + personalPhone: { + name: 'vendor.field.personal_phone', + type: 'text', + }, + companyName: { + name: 'vendor.field.company_name', + type: 'text', + }, + website: { + name: 'vendor.field.website', + type: 'text', + }, + balance: { + name: 'vendor.field.balance', + type: 'number', + }, + openingBalance: { + name: 'vendor.field.opening_balance', + type: 'number', + printable: false + }, + openingBalanceAt: { + name: 'vendor.field.opening_balance_at', + type: 'date', + printable: false + }, + currencyCode: { + name: 'vendor.field.currency', + type: 'text', + printable: false + }, + status: { + name: 'vendor.field.status', + printable: false + }, + note: { + name: 'vendor.field.note', + type: 'text', + printable: false + }, + // Billing Address + billingAddress1: { + name: 'Billing Address 1', + column: 'billing_address1', + type: 'text', + exportable: true, + printable: false + }, + billingAddress2: { + name: 'Billing Address 2', + column: 'billing_address2', + type: 'text', + exportable: true, + printable: false + }, + billingAddressCity: { + name: 'Billing Address City', + column: 'billing_address_city', + type: 'text', + exportable: true, + printable: false + }, + billingAddressCountry: { + name: 'Billing Address Country', + column: 'billing_address_country', + type: 'text', + exportable: true, + printable: false + }, + billingAddressPostcode: { + name: 'Billing Address Postcode', + column: 'billing_address_postcode', + type: 'text', + exportable: true, + printable: false + }, + billingAddressState: { + name: 'Billing Address State', + column: 'billing_address_state', + type: 'text', + exportable: true, + printable: false + }, + billingAddressPhone: { + name: 'Billing Address Phone', + column: 'billing_address_phone', + type: 'text', + exportable: true, + printable: false + }, + // Shipping Address + shippingAddress1: { + name: 'Shipping Address 1', + column: 'shipping_address1', + type: 'text', + exportable: true, + printable: false + }, + shippingAddress2: { + name: 'Shipping Address 2', + column: 'shipping_address2', + type: 'text', + exportable: true, + printable: false + }, + shippingAddressCity: { + name: 'Shipping Address City', + column: 'shipping_address_city', + type: 'text', + exportable: true, + printable: false + }, + shippingAddressCountry: { + name: 'Shipping Address Country', + column: 'shipping_address_country', + type: 'text', + exportable: true, + printable: false + }, + shippingAddressPostcode: { + name: 'Shipping Address Postcode', + column: 'shipping_address_postcode', + type: 'text', + exportable: true, + printable: false + }, + shippingAddressState: { + name: 'Shipping Address State', + column: 'shipping_address_state', + type: 'text', + exportable: true, + printable: false + }, + shippingAddressPhone: { + name: 'Shipping Address Phone', + column: 'shipping_address_phone', + type: 'text', + exportable: true, + printable: false + }, + createdAt: { + name: 'vendor.field.created_at', + type: 'date', + exportable: true, + printable: false + }, + }, + fields2: { + firstName: { + name: 'vendor.field.first_name', + column: 'first_name', + fieldType: 'text', + }, + lastName: { + name: 'vendor.field.last_name', + column: 'last_name', + fieldType: 'text', + }, + displayName: { + name: 'vendor.field.display_name', + column: 'display_name', + fieldType: 'text', + required: true, + }, + email: { + name: 'vendor.field.email', + column: 'email', + fieldType: 'text', + }, + workPhone: { + name: 'vendor.field.work_phone', + column: 'work_phone', + fieldType: 'text', + }, + personalPhone: { + name: 'vendor.field.personal_phone', + column: 'personal_phone', + fieldType: 'text', + }, + companyName: { + name: 'vendor.field.company_name', + column: 'company_name', + fieldType: 'text', + }, + website: { + name: 'vendor.field.website', + column: 'website', + fieldType: 'text', + }, + openingBalance: { + name: 'vendor.field.opening_balance', + column: 'opening_balance', + fieldType: 'number', + }, + openingBalanceAt: { + name: 'vendor.field.opening_balance_at', + column: 'opening_balance_at', + fieldType: 'date', + }, + openingBalanceExchangeRate: { + name: 'Opening Balance Ex. Rate', + column: 'opening_balance_exchange_rate', + fieldType: 'number', + }, + currencyCode: { + name: 'vendor.field.currency', + column: 'currency_code', + fieldType: 'text', + }, + note: { + name: 'Note', + column: 'note', + fieldType: 'text', + }, + active: { + name: 'Active', + column: 'active', + fieldType: 'boolean', + }, + // Billing Address + billingAddress1: { + name: 'Billing Address 1', + column: 'billing_address1', + fieldType: 'text', + }, + billingAddress2: { + name: 'Billing Address 2', + column: 'billing_address2', + fieldType: 'text', + }, + billingAddressCity: { + name: 'Billing Address City', + column: 'billing_address_city', + fieldType: 'text', + }, + billingAddressCountry: { + name: 'Billing Address Country', + column: 'billing_address_country', + fieldType: 'text', + }, + billingAddressPostcode: { + name: 'Billing Address Postcode', + column: 'billing_address_postcode', + fieldType: 'text', + }, + billingAddressState: { + name: 'Billing Address State', + column: 'billing_address_state', + fieldType: 'text', + }, + billingAddressPhone: { + name: 'Billing Address Phone', + column: 'billing_address_phone', + fieldType: 'text', + }, + // Shipping Address + shippingAddress1: { + name: 'Shipping Address 1', + column: 'shipping_address1', + fieldType: 'text', + }, + shippingAddress2: { + name: 'Shipping Address 2', + column: 'shipping_address2', + fieldType: 'text', + }, + shippingAddressCity: { + name: 'Shipping Address City', + column: 'shipping_address_city', + fieldType: 'text', + }, + shippingAddressCountry: { + name: 'Shipping Address Country', + column: 'shipping_address_country', + fieldType: 'text', + }, + shippingAddressPostcode: { + name: 'Shipping Address Postcode', + column: 'shipping_address_postcode', + fieldType: 'text', + }, + shippingAddressState: { + name: 'Shipping Address State', + column: 'shipping_address_state', + fieldType: 'text', + }, + shippingAddressPhone: { + name: 'Shipping Address Phone', + column: 'shipping_address_phone', + fieldType: 'text', + }, + }, +}; \ No newline at end of file diff --git a/packages/server/src/modules/Vendors/models/Vendor.ts b/packages/server/src/modules/Vendors/models/Vendor.ts index 194912df4..cc26bac3b 100644 --- a/packages/server/src/modules/Vendors/models/Vendor.ts +++ b/packages/server/src/modules/Vendors/models/Vendor.ts @@ -9,6 +9,8 @@ import { Model, mixin } from 'objection'; import { BaseModel } from '@/models/Model'; import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel'; import { ExportableModel } from '@/modules/Export/decorators/ExportableModel.decorator'; +import { InjectModelMeta } from '@/modules/Tenancy/TenancyModels/decorators/InjectModelMeta.decorator'; +import { VendorMeta } from './Vendor.meta'; // class VendorQueryBuilder extends PaginationQueryBuilder { // constructor(...args) { @@ -23,6 +25,7 @@ import { ExportableModel } from '@/modules/Export/decorators/ExportableModel.dec // } @ExportableModel() +@InjectModelMeta(VendorMeta) export class Vendor extends TenantBaseModel { contactService: string; contactType: string; diff --git a/packages/server/src/modules/Warehouses/Warehouses.module.ts b/packages/server/src/modules/Warehouses/Warehouses.module.ts index b141e5a59..aa899f2dc 100644 --- a/packages/server/src/modules/Warehouses/Warehouses.module.ts +++ b/packages/server/src/modules/Warehouses/Warehouses.module.ts @@ -90,6 +90,6 @@ const models = [RegisterTenancyModel(Warehouse)]; InventoryTransactionsWarehouses, ValidateWarehouseExistance ], - exports: [WarehouseTransactionDTOTransform, ...models], + exports: [WarehousesSettings, WarehouseTransactionDTOTransform, ...models], }) export class WarehousesModule {} From c953c48c39a525359b49018eb040e9218c68d2b8 Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Thu, 10 Apr 2025 23:34:42 +0200 Subject: [PATCH 5/5] refactor(nestjs): export module --- .../modules/Accounts/models/Account.model.ts | 6 -- .../server/src/modules/Bills/Bills.module.ts | 5 +- .../modules/Bills/commands/BillsExportable.ts | 3 + .../modules/CreditNotes/CreditNotes.module.ts | 5 +- .../commands/CreditNotesExportable.ts | 3 + .../queries/GetCreditNotes.service.ts | 3 +- .../src/modules/Expenses/Expenses.module.ts | 4 +- .../modules/Expenses/ExpensesExportable.ts | 1 + .../src/modules/Export/Export.module.ts | 2 - .../src/modules/Export/ExportService.ts | 2 - .../decorators/ExportableModel.decorator.ts | 5 ++ .../ItemCategories/ItemCategory.module.ts | 8 +- .../server/src/modules/Items/Items.module.ts | 4 +- .../modules/Items/ItemsExportable.service.ts | 36 +++++++++ .../modules/Items/ItemsImportable.service.ts | 36 +++++++++ .../server/src/modules/Items/models/Item.ts | 7 ++ .../ManualJournals/ManualJournals.module.ts | 3 +- .../commands/ManualJournalExportable.ts | 4 + .../SaleEstimates/SaleEstimates.module.ts | 4 + .../SaleEstimates/SaleEstimatesExportable.ts | 3 + .../SaleInvoices/SaleInvoices.module.ts | 12 ++- .../commands/SaleInvoicesImportable.ts | 77 +++++++++---------- .../SaleInvoices/queries/GetSaleInvoices.ts | 11 ++- 23 files changed, 176 insertions(+), 68 deletions(-) create mode 100644 packages/server/src/modules/Items/ItemsExportable.service.ts create mode 100644 packages/server/src/modules/Items/ItemsImportable.service.ts diff --git a/packages/server/src/modules/Accounts/models/Account.model.ts b/packages/server/src/modules/Accounts/models/Account.model.ts index e7429581b..73b3503aa 100644 --- a/packages/server/src/modules/Accounts/models/Account.model.ts +++ b/packages/server/src/modules/Accounts/models/Account.model.ts @@ -6,9 +6,6 @@ import { ACCOUNT_TYPES, getAccountsSupportsMultiCurrency, } from '@/constants/accounts'; -// import { SearchableModel } from '@/modules/Search/SearchableMdel'; -// import { CustomViewBaseModel } from '@/modules/CustomViews/CustomViewBaseModel'; -// import { ModelSettings } from '@/modules/Settings/ModelSettings'; import { AccountTypesUtils } from '@/libs/accounts-utils/AccountTypesUtils'; import { PlaidItem } from '@/modules/BankingPlaid/models/PlaidItem'; import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel'; @@ -16,9 +13,6 @@ import { flatToNestedArray } from '@/utils/flat-to-nested-array'; import { ExportableModel } from '../../Export/decorators/ExportableModel.decorator'; import { AccountMeta } from './Account.meta'; import { InjectModelMeta } from '@/modules/Tenancy/TenancyModels/decorators/InjectModelMeta.decorator'; -// import AccountSettings from './Account.Settings'; -// import { DEFAULT_VIEWS } from '@/modules/Accounts/constants'; -// import { buildFilterQuery, buildSortColumnQuery } from '@/lib/ViewRolesBuilder'; @ExportableModel() @InjectModelMeta(AccountMeta) diff --git a/packages/server/src/modules/Bills/Bills.module.ts b/packages/server/src/modules/Bills/Bills.module.ts index a9f5549e1..df4d35975 100644 --- a/packages/server/src/modules/Bills/Bills.module.ts +++ b/packages/server/src/modules/Bills/Bills.module.ts @@ -27,6 +27,7 @@ import { GetBillsService } from './queries/GetBills.service'; import { DynamicListModule } from '../DynamicListing/DynamicList.module'; import { InventoryCostModule } from '../InventoryCost/InventoryCost.module'; import { BillsExportable } from './commands/BillsExportable'; +import { BillsImportable } from './commands/BillsImportable'; @Module({ imports: [ @@ -58,8 +59,10 @@ import { BillsExportable } from './commands/BillsExportable'; BillGLEntriesSubscriber, BillInventoryTransactions, BillWriteInventoryTransactionsSubscriber, - BillsExportable + BillsExportable, + BillsImportable ], controllers: [BillsController], + exports: [BillsExportable, BillsImportable], }) export class BillsModule {} diff --git a/packages/server/src/modules/Bills/commands/BillsExportable.ts b/packages/server/src/modules/Bills/commands/BillsExportable.ts index df9d09b66..832b1deed 100644 --- a/packages/server/src/modules/Bills/commands/BillsExportable.ts +++ b/packages/server/src/modules/Bills/commands/BillsExportable.ts @@ -4,8 +4,11 @@ import { Injectable } from '@nestjs/common'; import { Exportable } from '@/modules/Export/Exportable'; import { IBillsFilter } from '../Bills.types'; import { EXPORT_SIZE_LIMIT } from '@/modules/Export/constants'; +import { ExportableService } from '@/modules/Export/decorators/ExportableModel.decorator'; +import { Bill } from '../models/Bill'; @Injectable() +@ExportableService({ name: Bill.name }) export class BillsExportable extends Exportable { constructor(private readonly billsApplication: BillsApplication) { super(); diff --git a/packages/server/src/modules/CreditNotes/CreditNotes.module.ts b/packages/server/src/modules/CreditNotes/CreditNotes.module.ts index b7785488c..11d61daba 100644 --- a/packages/server/src/modules/CreditNotes/CreditNotes.module.ts +++ b/packages/server/src/modules/CreditNotes/CreditNotes.module.ts @@ -37,7 +37,7 @@ import { CreditNotesExportable } from './commands/CreditNotesExportable'; AutoIncrementOrdersModule, LedgerModule, AccountsModule, - DynamicListModule + DynamicListModule, ], providers: [ CreateCreditNoteService, @@ -54,7 +54,7 @@ import { CreditNotesExportable } from './commands/CreditNotesExportable'; CreditNoteBrandingTemplate, CreditNoteGLEntries, CreditNoteGLEntriesSubscriber, - CreditNotesExportable + CreditNotesExportable, ], exports: [ CreateCreditNoteService, @@ -68,6 +68,7 @@ import { CreditNotesExportable } from './commands/CreditNotesExportable'; GetCreditNoteState, CreditNoteApplication, CreditNoteBrandingTemplate, + CreditNotesExportable, ], controllers: [CreditNotesController], }) diff --git a/packages/server/src/modules/CreditNotes/commands/CreditNotesExportable.ts b/packages/server/src/modules/CreditNotes/commands/CreditNotesExportable.ts index ac5c8b55a..00e0dea09 100644 --- a/packages/server/src/modules/CreditNotes/commands/CreditNotesExportable.ts +++ b/packages/server/src/modules/CreditNotes/commands/CreditNotesExportable.ts @@ -2,8 +2,11 @@ import { Exportable } from '@/modules/Export/Exportable'; import { CreditNoteApplication } from '../CreditNoteApplication.service'; import { Injectable } from '@nestjs/common'; import { ICreditNotesQueryDTO } from '../types/CreditNotes.types'; +import { ExportableService } from '@/modules/Export/decorators/ExportableModel.decorator'; +import { CreditNote } from '../models/CreditNote'; @Injectable() +@ExportableService({ name: CreditNote.name }) export class CreditNotesExportable extends Exportable { constructor(private readonly creditNotesApp: CreditNoteApplication) { super(); diff --git a/packages/server/src/modules/CreditNotes/queries/GetCreditNotes.service.ts b/packages/server/src/modules/CreditNotes/queries/GetCreditNotes.service.ts index 7457c923b..a588dddad 100644 --- a/packages/server/src/modules/CreditNotes/queries/GetCreditNotes.service.ts +++ b/packages/server/src/modules/CreditNotes/queries/GetCreditNotes.service.ts @@ -1,3 +1,4 @@ +import { Inject, Injectable } from '@nestjs/common'; import * as R from 'ramda'; import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectable.service'; import { DynamicListService } from '@/modules/DynamicListing/DynamicList.service'; @@ -7,8 +8,6 @@ import { } from '../types/CreditNotes.types'; import { CreditNote } from '../models/CreditNote'; import { CreditNoteTransformer } from './CreditNoteTransformer'; -import { Inject } from '@nestjs/common'; -import { Injectable } from '@nestjs/common'; import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel'; @Injectable() diff --git a/packages/server/src/modules/Expenses/Expenses.module.ts b/packages/server/src/modules/Expenses/Expenses.module.ts index 60278857e..9a36478ab 100644 --- a/packages/server/src/modules/Expenses/Expenses.module.ts +++ b/packages/server/src/modules/Expenses/Expenses.module.ts @@ -23,7 +23,7 @@ import { ExpensesImportable } from './ExpensesImportable'; @Module({ imports: [LedgerModule, BranchesModule, DynamicListModule], controllers: [ExpensesController], - exports: [CreateExpense], + exports: [CreateExpense, ExpensesExportable, ExpensesImportable], providers: [ CreateExpense, ExpenseDTOTransformer, @@ -40,7 +40,7 @@ import { ExpensesImportable } from './ExpensesImportable'; ExpenseGLEntriesService, GetExpensesService, ExpensesExportable, - ExpensesImportable + ExpensesImportable, ], }) export class ExpensesModule {} diff --git a/packages/server/src/modules/Expenses/ExpensesExportable.ts b/packages/server/src/modules/Expenses/ExpensesExportable.ts index 902a2c91a..9207101ba 100644 --- a/packages/server/src/modules/Expenses/ExpensesExportable.ts +++ b/packages/server/src/modules/Expenses/ExpensesExportable.ts @@ -17,6 +17,7 @@ export class ExpensesExportable extends Exportable { /** * Retrieves the accounts data to exportable sheet. + * @param {IExpensesFilter} */ public exportable(query: IExpensesFilter) { const filterQuery = (query) => { diff --git a/packages/server/src/modules/Export/Export.module.ts b/packages/server/src/modules/Export/Export.module.ts index 59e73e771..1aec5e4f9 100644 --- a/packages/server/src/modules/Export/Export.module.ts +++ b/packages/server/src/modules/Export/Export.module.ts @@ -7,7 +7,6 @@ import { ExportApplication } from './ExportApplication'; import { ResourceModule } from '../Resource/Resource.module'; import { RegisterTenancyModel } from '../Tenancy/TenancyModels/Tenancy.module'; import { ImportModel } from '../Import/models/Import'; -import { ExportableResources } from './ExportResources'; import { ExportableRegistry } from './ExportRegistery'; import { TemplateInjectableModule } from '../TemplateInjectable/TemplateInjectable.module'; import { ChromiumlyTenancyModule } from '../ChromiumlyTenancy/ChromiumlyTenancy.module'; @@ -28,7 +27,6 @@ const models = [RegisterTenancyModel(ImportModel)]; ExportPdf, ExportAls, ExportApplication, - ExportableResources, ExportableRegistry ], exports: [...models], diff --git a/packages/server/src/modules/Export/ExportService.ts b/packages/server/src/modules/Export/ExportService.ts index 6e8e704e4..c464dd41d 100644 --- a/packages/server/src/modules/Export/ExportService.ts +++ b/packages/server/src/modules/Export/ExportService.ts @@ -3,7 +3,6 @@ import * as xlsx from 'xlsx'; import * as R from 'ramda'; import { get } from 'lodash'; import { sanitizeResourceName } from '../Import/_utils'; -import { ExportableResources } from './ExportResources'; import { Errors, ExportFormat } from './common'; import { flatDataCollections, getDataAccessor } from './utils'; import { ExportPdf } from './ExportPdf'; @@ -19,7 +18,6 @@ export class ExportResourceService { constructor( private readonly exportAls: ExportAls, private readonly exportPdf: ExportPdf, - private readonly exportableResources: ExportableResources, private readonly resourceService: ResourceService, private readonly moduleRef: ModuleRef, ) {} diff --git a/packages/server/src/modules/Export/decorators/ExportableModel.decorator.ts b/packages/server/src/modules/Export/decorators/ExportableModel.decorator.ts index 28a64e8ff..ea9ca0fb3 100644 --- a/packages/server/src/modules/Export/decorators/ExportableModel.decorator.ts +++ b/packages/server/src/modules/Export/decorators/ExportableModel.decorator.ts @@ -1,3 +1,5 @@ +import { Global } from "@nestjs/common"; + const exportableModels = new Map(); const exportableService = new Map() @@ -15,6 +17,9 @@ export function ExportableModel() { export function ExportableService({ name }: { name: string }) { return function (target: any) { exportableService.set(name, target); + + // Apply the @Global() decorator to make the service globally available + Global()(target); }; } diff --git a/packages/server/src/modules/ItemCategories/ItemCategory.module.ts b/packages/server/src/modules/ItemCategories/ItemCategory.module.ts index b9919a0ee..c5cec3989 100644 --- a/packages/server/src/modules/ItemCategories/ItemCategory.module.ts +++ b/packages/server/src/modules/ItemCategories/ItemCategory.module.ts @@ -25,10 +25,14 @@ import { ItemCategoriesImportable } from './ItemCategoriesImportable'; DeleteItemCategoryService, ItemCategoryApplication, CommandItemCategoryValidatorService, - ItemCategoriesExportable, TransformerInjectable, TenancyContext, - ItemCategoriesImportable + ItemCategoriesExportable, + ItemCategoriesImportable, + ], + exports: [ + ItemCategoriesExportable, + ItemCategoriesImportable, ], }) export class ItemCategoryModule {} diff --git a/packages/server/src/modules/Items/Items.module.ts b/packages/server/src/modules/Items/Items.module.ts index 73be6e1d1..cc0c4fb1f 100644 --- a/packages/server/src/modules/Items/Items.module.ts +++ b/packages/server/src/modules/Items/Items.module.ts @@ -16,6 +16,7 @@ import { ItemsEntriesService } from './ItemsEntries.service'; import { GetItemsService } from './GetItems.service'; import { DynamicListModule } from '../DynamicListing/DynamicList.module'; import { InventoryAdjustmentsModule } from '../InventoryAdjutments/InventoryAdjustments.module'; +import { ItemsExportable } from './ItemsExportable.service'; @Module({ imports: [ @@ -38,7 +39,8 @@ import { InventoryAdjustmentsModule } from '../InventoryAdjutments/InventoryAdju TenancyContext, TransformerInjectable, ItemsEntriesService, + ItemsExportable, ], - exports: [ItemsEntriesService], + exports: [ItemsEntriesService, ItemsExportable], }) export class ItemsModule {} diff --git a/packages/server/src/modules/Items/ItemsExportable.service.ts b/packages/server/src/modules/Items/ItemsExportable.service.ts new file mode 100644 index 000000000..6a1474bff --- /dev/null +++ b/packages/server/src/modules/Items/ItemsExportable.service.ts @@ -0,0 +1,36 @@ +import { Global, Injectable } from '@nestjs/common'; +import { Exportable } from '../Export/Exportable'; +import { EXPORT_SIZE_LIMIT } from '../Export/constants'; +import { ItemsApplicationService } from './ItemsApplication.service'; +import { IItemsFilter } from './types/Items.types'; +import { ExportableService } from '../Export/decorators/ExportableModel.decorator'; +import { Item } from './models/Item'; + +@Injectable() +@ExportableService({ name: Item.name }) +@Global() +export class ItemsExportable extends Exportable { + constructor( + private readonly itemsApplication: ItemsApplicationService, + ) { + super(); + } + + /** + * Retrieves the accounts data to exportable sheet. + * @param {IItemsFilter} query - Items export query. + */ + public exportable(query: IItemsFilter) { + const parsedQuery = { + sortOrder: 'DESC', + columnSortBy: 'created_at', + page: 1, + ...query, + pageSize: EXPORT_SIZE_LIMIT, + } as IItemsFilter; + + return this.itemsApplication + .getItems(parsedQuery) + .then((output) => output.items); + } +} \ No newline at end of file diff --git a/packages/server/src/modules/Items/ItemsImportable.service.ts b/packages/server/src/modules/Items/ItemsImportable.service.ts new file mode 100644 index 000000000..091473c87 --- /dev/null +++ b/packages/server/src/modules/Items/ItemsImportable.service.ts @@ -0,0 +1,36 @@ +import { Injectable } from '@nestjs/common'; +import { Knex } from 'knex'; +import { Importable } from '../Import/Importable'; +import { CreateItemService } from './CreateItem.service'; +import { CreateItemDto } from './dtos/Item.dto'; +import { ItemsSampleData } from './Items.constants'; + +@Injectable() +export class ItemsImportable extends Importable { + constructor( + private readonly createItemService: CreateItemService, + ) { + super(); + } + + /** + * Mapps the imported data to create a new item service. + * @param {number} tenantId + * @param {ICustomerNewDTO} createDTO + * @param {Knex.Transaction} trx + * @returns {Promise} + */ + public async importable( + createDTO: CreateItemDto, + trx?: Knex.Transaction + ): Promise { + await this.createItemService.createItem(createDTO, trx); + } + + /** + * Retrieves the sample data of customers used to download sample sheet. + */ + public sampleData(): any[] { + return ItemsSampleData; + } +} \ No newline at end of file diff --git a/packages/server/src/modules/Items/models/Item.ts b/packages/server/src/modules/Items/models/Item.ts index 39227a0e0..c9f561c81 100644 --- a/packages/server/src/modules/Items/models/Item.ts +++ b/packages/server/src/modules/Items/models/Item.ts @@ -53,6 +53,13 @@ export class Item extends TenantBaseModel { } return q; }, + + /** + * Inactive/Active mode. + */ + inactiveMode(query, active = false) { + query.where('items.active', !active); + }, }; } diff --git a/packages/server/src/modules/ManualJournals/ManualJournals.module.ts b/packages/server/src/modules/ManualJournals/ManualJournals.module.ts index 2b2a8c773..be1dabfb8 100644 --- a/packages/server/src/modules/ManualJournals/ManualJournals.module.ts +++ b/packages/server/src/modules/ManualJournals/ManualJournals.module.ts @@ -40,7 +40,8 @@ import { DynamicListModule } from '../DynamicListing/DynamicList.module'; ManualJournalGLEntries, ManualJournalWriteGLSubscriber, ManualJournalsExportable, - ManualJournalImportable + ManualJournalImportable, ], + exports: [ManualJournalsExportable, ManualJournalImportable], }) export class ManualJournalsModule {} diff --git a/packages/server/src/modules/ManualJournals/commands/ManualJournalExportable.ts b/packages/server/src/modules/ManualJournals/commands/ManualJournalExportable.ts index dc96bf0cd..1afe280d1 100644 --- a/packages/server/src/modules/ManualJournals/commands/ManualJournalExportable.ts +++ b/packages/server/src/modules/ManualJournals/commands/ManualJournalExportable.ts @@ -3,8 +3,11 @@ import { EXPORT_SIZE_LIMIT } from '../../Export/constants'; import { Injectable } from '@nestjs/common'; import { IManualJournalsFilter } from '../types/ManualJournals.types'; import { ManualJournalsApplication } from '../ManualJournalsApplication.service'; +import { ExportableService } from '@/modules/Export/decorators/ExportableModel.decorator'; +import { ManualJournal } from '../models/ManualJournal'; @Injectable() +@ExportableService({ name: ManualJournal.name }) export class ManualJournalsExportable extends Exportable { constructor( private readonly manualJournalsApplication: ManualJournalsApplication, @@ -14,6 +17,7 @@ export class ManualJournalsExportable extends Exportable { /** * Retrieves the manual journals data to exportable sheet. + * @param {IManualJournalsFilter} query - */ public exportable(query: IManualJournalsFilter) { const parsedQuery = { diff --git a/packages/server/src/modules/SaleEstimates/SaleEstimates.module.ts b/packages/server/src/modules/SaleEstimates/SaleEstimates.module.ts index 43184d0f4..2732dcac6 100644 --- a/packages/server/src/modules/SaleEstimates/SaleEstimates.module.ts +++ b/packages/server/src/modules/SaleEstimates/SaleEstimates.module.ts @@ -80,5 +80,9 @@ import { SaleEstimatesImportable } from './SaleEstimatesImportable'; SaleEstimatesExportable, SaleEstimatesImportable ], + exports: [ + SaleEstimatesExportable, + SaleEstimatesImportable + ] }) export class SaleEstimatesModule {} diff --git a/packages/server/src/modules/SaleEstimates/SaleEstimatesExportable.ts b/packages/server/src/modules/SaleEstimates/SaleEstimatesExportable.ts index 4937223fe..92fad9bcc 100644 --- a/packages/server/src/modules/SaleEstimates/SaleEstimatesExportable.ts +++ b/packages/server/src/modules/SaleEstimates/SaleEstimatesExportable.ts @@ -4,8 +4,11 @@ import { Exportable } from '../Export/Exportable'; import { ISalesInvoicesFilter } from '../SaleInvoices/SaleInvoice.types'; import { SaleEstimatesApplication } from './SaleEstimates.application'; import { ISalesEstimatesFilter } from './types/SaleEstimates.types'; +import { ExportableService } from '../Export/decorators/ExportableModel.decorator'; +import { SaleEstimate } from './models/SaleEstimate'; @Injectable() +@ExportableService({ name: SaleEstimate.name }) export class SaleEstimatesExportable extends Exportable { constructor( private readonly saleEstimatesApplication: SaleEstimatesApplication, diff --git a/packages/server/src/modules/SaleInvoices/SaleInvoices.module.ts b/packages/server/src/modules/SaleInvoices/SaleInvoices.module.ts index 3c5bcbfe3..a88679f57 100644 --- a/packages/server/src/modules/SaleInvoices/SaleInvoices.module.ts +++ b/packages/server/src/modules/SaleInvoices/SaleInvoices.module.ts @@ -57,6 +57,7 @@ import { InvoicePaymentsGLEntriesRewrite } from './InvoicePaymentsGLRewrite'; import { PaymentsReceivedModule } from '../PaymentReceived/PaymentsReceived.module'; import { SaleInvoicesCost } from './SalesInvoicesCost'; import { SaleInvoicesExportable } from './commands/SaleInvoicesExportable'; +import { SaleInvoicesImportable } from './commands/SaleInvoicesImportable'; @Module({ imports: [ @@ -119,8 +120,15 @@ import { SaleInvoicesExportable } from './commands/SaleInvoicesExportable'; SaleInvoiceWriteInventoryTransactionsSubscriber, InvoicePaymentsGLEntriesRewrite, SaleInvoicesCost, - SaleInvoicesExportable + SaleInvoicesExportable, + SaleInvoicesImportable, + ], + exports: [ + GetSaleInvoice, + SaleInvoicesCost, + SaleInvoicePdf, + SaleInvoicesExportable, + SaleInvoicesImportable, ], - exports: [GetSaleInvoice, SaleInvoicesCost, SaleInvoicePdf], }) export class SaleInvoicesModule {} diff --git a/packages/server/src/modules/SaleInvoices/commands/SaleInvoicesImportable.ts b/packages/server/src/modules/SaleInvoices/commands/SaleInvoicesImportable.ts index f0b48423c..6e4e6cee6 100644 --- a/packages/server/src/modules/SaleInvoices/commands/SaleInvoicesImportable.ts +++ b/packages/server/src/modules/SaleInvoices/commands/SaleInvoicesImportable.ts @@ -1,46 +1,39 @@ -// import { Inject, Service } from 'typedi'; -// import { Knex } from 'knex'; -// import { ISaleInvoiceCreateDTO } from '@/interfaces'; -// import { CreateSaleInvoice } from './commands/CreateSaleInvoice.service'; -// import { Importable } from '@/services/Import/Importable'; -// import { SaleInvoicesSampleData } from './constants'; +import { Injectable } from '@nestjs/common'; +import { Knex } from 'knex'; +import { CreateSaleInvoice } from './CreateSaleInvoice.service'; +import { Importable } from '@/modules/Import/Importable'; +import { CreateSaleInvoiceDto } from '../dtos/SaleInvoice.dto'; +import { SaleInvoicesSampleData } from '../constants'; -// @Service() -// export class SaleInvoicesImportable extends Importable { -// @Inject() -// private createInvoiceService: CreateSaleInvoice; +@Injectable() +export class SaleInvoicesImportable extends Importable { + constructor(private readonly createInvoiceService: CreateSaleInvoice) { + super(); + } -// /** -// * Importing to account service. -// * @param {number} tenantId -// * @param {IAccountCreateDTO} createAccountDTO -// * @returns -// */ -// public importable( -// tenantId: number, -// createAccountDTO: ISaleInvoiceCreateDTO, -// trx?: Knex.Transaction -// ) { -// return this.createInvoiceService.createSaleInvoice( -// tenantId, -// createAccountDTO, -// {}, -// trx -// ); -// } + /** + * Importing to account service. + * @param {CreateSaleInvoiceDto} createAccountDTO + */ + public importable( + createAccountDTO: CreateSaleInvoiceDto, + trx?: Knex.Transaction, + ) { + return this.createInvoiceService.createSaleInvoice(createAccountDTO, trx); + } -// /** -// * Concurrrency controlling of the importing process. -// * @returns {number} -// */ -// public get concurrency() { -// return 1; -// } + /** + * Concurrrency controlling of the importing process. + * @returns {number} + */ + public get concurrency() { + return 1; + } -// /** -// * Retrieves the sample data that used to download accounts sample sheet. -// */ -// public sampleData(): any[] { -// return SaleInvoicesSampleData; -// } -// } + /** + * Retrieves the sample data that used to download accounts sample sheet. + */ + public sampleData(): any[] { + return SaleInvoicesSampleData; + } +} diff --git a/packages/server/src/modules/SaleInvoices/queries/GetSaleInvoices.ts b/packages/server/src/modules/SaleInvoices/queries/GetSaleInvoices.ts index a7f58344e..1552df05f 100644 --- a/packages/server/src/modules/SaleInvoices/queries/GetSaleInvoices.ts +++ b/packages/server/src/modules/SaleInvoices/queries/GetSaleInvoices.ts @@ -1,18 +1,22 @@ import * as R from 'ramda'; +import { Knex } from 'knex'; +import { Inject, Injectable } from '@nestjs/common'; import { SaleInvoiceTransformer } from './SaleInvoice.transformer'; -import { Injectable } from '@nestjs/common'; import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectable.service'; 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'; +import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel'; @Injectable() export class GetSaleInvoicesService { constructor( private readonly dynamicListService: DynamicListService, private readonly transformer: TransformerInjectable, + + @Inject(SaleInvoice.name) + private readonly saleInvoiceModel: TenantModelProxy, ) {} /** @@ -33,7 +37,8 @@ export class GetSaleInvoicesService { SaleInvoice, filter, ); - const { results, pagination } = await SaleInvoice.query() + const { results, pagination } = await this.saleInvoiceModel() + .query() .onBuild((builder) => { builder.withGraphFetched('entries.item'); builder.withGraphFetched('customer');