From d15c5890ede066ee1498bf9a581d1b4a60e2184e Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Tue, 28 Nov 2023 19:53:13 +0200 Subject: [PATCH] feat: export reports csv and xlsx (#286) --- packages/server/package.json | 3 +- .../FinancialStatements/APAgingSummary.ts | 84 ++-- .../FinancialStatements/ARAgingSummary.ts | 80 ++-- .../FinancialStatements/BalanceSheet.ts | 80 ++-- .../FinancialStatements/CashFlow/CashFlow.ts | 108 +++--- .../CustomerBalanceSummary/index.ts | 116 +++--- .../InventoryDetails/index.ts | 115 +++--- .../FinancialStatements/ProfitLossSheet.ts | 87 +++-- .../FinancialStatements/SalesByItems.ts | 15 +- .../SalesTaxLiabilitySummary/index.ts | 83 ++-- .../TransactionsByCustomers/index.ts | 106 +++-- .../TransactionsByVendors/index.ts | 110 +++--- .../FinancialStatements/TrialBalanceSheet.ts | 55 ++- .../VendorBalanceSummary/index.ts | 119 +++--- .../src/interfaces/APAgingSummaryReport.ts | 6 + .../src/interfaces/ARAgingSummaryReport.ts | 6 + .../server/src/interfaces/BalanceSheet.ts | 6 + packages/server/src/interfaces/CashFlow.ts | 7 +- .../src/interfaces/CustomerBalanceSummary.ts | 9 +- packages/server/src/interfaces/Http.ts | 7 + .../server/src/interfaces/InventoryDetails.ts | 17 +- .../server/src/interfaces/ProfitLossSheet.ts | 7 + .../interfaces/SalesTaxLiabilitySummary.ts | 7 + packages/server/src/interfaces/Table.ts | 13 +- .../src/interfaces/TransactionsByCustomers.ts | 6 + .../src/interfaces/TransactionsByVendors.ts | 5 + .../src/interfaces/TrialBalanceSheet.ts | 6 + .../src/interfaces/VendorBalanceSummary.ts | 9 +- packages/server/src/lib/Xlsx/TableSheet.tsx | 134 +++++++ .../AgingSummary/APAgingSummaryApplication.ts | 53 +++ .../APAgingSummaryExportInjectable.ts | 43 +++ .../AgingSummary/APAgingSummaryService.ts | 24 +- .../APAgingSummaryTableInjectable.ts | 36 ++ .../AgingSummary/ARAgingSummaryApplication.ts | 53 +++ .../ARAgingSummaryExportInjectable.ts | 46 +++ .../AgingSummary/ARAgingSummaryService.ts | 18 - .../ARAgingSummaryTableInjectable.ts | 36 ++ .../BalanceSheet/BalanceSheetApplication.ts | 57 +++ .../BalanceSheetExportInjectable.ts | 43 +++ ...etService.ts => BalanceSheetInjectable.ts} | 9 +- .../BalanceSheetTableInjectable.ts | 42 ++ .../CashFlow/CashflowExportInjectable.ts | 46 +++ .../CashFlow/CashflowSheetApplication.ts | 58 +++ .../CashFlow/CashflowTableInjectable.ts | 37 ++ .../CustomerBalanceSummaryApplication.ts | 60 +++ .../CustomerBalanceSummaryExportInjectable.ts | 43 +++ .../CustomerBalanceSummaryService.ts | 29 +- .../CustomerBalanceSummaryTableInjectable.ts | 44 +++ .../CustomerBalanceSummaryTableRows.ts | 2 +- .../FinancialTableStructure.ts | 48 +++ .../InventoryDetails/InventoryDetails.ts | 2 +- .../InventoryDetailsApplication.ts | 66 ++++ .../InventoryDetailsExportInjectable.ts | 43 +++ .../InventoryDetailsService.ts | 4 +- .../InventoryDetails/InventoryDetailsTable.ts | 6 +- .../InventoryDetailsTableInjectable.ts | 45 +++ .../ProfitLossSheetApplication.ts | 60 +++ .../ProfitLossSheetExportInjectable.ts | 43 +++ .../ProfitLossSheet/ProfitLossSheetService.ts | 68 ++-- .../ProfitLossSheetTableInjectable.ts | 42 ++ .../SalesByItems/SalesByItemsService.ts | 4 - .../SalesTaxLiabilitySummaryApplication.ts | 63 +++ ...alesTaxLiabilitySummaryExportInjectable.ts | 46 +++ .../SalesTaxLiabilitySummaryService.ts | 27 -- ...SalesTaxLiabilitySummaryTableInjectable.ts | 40 ++ .../TransactionsByCustomers.ts | 7 - .../TransactionsByCustomersApplication.ts | 72 ++++ ...TransactionsByCustomersExportInjectable.ts | 46 +++ .../TransactionsByCustomersRepository.ts | 6 +- .../TransactionsByCustomersService.ts | 12 +- ...ows.ts => TransactionsByCustomersTable.ts} | 19 +- .../TransactionsByCustomersTableInjectable.ts | 44 +++ .../TransactionsByVendor.ts | 7 - .../TransactionsByVendorApplication.ts | 75 ++++ .../TransactionsByVendorExportInjectable.ts | 46 +++ ...e.ts => TransactionsByVendorInjectable.ts} | 13 +- ...leRows.ts => TransactionsByVendorTable.ts} | 25 +- .../TransactionsByVendorTableInjectable.ts | 44 +++ .../TrialBalanceExportInjectable.ts | 43 +++ .../TrialBalanceSheetApplication.ts | 60 +++ ...vice.ts => TrialBalanceSheetInjectable.ts} | 30 +- .../TrialBalanceSheetTableInjectable.ts | 33 ++ .../VendorBalanceSummary.ts | 4 - .../VendorBalanceSummaryApplication.ts | 62 +++ .../VendorBalanceSummaryExportInjectable.ts | 43 +++ .../VendorBalanceSummaryRepository.ts | 2 +- .../VendorBalanceSummaryService.ts | 20 +- .../VendorBalanceSummaryTableInjectable.ts | 44 +++ .../VendorBalanceSummaryTableRows.ts | 2 +- packages/server/src/utils/deepdash.ts | 22 ++ packages/server/src/utils/table.ts | 4 +- .../APAgingSummaryActionsBar.tsx | 18 +- .../APAgingSummary/APAgingSummaryProvider.tsx | 1 + .../APAgingSummary/components.tsx | 101 ++++- .../ARAgingSummaryActionsBar.tsx | 18 +- .../ARAgingSummary/components.tsx | 102 ++++- .../BalanceSheet/BalanceSheetActionsBar.tsx | 21 +- .../BalanceSheet/components.tsx | 110 +++++- .../CashFlowStatementActionsBar.tsx | 18 +- .../CashFlowStatement/components.tsx | 110 +++++- .../CustomersBalanceSummaryActionsBar.tsx | 20 +- .../CustomersBalanceSummaryProvider.tsx | 1 + .../CustomersBalanceSummaryTable.tsx | 2 +- .../CustomersBalanceSummary/components.tsx | 104 ++++- .../CustomersTransactionsActionsBar.tsx | 20 +- .../CustomersTransactions/components.tsx | 106 ++++- .../InventoryItemDetailsActionsBar.tsx | 18 +- .../InventoryItemDetails/components.tsx | 117 +++++- .../InventoryItemDetails/utils2.tsx | 11 + .../ProfitLossSheet/ProfitLossActionsBar.tsx | 18 +- .../ProfitLossSheet/ProfitLossProvider.tsx | 12 +- .../ProfitLossSheet/components.tsx | 110 +++++- .../SalesTaxLiabilitySummaryActionsBar.tsx | 18 +- .../SalesTaxLiabilitySummary/components.tsx | 109 +++++- .../TrialBalanceActionsBar.tsx | 18 +- .../TrialBalanceSheet/components.tsx | 118 +++++- .../TrialBalanceSheet/utils.tsx | 11 + .../VendorsBalanceSummaryActionsBar.tsx | 18 +- .../VendorsBalanceSummaryTable.tsx | 2 +- .../VendorsBalanceSummary/components.tsx | 96 ++++- .../VendorsTransactionsActionsBar.tsx | 18 +- .../VendorsTransactions/components.tsx | 102 ++++- .../src/hooks/query/financialReports.tsx | 364 +++++++++++++++++- packages/webapp/src/hooks/useDownloadFile.ts | 72 ++++ pnpm-lock.yaml | 63 +++ 125 files changed, 4682 insertions(+), 942 deletions(-) create mode 100644 packages/server/src/interfaces/Http.ts create mode 100644 packages/server/src/lib/Xlsx/TableSheet.tsx create mode 100644 packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryApplication.ts create mode 100644 packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryExportInjectable.ts create mode 100644 packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryTableInjectable.ts create mode 100644 packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryApplication.ts create mode 100644 packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryExportInjectable.ts create mode 100644 packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryTableInjectable.ts create mode 100644 packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetApplication.ts create mode 100644 packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetExportInjectable.ts rename packages/server/src/services/FinancialStatements/BalanceSheet/{BalanceSheetService.ts => BalanceSheetInjectable.ts} (96%) create mode 100644 packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetTableInjectable.ts create mode 100644 packages/server/src/services/FinancialStatements/CashFlow/CashflowExportInjectable.ts create mode 100644 packages/server/src/services/FinancialStatements/CashFlow/CashflowSheetApplication.ts create mode 100644 packages/server/src/services/FinancialStatements/CashFlow/CashflowTableInjectable.ts create mode 100644 packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryApplication.ts create mode 100644 packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryExportInjectable.ts create mode 100644 packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryTableInjectable.ts create mode 100644 packages/server/src/services/FinancialStatements/FinancialTableStructure.ts create mode 100644 packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsApplication.ts create mode 100644 packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsExportInjectable.ts create mode 100644 packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsTableInjectable.ts create mode 100644 packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetApplication.ts create mode 100644 packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetExportInjectable.ts create mode 100644 packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetTableInjectable.ts create mode 100644 packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryApplication.ts create mode 100644 packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryExportInjectable.ts create mode 100644 packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryTableInjectable.ts create mode 100644 packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersApplication.ts create mode 100644 packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersExportInjectable.ts rename packages/server/src/services/FinancialStatements/TransactionsByCustomer/{TransactionsByCustomersTableRows.ts => TransactionsByCustomersTable.ts} (81%) create mode 100644 packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersTableInjectable.ts create mode 100644 packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorApplication.ts create mode 100644 packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorExportInjectable.ts rename packages/server/src/services/FinancialStatements/TransactionsByVendor/{TransactionsByVendorService.ts => TransactionsByVendorInjectable.ts} (94%) rename packages/server/src/services/FinancialStatements/TransactionsByVendor/{TransactionsByVendorTableRows.ts => TransactionsByVendorTable.ts} (76%) create mode 100644 packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorTableInjectable.ts create mode 100644 packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceExportInjectable.ts create mode 100644 packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetApplication.ts rename packages/server/src/services/FinancialStatements/TrialBalanceSheet/{TrialBalanceSheetService.ts => TrialBalanceSheetInjectable.ts} (78%) create mode 100644 packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetTableInjectable.ts create mode 100644 packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryApplication.ts create mode 100644 packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryExportInjectable.ts create mode 100644 packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryTableInjectable.ts create mode 100644 packages/webapp/src/hooks/useDownloadFile.ts diff --git a/packages/server/package.json b/packages/server/package.json index d364e9b51d..c72ba7d89d 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -100,7 +100,8 @@ "tsyringe": "^4.3.0", "typedi": "^0.8.0", "uniqid": "^5.2.0", - "winston": "^3.2.1" + "winston": "^3.2.1", + "xlsx": "^0.18.5" }, "devDependencies": { "@types/lodash": "^4.14.158", diff --git a/packages/server/src/api/controllers/FinancialStatements/APAgingSummary.ts b/packages/server/src/api/controllers/FinancialStatements/APAgingSummary.ts index b0dc28841c..5d626896ca 100644 --- a/packages/server/src/api/controllers/FinancialStatements/APAgingSummary.ts +++ b/packages/server/src/api/controllers/FinancialStatements/APAgingSummary.ts @@ -2,19 +2,20 @@ import { Router, Request, Response, NextFunction } from 'express'; import { query } from 'express-validator'; import { Inject } from 'typedi'; import asyncMiddleware from '@/api/middleware/asyncMiddleware'; -import APAgingSummaryReportService from '@/services/FinancialStatements/AgingSummary/APAgingSummaryService'; import BaseFinancialReportController from './BaseFinancialReportController'; import { AbilitySubject, ReportsAction } from '@/interfaces'; import CheckPolicies from '@/api/middleware/CheckPolicies'; +import { ACCEPT_TYPE } from '@/interfaces/Http'; +import { APAgingSummaryApplication } from '@/services/FinancialStatements/AgingSummary/APAgingSummaryApplication'; export default class APAgingSummaryReportController extends BaseFinancialReportController { @Inject() - APAgingSummaryService: APAgingSummaryReportService; + private APAgingSummaryApp: APAgingSummaryApplication; /** * Router constructor. */ - router() { + public router() { const router = Router(); router.get( @@ -28,8 +29,9 @@ export default class APAgingSummaryReportController extends BaseFinancialReportC /** * Validation schema. + * @returns {ValidationChain[]} */ - get validationSchema() { + private get validationSchema() { return [ ...this.sheetNumberFormatValidationSchema, query('as_date').optional().isISO8601(), @@ -49,42 +51,58 @@ export default class APAgingSummaryReportController extends BaseFinancialReportC } /** - * Retrieve payable aging summary report. + * Retrieves payable aging summary report. + * @param {Request} req - + * @param {Response} res - + * @param {NextFunction} next - */ - async payableAgingSummary(req: Request, res: Response, next: NextFunction) { - const { tenantId, settings } = req; + private async payableAgingSummary( + req: Request, + res: Response, + next: NextFunction + ) { + const { tenantId } = req; const filter = this.matchedQueryData(req); try { const accept = this.accepts(req); - const acceptType = accept.types(['json', 'application/json+table']); + const acceptType = accept.types([ + ACCEPT_TYPE.APPLICATION_JSON, + ACCEPT_TYPE.APPLICATION_JSON_TABLE, + ACCEPT_TYPE.APPLICATION_CSV, + ACCEPT_TYPE.APPLICATION_XLSX, + ]); + // Retrieves the json table format. + if (ACCEPT_TYPE.APPLICATION_JSON_TABLE === acceptType) { + const table = await this.APAgingSummaryApp.table(tenantId, filter); - switch (acceptType) { - case 'application/json+table': - const table = await this.APAgingSummaryService.APAgingSummaryTable( - tenantId, - filter - ); - return res.status(200).send({ - table: { - rows: table.rows, - columns: table.columns, - }, - meta: table.meta, - query: table.query, - }); - break; - default: - const { data, columns, query, meta } = - await this.APAgingSummaryService.APAgingSummary(tenantId, filter); + return res.status(200).send(table); + // Retrieves the csv format. + } else if (ACCEPT_TYPE.APPLICATION_CSV === acceptType) { + const csv = await this.APAgingSummaryApp.csv(tenantId, filter); - return res.status(200).send({ - data: this.transfromToResponse(data), - columns: this.transfromToResponse(columns), - query: this.transfromToResponse(query), - meta: this.transfromToResponse(meta), - }); - break; + res.setHeader('Content-Disposition', 'attachment; filename=output.csv'); + res.setHeader('Content-Type', 'text/csv'); + + return res.send(csv); + // Retrieves the xlsx format. + } else if (ACCEPT_TYPE.APPLICATION_XLSX === acceptType) { + const buffer = await this.APAgingSummaryApp.xlsx(tenantId, filter); + + res.setHeader( + 'Content-Disposition', + 'attachment; filename=output.xlsx' + ); + res.setHeader( + 'Content-Type', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + ); + return res.send(buffer); + // Retrieves the json format. + } else { + const sheet = await this.APAgingSummaryApp.sheet(tenantId, filter); + + return res.status(200).send(sheet); } } catch (error) { next(error); diff --git a/packages/server/src/api/controllers/FinancialStatements/ARAgingSummary.ts b/packages/server/src/api/controllers/FinancialStatements/ARAgingSummary.ts index 489eb04aea..10e42e900d 100644 --- a/packages/server/src/api/controllers/FinancialStatements/ARAgingSummary.ts +++ b/packages/server/src/api/controllers/FinancialStatements/ARAgingSummary.ts @@ -5,16 +5,18 @@ import ARAgingSummaryService from '@/services/FinancialStatements/AgingSummary/A import BaseFinancialReportController from './BaseFinancialReportController'; import { AbilitySubject, ReportsAction } from '@/interfaces'; import CheckPolicies from '@/api/middleware/CheckPolicies'; +import { ARAgingSummaryApplication } from '@/services/FinancialStatements/AgingSummary/ARAgingSummaryApplication'; +import { ACCEPT_TYPE } from '@/interfaces/Http'; @Service() export default class ARAgingSummaryReportController extends BaseFinancialReportController { @Inject() - ARAgingSummaryService: ARAgingSummaryService; + ARAgingSummaryApp: ARAgingSummaryApplication; /** * Router constructor. */ - router() { + public router() { const router = Router(); router.get( @@ -30,7 +32,7 @@ export default class ARAgingSummaryReportController extends BaseFinancialReportC /** * AR aging summary validation roles. */ - get validationSchema() { + private get validationSchema() { return [ ...this.sheetNumberFormatValidationSchema, @@ -52,41 +54,53 @@ export default class ARAgingSummaryReportController extends BaseFinancialReportC /** * Retrieve AR aging summary report. + * @param {Request} req + * @param {Response} res */ - async receivableAgingSummary(req: Request, res: Response) { - const { tenantId, settings } = req; + private async receivableAgingSummary(req: Request, res: Response) { + const { tenantId } = req; const filter = this.matchedQueryData(req); try { const accept = this.accepts(req); - const acceptType = accept.types(['json', 'application/json+table']); - - switch (acceptType) { - case 'application/json+table': - const table = await this.ARAgingSummaryService.ARAgingSummaryTable( - tenantId, - filter - ); - return res.status(200).send({ - table: { - rows: table.rows, - columns: table.columns, - }, - meta: table.meta, - query: table.query, - }); - break; - default: - const { data, columns, query, meta } = - await this.ARAgingSummaryService.ARAgingSummary(tenantId, filter); - - return res.status(200).send({ - data: this.transfromToResponse(data), - columns: this.transfromToResponse(columns), - query: this.transfromToResponse(query), - meta: this.transfromToResponse(meta), - }); - break; + + const acceptType = accept.types([ + ACCEPT_TYPE.APPLICATION_JSON, + ACCEPT_TYPE.APPLICATION_JSON_TABLE, + ACCEPT_TYPE.APPLICATION_CSV, + ACCEPT_TYPE.APPLICATION_XLSX, + ]); + // Retrieves the xlsx format. + if (ACCEPT_TYPE.APPLICATION_XLSX === acceptType) { + const buffer = await this.ARAgingSummaryApp.xlsx(tenantId, filter); + + res.setHeader( + 'Content-Disposition', + 'attachment; filename=output.xlsx' + ); + res.setHeader( + 'Content-Type', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + ); + return res.send(buffer); + // Retrieves the table format. + } else if (ACCEPT_TYPE.APPLICATION_JSON_TABLE === acceptType) { + const table = await this.ARAgingSummaryApp.table(tenantId, filter); + + return res.status(200).send(table); + // Retrieves the csv format. + } else if (ACCEPT_TYPE.APPLICATION_CSV === acceptType) { + const buffer = await this.ARAgingSummaryApp.csv(tenantId, filter); + + res.setHeader('Content-Disposition', 'attachment; filename=output.csv'); + res.setHeader('Content-Type', 'text/csv'); + + return res.send(buffer); + // Retrieves the json format. + } else { + const sheet = await this.ARAgingSummaryApp.sheet(tenantId, filter); + + return res.status(200).send(sheet); } } catch (error) { console.log(error); diff --git a/packages/server/src/api/controllers/FinancialStatements/BalanceSheet.ts b/packages/server/src/api/controllers/FinancialStatements/BalanceSheet.ts index bc9499889d..0af53d723a 100644 --- a/packages/server/src/api/controllers/FinancialStatements/BalanceSheet.ts +++ b/packages/server/src/api/controllers/FinancialStatements/BalanceSheet.ts @@ -3,25 +3,21 @@ import { Router, Request, Response, NextFunction } from 'express'; import { query, ValidationChain } from 'express-validator'; import { castArray } from 'lodash'; import asyncMiddleware from '@/api/middleware/asyncMiddleware'; -import BalanceSheetStatementService from '@/services/FinancialStatements/BalanceSheet/BalanceSheetService'; import BaseFinancialReportController from './BaseFinancialReportController'; import { AbilitySubject, ReportsAction } from '@/interfaces'; import CheckPolicies from '@/api/middleware/CheckPolicies'; -import BalanceSheetTable from '@/services/FinancialStatements/BalanceSheet/BalanceSheetTable'; -import HasTenancyService from '@/services/Tenancy/TenancyService'; +import { BalanceSheetApplication } from '@/services/FinancialStatements/BalanceSheet/BalanceSheetApplication'; +import { ACCEPT_TYPE } from '@/interfaces/Http'; @Service() export default class BalanceSheetStatementController extends BaseFinancialReportController { @Inject() - balanceSheetService: BalanceSheetStatementService; - - @Inject() - tenancy: HasTenancyService; + private balanceSheetApp: BalanceSheetApplication; /** * Router constructor. */ - router() { + public router() { const router = Router(); router.get( @@ -38,7 +34,7 @@ export default class BalanceSheetStatementController extends BaseFinancialReport * Balance sheet validation schecma. * @returns {ValidationChain[]} */ - get balanceSheetValidationSchema(): ValidationChain[] { + private get balanceSheetValidationSchema(): ValidationChain[] { return [ ...this.sheetNumberFormatValidationSchema, query('accounting_method').optional().isIn(['cash', 'accrual']), @@ -84,10 +80,12 @@ export default class BalanceSheetStatementController extends BaseFinancialReport /** * Retrieve the balance sheet. + * @param {Request} req + * @param {Response} res + * @param {NextFunction} next */ - async balanceSheet(req: Request, res: Response, next: NextFunction) { - const { tenantId, settings } = req; - const i18n = this.tenancy.i18n(tenantId); + private async balanceSheet(req: Request, res: Response, next: NextFunction) { + const { tenantId } = req; let filter = this.matchedQueryData(req); @@ -95,29 +93,45 @@ export default class BalanceSheetStatementController extends BaseFinancialReport ...filter, accountsIds: castArray(filter.accountsIds), }; - try { - const { data, columns, query, meta } = - await this.balanceSheetService.balanceSheet(tenantId, filter); - const accept = this.accepts(req); - const acceptType = accept.types(['json', 'application/json+table']); - - const table = new BalanceSheetTable(data, query, i18n); - - switch (acceptType) { - case 'application/json+table': - return res.status(200).send({ - table: { - rows: table.tableRows(), - columns: table.tableColumns(), - }, - query, - meta, - }); - case 'json': - default: - return res.status(200).send({ data, columns, query, meta }); + + const acceptType = accept.types([ + ACCEPT_TYPE.APPLICATION_JSON, + ACCEPT_TYPE.APPLICATION_JSON_TABLE, + ACCEPT_TYPE.APPLICATION_XLSX, + ACCEPT_TYPE.APPLICATION_CSV, + ]); + // Retrieves the json table format. + if (ACCEPT_TYPE.APPLICATION_JSON_TABLE == acceptType) { + const table = await this.balanceSheetApp.table(tenantId, filter); + + return res.status(200).send(table); + // Retrieves the csv format. + } else if (ACCEPT_TYPE.APPLICATION_CSV === acceptType) { + const buffer = await this.balanceSheetApp.csv(tenantId, filter); + + res.setHeader('Content-Disposition', 'attachment; filename=output.csv'); + res.setHeader('Content-Type', 'text/csv'); + + return res.send(buffer); + // Retrieves the xlsx format. + } else if (ACCEPT_TYPE.APPLICATION_XLSX === acceptType) { + const buffer = await this.balanceSheetApp.xlsx(tenantId, filter); + + res.setHeader( + 'Content-Disposition', + 'attachment; filename=output.xlsx' + ); + res.setHeader( + 'Content-Type', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + ); + return res.send(buffer); + } else { + const sheet = await this.balanceSheetApp.sheet(tenantId, filter); + + return res.status(200).send(sheet); } } catch (error) { next(error); diff --git a/packages/server/src/api/controllers/FinancialStatements/CashFlow/CashFlow.ts b/packages/server/src/api/controllers/FinancialStatements/CashFlow/CashFlow.ts index df2f3f5dd5..bab04246d1 100644 --- a/packages/server/src/api/controllers/FinancialStatements/CashFlow/CashFlow.ts +++ b/packages/server/src/api/controllers/FinancialStatements/CashFlow/CashFlow.ts @@ -8,29 +8,20 @@ import { ValidationChain, } from 'express'; import BaseFinancialReportController from '../BaseFinancialReportController'; -import CashFlowStatementService from '@/services/FinancialStatements/CashFlow/CashFlowService'; -import { - ICashFlowStatementDOO, - ICashFlowStatement, - AbilitySubject, - ReportsAction, -} from '@/interfaces'; -import CashFlowTable from '@/services/FinancialStatements/CashFlow/CashFlowTable'; -import HasTenancyService from '@/services/Tenancy/TenancyService'; +import { AbilitySubject, ReportsAction } from '@/interfaces'; import CheckPolicies from '@/api/middleware/CheckPolicies'; +import { ACCEPT_TYPE } from '@/interfaces/Http'; +import { CashflowSheetApplication } from '@/services/FinancialStatements/CashFlow/CashflowSheetApplication'; @Service() export default class CashFlowController extends BaseFinancialReportController { @Inject() - cashFlowService: CashFlowStatementService; - - @Inject() - tenancy: HasTenancyService; + private cashflowSheetApp: CashflowSheetApplication; /** * Router constructor. */ - router() { + public router() { const router = Router(); router.get( @@ -47,7 +38,7 @@ export default class CashFlowController extends BaseFinancialReportController { * Balance sheet validation schecma. * @returns {ValidationChain[]} */ - get cashflowValidationSchema(): ValidationChain[] { + private get cashflowValidationSchema(): ValidationChain[] { return [ ...this.sheetNumberFormatValidationSchema, query('from_date').optional(), @@ -67,41 +58,6 @@ export default class CashFlowController extends BaseFinancialReportController { ]; } - /** - * Retrieve the cashflow statment to json response. - * @param {ICashFlowStatement} cashFlow - - */ - private transformJsonResponse(cashFlowDOO: ICashFlowStatementDOO) { - const { data, query, meta } = cashFlowDOO; - - return { - data: this.transfromToResponse(data), - query: this.transfromToResponse(query), - meta: this.transfromToResponse(meta), - }; - } - - /** - * Transformes the report statement to table rows. - * @param {ITransactionsByVendorsStatement} statement - - */ - private transformToTableRows( - cashFlowDOO: ICashFlowStatementDOO, - tenantId: number - ) { - const i18n = this.tenancy.i18n(tenantId); - const cashFlowTable = new CashFlowTable(cashFlowDOO, i18n); - - return { - table: { - data: cashFlowTable.tableRows(), - columns: cashFlowTable.tableColumns(), - }, - query: this.transfromToResponse(cashFlowDOO.query), - meta: this.transfromToResponse(cashFlowDOO.meta), - }; - } - /** * Retrieve the cash flow statment. * @param {Request} req @@ -109,26 +65,52 @@ export default class CashFlowController extends BaseFinancialReportController { * @param {NextFunction} next * @returns {Response} */ - async cashFlow(req: Request, res: Response, next: NextFunction) { - const { tenantId, settings } = req; + public async cashFlow(req: Request, res: Response, next: NextFunction) { + const { tenantId } = req; const filter = { ...this.matchedQueryData(req), }; try { - const cashFlow = await this.cashFlowService.cashFlow(tenantId, filter); - const accept = this.accepts(req); - const acceptType = accept.types(['json', 'application/json+table']); - switch (acceptType) { - case 'application/json+table': - return res - .status(200) - .send(this.transformToTableRows(cashFlow, tenantId)); - case 'json': - default: - return res.status(200).send(this.transformJsonResponse(cashFlow)); + const acceptType = accept.types([ + ACCEPT_TYPE.APPLICATION_JSON, + ACCEPT_TYPE.APPLICATION_JSON_TABLE, + ACCEPT_TYPE.APPLICATION_CSV, + ACCEPT_TYPE.APPLICATION_XLSX, + ]); + // Retrieves the json table format. + if (ACCEPT_TYPE.APPLICATION_JSON_TABLE === acceptType) { + const table = await this.cashflowSheetApp.table(tenantId, filter); + + return res.status(200).send(table); + // Retrieves the csv format. + } else if (ACCEPT_TYPE.APPLICATION_CSV === acceptType) { + const buffer = await this.cashflowSheetApp.csv(tenantId, filter); + + res.setHeader('Content-Disposition', 'attachment; filename=output.csv'); + res.setHeader('Content-Type', 'text/csv'); + + return res.status(200).send(buffer); + // Retrieves the pdf format. + } else if (ACCEPT_TYPE.APPLICATION_XLSX === acceptType) { + const buffer = await this.cashflowSheetApp.xlsx(tenantId, filter); + + res.setHeader( + 'Content-Disposition', + 'attachment; filename=output.xlsx' + ); + res.setHeader( + 'Content-Type', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + ); + return res.send(buffer); + // Retrieves the json format. + } else { + const cashflow = await this.cashflowSheetApp.sheet(tenantId, filter); + + return res.status(200).send(cashflow); } } catch (error) { next(error); diff --git a/packages/server/src/api/controllers/FinancialStatements/CustomerBalanceSummary/index.ts b/packages/server/src/api/controllers/FinancialStatements/CustomerBalanceSummary/index.ts index eb026e7527..6c10543f5a 100644 --- a/packages/server/src/api/controllers/FinancialStatements/CustomerBalanceSummary/index.ts +++ b/packages/server/src/api/controllers/FinancialStatements/CustomerBalanceSummary/index.ts @@ -1,29 +1,21 @@ import { Router, Request, Response, NextFunction } from 'express'; import { query } from 'express-validator'; import { Inject } from 'typedi'; -import { - AbilitySubject, - ICustomerBalanceSummaryStatement, - ReportsAction, -} from '@/interfaces'; +import { AbilitySubject, ReportsAction } from '@/interfaces'; import asyncMiddleware from '@/api/middleware/asyncMiddleware'; -import CustomerBalanceSummary from '@/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryService'; import BaseFinancialReportController from '../BaseFinancialReportController'; -import CustomerBalanceSummaryTableRows from '@/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryTableRows'; import CheckPolicies from '@/api/middleware/CheckPolicies'; -import HasTenancyService from '@/services/Tenancy/TenancyService'; +import { ACCEPT_TYPE } from '@/interfaces/Http'; +import { CustomerBalanceSummaryApplication } from '@/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryApplication'; export default class CustomerBalanceSummaryReportController extends BaseFinancialReportController { @Inject() - customerBalanceSummaryService: CustomerBalanceSummary; - - @Inject() - tenancy: HasTenancyService; + private customerBalanceSummaryApp: CustomerBalanceSummaryApplication; /** * Router constructor. */ - router() { + public router() { const router = Router(); router.get( @@ -42,7 +34,7 @@ export default class CustomerBalanceSummaryReportController extends BaseFinancia /** * Validation schema. */ - get validationSchema() { + private get validationSchema() { return [ ...this.sheetNumberFormatValidationSchema, @@ -62,75 +54,67 @@ export default class CustomerBalanceSummaryReportController extends BaseFinancia ]; } - /** - * Transformes the balance summary statement to table rows. - * @param {ICustomerBalanceSummaryStatement} statement - - */ - private transformToTableRows( - tenantId, - { data, query }: ICustomerBalanceSummaryStatement - ) { - const i18n = this.tenancy.i18n(tenantId); - const tableRows = new CustomerBalanceSummaryTableRows(data, query, i18n); - - return { - table: { - columns: tableRows.tableColumns(), - data: tableRows.tableRows(), - }, - query: this.transfromToResponse(query), - }; - } - - /** - * Transformes the balance summary statement to raw json. - * @param {ICustomerBalanceSummaryStatement} customerBalance - - */ - private transformToJsonResponse({ - data, - columns, - query, - }: ICustomerBalanceSummaryStatement) { - return { - data: this.transfromToResponse(data), - columns: this.transfromToResponse(columns), - query: this.transfromToResponse(query), - }; - } - /** * Retrieve payable aging summary report. * @param {Request} req - * @param {Response} res - * @param {NextFunction} next - */ - async customerBalanceSummary( + private async customerBalanceSummary( req: Request, res: Response, next: NextFunction ) { - const { tenantId, settings } = req; + const { tenantId } = req; const filter = this.matchedQueryData(req); try { - const customerBalanceSummary = - await this.customerBalanceSummaryService.customerBalanceSummary( + const accept = this.accepts(req); + const acceptType = accept.types([ + ACCEPT_TYPE.APPLICATION_JSON, + ACCEPT_TYPE.APPLICATION_JSON_TABLE, + ACCEPT_TYPE.APPLICATION_CSV, + ACCEPT_TYPE.APPLICATION_XLSX, + ]); + + // Retrieves the xlsx format. + if (ACCEPT_TYPE.APPLICATION_XLSX === acceptType) { + const buffer = await this.customerBalanceSummaryApp.xlsx( tenantId, filter ); - const accept = this.accepts(req); - const acceptType = accept.types(['json', 'application/json+table']); + res.setHeader( + 'Content-Disposition', + 'attachment; filename=output.xlsx' + ); + res.setHeader( + 'Content-Type', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + ); + return res.send(buffer); + // Retrieves the csv format. + } else if (ACCEPT_TYPE.APPLICATION_CSV === acceptType) { + const buffer = await this.customerBalanceSummaryApp.csv( + tenantId, + filter + ); + res.setHeader('Content-Disposition', 'attachment; filename=output.csv'); + res.setHeader('Content-Type', 'text/csv'); - switch (acceptType) { - case 'application/json+table': - return res - .status(200) - .send(this.transformToTableRows(tenantId, customerBalanceSummary)); - case 'application/json': - default: - return res - .status(200) - .send(this.transformToJsonResponse(customerBalanceSummary)); + return res.send(buffer); + // Retrieves the json table format. + } else if (ACCEPT_TYPE.APPLICATION_JSON_TABLE === acceptType) { + const table = await this.customerBalanceSummaryApp.table( + tenantId, + filter + ); + return res.status(200).send(table); + } else { + const sheet = await this.customerBalanceSummaryApp.sheet( + tenantId, + filter + ); + return res.status(200).send(sheet); } } catch (error) { next(error); diff --git a/packages/server/src/api/controllers/FinancialStatements/InventoryDetails/index.ts b/packages/server/src/api/controllers/FinancialStatements/InventoryDetails/index.ts index 2f8df77220..07f91af4a7 100644 --- a/packages/server/src/api/controllers/FinancialStatements/InventoryDetails/index.ts +++ b/packages/server/src/api/controllers/FinancialStatements/InventoryDetails/index.ts @@ -8,24 +8,20 @@ import { ValidationChain, } from 'express'; import BaseController from '@/api/controllers/BaseController'; -import InventoryDetailsService from '@/services/FinancialStatements/InventoryDetails/InventoryDetailsService'; -import InventoryDetailsTable from '@/services/FinancialStatements/InventoryDetails/InventoryDetailsTable'; -import HasTenancyService from '@/services/Tenancy/TenancyService'; import { AbilitySubject, ReportsAction } from '@/interfaces'; +import { InventortyDetailsApplication } from '@/services/FinancialStatements/InventoryDetails/InventoryDetailsApplication'; import CheckPolicies from '@/api/middleware/CheckPolicies'; +import { ACCEPT_TYPE } from '@/interfaces/Http'; @Service() export default class InventoryDetailsController extends BaseController { @Inject() - inventoryDetailsService: InventoryDetailsService; - - @Inject() - tenancy: HasTenancyService; + private inventoryItemDetailsApp: InventortyDetailsApplication; /** * Router constructor. */ - router() { + public router() { const router = Router(); router.get( @@ -45,7 +41,7 @@ export default class InventoryDetailsController extends BaseController { * Balance sheet validation schecma. * @returns {ValidationChain[]} */ - get validationSchema(): ValidationChain[] { + private get validationSchema(): ValidationChain[] { return [ query('number_format.precision') .optional() @@ -77,69 +73,66 @@ export default class InventoryDetailsController extends BaseController { } /** - * Retrieve the cashflow statment to json response. - * @param {ICashFlowStatement} cashFlow - - */ - private transformJsonResponse(inventoryDetails) { - const { data, query, meta } = inventoryDetails; - - return { - data: this.transfromToResponse(data), - query: this.transfromToResponse(query), - meta: this.transfromToResponse(meta), - }; - } - - /** - * Transformes the report statement to table rows. - */ - private transformToTableRows(inventoryDetails, tenantId: number) { - const i18n = this.tenancy.i18n(tenantId); - const inventoryDetailsTable = new InventoryDetailsTable( - inventoryDetails, - i18n - ); - - return { - table: { - data: inventoryDetailsTable.tableData(), - columns: inventoryDetailsTable.tableColumns(), - }, - query: this.transfromToResponse(inventoryDetails.query), - meta: this.transfromToResponse(inventoryDetails.meta), - }; - } - - /** - * Retrieve the cash flow statment. + * Retrieve the inventory item details sheet. * @param {Request} req * @param {Response} res * @param {NextFunction} next * @returns {Response} */ - async inventoryDetails(req: Request, res: Response, next: NextFunction) { - const { tenantId, settings } = req; + private async inventoryDetails( + req: Request, + res: Response, + next: NextFunction + ) { + const { tenantId } = req; const filter = { ...this.matchedQueryData(req), }; try { - const inventoryDetails = - await this.inventoryDetailsService.inventoryDetails(tenantId, filter); - const accept = this.accepts(req); - const acceptType = accept.types(['json', 'application/json+table']); - - switch (acceptType) { - case 'application/json+table': - return res - .status(200) - .send(this.transformToTableRows(inventoryDetails, tenantId)); - case 'json': - default: - return res - .status(200) - .send(this.transformJsonResponse(inventoryDetails)); + const acceptType = accept.types([ + ACCEPT_TYPE.APPLICATION_JSON, + ACCEPT_TYPE.APPLICATION_JSON_TABLE, + ACCEPT_TYPE.APPLICATION_CSV, + ACCEPT_TYPE.APPLICATION_XLSX, + ]); + // Retrieves the csv format. + if (acceptType === ACCEPT_TYPE.APPLICATION_CSV) { + const buffer = await this.inventoryItemDetailsApp.csv(tenantId, filter); + + res.setHeader('Content-Disposition', 'attachment; filename=output.csv'); + res.setHeader('Content-Type', 'text/csv'); + + return res.send(buffer); + // Retrieves the xlsx format. + } else if (acceptType === ACCEPT_TYPE.APPLICATION_XLSX) { + const buffer = await this.inventoryItemDetailsApp.xlsx( + tenantId, + filter + ); + res.setHeader( + 'Content-Disposition', + 'attachment; filename=output.xlsx' + ); + res.setHeader( + 'Content-Type', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + ); + return res.send(buffer); + // Retrieves the json table format. + } else if (acceptType === ACCEPT_TYPE.APPLICATION_JSON_TABLE) { + const table = await this.inventoryItemDetailsApp.table( + tenantId, + filter + ); + return res.status(200).send(table); + } else { + const sheet = await this.inventoryItemDetailsApp.sheet( + tenantId, + filter + ); + return res.status(200).send(sheet); } } catch (error) { next(error); diff --git a/packages/server/src/api/controllers/FinancialStatements/ProfitLossSheet.ts b/packages/server/src/api/controllers/FinancialStatements/ProfitLossSheet.ts index 233654dc00..8c24043351 100644 --- a/packages/server/src/api/controllers/FinancialStatements/ProfitLossSheet.ts +++ b/packages/server/src/api/controllers/FinancialStatements/ProfitLossSheet.ts @@ -1,24 +1,20 @@ import { Service, Inject } from 'typedi'; import { Router, Request, Response, NextFunction } from 'express'; import { query, ValidationChain } from 'express-validator'; -import ProfitLossSheetService from '@/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetService'; import BaseFinancialReportController from './BaseFinancialReportController'; import CheckPolicies from '@/api/middleware/CheckPolicies'; import { AbilitySubject, ReportsAction } from '@/interfaces'; -import { ProfitLossSheetTable } from '@/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetTable'; -import HasTenancyService from '@/services/Tenancy/TenancyService'; +import { ACCEPT_TYPE } from '@/interfaces/Http'; +import { ProfitLossSheetApplication } from '@/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetApplication'; @Service() export default class ProfitLossSheetController extends BaseFinancialReportController { @Inject() - profitLossSheetService: ProfitLossSheetService; - - @Inject() - tenancy: HasTenancyService; + private profitLossSheetApp: ProfitLossSheetApplication; /** * Router constructor. */ - router() { + public router() { const router = Router(); router.get( @@ -34,7 +30,7 @@ export default class ProfitLossSheetController extends BaseFinancialReportContro /** * Validation schema. */ - get validationSchema(): ValidationChain[] { + private get validationSchema(): ValidationChain[] { return [ ...this.sheetNumberFormatValidationSchema, query('basis').optional(), @@ -85,37 +81,54 @@ export default class ProfitLossSheetController extends BaseFinancialReportContro * @param {Request} req - * @param {Response} res - */ - async profitLossSheet(req: Request, res: Response, next: NextFunction) { - const { tenantId, settings } = req; - const i18n = this.tenancy.i18n(tenantId); + private async profitLossSheet( + req: Request, + res: Response, + next: NextFunction + ) { + const { tenantId } = req; const filter = this.matchedQueryData(req); + const accept = this.accepts(req); + + const acceptType = accept.types([ + ACCEPT_TYPE.APPLICATION_JSON, + ACCEPT_TYPE.APPLICATION_JSON_TABLE, + ACCEPT_TYPE.APPLICATION_CSV, + ACCEPT_TYPE.APPLICATION_XLSX, + ]); try { - const { data, query, meta } = - await this.profitLossSheetService.profitLossSheet(tenantId, filter); - - const accept = this.accepts(req); - const acceptType = accept.types(['json', 'application/json+table']); - - switch (acceptType) { - case 'application/json+table': - const table = new ProfitLossSheetTable(data, query, i18n); - - return res.status(200).send({ - table: { - rows: table.tableRows(), - columns: table.tableColumns(), - }, - query, - meta, - }); - case 'json': - default: - return res.status(200).send({ - data, - query, - meta, - }); + // Retrieves the csv format. + if (acceptType === ACCEPT_TYPE.APPLICATION_CSV) { + const sheet = await this.profitLossSheetApp.csv(tenantId, filter); + + res.setHeader('Content-Disposition', 'attachment; filename=output.csv'); + res.setHeader('Content-Type', 'text/csv'); + + return res.send(sheet); + // Retrieves the json table format. + } else if (acceptType === ACCEPT_TYPE.APPLICATION_JSON_TABLE) { + const table = await this.profitLossSheetApp.table(tenantId, filter); + + return res.status(200).send(table); + // Retrieves the xlsx format. + } else if (acceptType === ACCEPT_TYPE.APPLICATION_XLSX) { + const sheet = await this.profitLossSheetApp.xlsx(tenantId, filter); + + res.setHeader( + 'Content-Disposition', + 'attachment; filename=output.xlsx' + ); + res.setHeader( + 'Content-Type', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + ); + return res.send(sheet); + // Retrieves the json format. + } else { + const sheet = await this.profitLossSheetApp.sheet(tenantId, filter); + + return res.status(200).send(sheet); } } catch (error) { next(error); diff --git a/packages/server/src/api/controllers/FinancialStatements/SalesByItems.ts b/packages/server/src/api/controllers/FinancialStatements/SalesByItems.ts index 759165bd1d..d31954398c 100644 --- a/packages/server/src/api/controllers/FinancialStatements/SalesByItems.ts +++ b/packages/server/src/api/controllers/FinancialStatements/SalesByItems.ts @@ -16,15 +16,12 @@ export default class SalesByItemsReportController extends BaseFinancialReportCon /** * Router constructor. */ - router() { + public router() { const router = Router(); router.get( '/', - CheckPolicies( - ReportsAction.READ_SALES_BY_ITEMS, - AbilitySubject.Report - ), + CheckPolicies(ReportsAction.READ_SALES_BY_ITEMS, AbilitySubject.Report), this.validationSchema, this.validationResult, asyncMiddleware(this.purchasesByItems.bind(this)) @@ -35,7 +32,7 @@ export default class SalesByItemsReportController extends BaseFinancialReportCon /** * Validation schema. */ - get validationSchema(): ValidationChain[] { + private get validationSchema(): ValidationChain[] { return [ query('from_date').optional().isISO8601(), query('to_date').optional().isISO8601(), @@ -63,7 +60,11 @@ export default class SalesByItemsReportController extends BaseFinancialReportCon * @param {Request} req - * @param {Response} res - */ - async purchasesByItems(req: Request, res: Response, next: NextFunction) { + private async purchasesByItems( + req: Request, + res: Response, + next: NextFunction + ) { const { tenantId } = req; const filter = this.matchedQueryData(req); diff --git a/packages/server/src/api/controllers/FinancialStatements/SalesTaxLiabilitySummary/index.ts b/packages/server/src/api/controllers/FinancialStatements/SalesTaxLiabilitySummary/index.ts index 56c8372888..933b5c9c42 100644 --- a/packages/server/src/api/controllers/FinancialStatements/SalesTaxLiabilitySummary/index.ts +++ b/packages/server/src/api/controllers/FinancialStatements/SalesTaxLiabilitySummary/index.ts @@ -1,20 +1,21 @@ +import { Inject } from 'typedi'; import { Router, Request, Response, NextFunction } from 'express'; import { query } from 'express-validator'; -import { Inject } from 'typedi'; import asyncMiddleware from '@/api/middleware/asyncMiddleware'; import BaseFinancialReportController from '../BaseFinancialReportController'; import { AbilitySubject, ReportsAction } from '@/interfaces'; import CheckPolicies from '@/api/middleware/CheckPolicies'; -import { SalesTaxLiabilitySummaryService } from '@/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryService'; +import { SalesTaxLiabilitySummaryApplication } from '@/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryApplication'; +import { ACCEPT_TYPE } from '@/interfaces/Http'; export default class SalesTaxLiabilitySummary extends BaseFinancialReportController { @Inject() - private salesTaxLiabilitySummaryService: SalesTaxLiabilitySummaryService; + private salesTaxLiabilitySummaryApp: SalesTaxLiabilitySummaryApplication; /** * Router constructor. */ - router() { + public router() { const router = Router(); router.get( @@ -31,8 +32,9 @@ export default class SalesTaxLiabilitySummary extends BaseFinancialReportControl /** * Validation schema. + * @returns {ValidationChain[]} */ - get validationSchema() { + private get validationSchema() { return [ query('from_date').optional().isISO8601(), query('to_date').optional().isISO8601(), @@ -45,7 +47,7 @@ export default class SalesTaxLiabilitySummary extends BaseFinancialReportControl * @param {Response} res - * @param {NextFunction} next - */ - async salesTaxLiabilitySummary( + private async salesTaxLiabilitySummary( req: Request, res: Response, next: NextFunction @@ -55,33 +57,52 @@ export default class SalesTaxLiabilitySummary extends BaseFinancialReportControl try { const accept = this.accepts(req); - const acceptType = accept.types(['json', 'application/json+table']); + const acceptType = accept.types([ + ACCEPT_TYPE.APPLICATION_JSON, + ACCEPT_TYPE.APPLICATION_JSON_TABLE, + ACCEPT_TYPE.APPLICATION_CSV, + ACCEPT_TYPE.APPLICATION_XLSX, + ]); - switch (acceptType) { - case 'application/json+table': - const salesTaxLiabilityTable = - await this.salesTaxLiabilitySummaryService.salesTaxLiabilitySummaryTable( - tenantId, - filter - ); + // Retrieves the json table format. + if (acceptType === ACCEPT_TYPE.APPLICATION_JSON_TABLE) { + const table = await this.salesTaxLiabilitySummaryApp.table( + tenantId, + filter + ); + return res.status(200).send(table); + // Retrieves the xlsx format. + } else if (acceptType === ACCEPT_TYPE.APPLICATION_XLSX) { + const buffer = await this.salesTaxLiabilitySummaryApp.xlsx( + tenantId, + filter + ); + res.setHeader( + 'Content-Disposition', + 'attachment; filename=output.xlsx' + ); + res.setHeader( + 'Content-Type', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + ); + return res.send(buffer); + // Retrieves the csv format. + } else if (acceptType === ACCEPT_TYPE.APPLICATION_CSV) { + const buffer = await this.salesTaxLiabilitySummaryApp.csv( + tenantId, + filter + ); + res.setHeader('Content-Disposition', 'attachment; filename=output.csv'); + res.setHeader('Content-Type', 'text/csv'); - return res.status(200).send({ - table: salesTaxLiabilityTable.table, - query: salesTaxLiabilityTable.query, - meta: salesTaxLiabilityTable.meta, - }); - case 'json': - default: - const salesTaxLiability = - await this.salesTaxLiabilitySummaryService.salesTaxLiability( - tenantId, - filter - ); - return res.status(200).send({ - data: salesTaxLiability.data, - query: salesTaxLiability.query, - meta: salesTaxLiability.meta, - }); + return res.send(buffer); + // Retrieves the json format. + } else { + const sheet = await this.salesTaxLiabilitySummaryApp.sheet( + tenantId, + filter + ); + return res.status(200).send(sheet); } } catch (error) { next(error); diff --git a/packages/server/src/api/controllers/FinancialStatements/TransactionsByCustomers/index.ts b/packages/server/src/api/controllers/FinancialStatements/TransactionsByCustomers/index.ts index fa20ea3f34..4bc3b1f44b 100644 --- a/packages/server/src/api/controllers/FinancialStatements/TransactionsByCustomers/index.ts +++ b/packages/server/src/api/controllers/FinancialStatements/TransactionsByCustomers/index.ts @@ -1,30 +1,22 @@ import { Router, Request, Response, NextFunction } from 'express'; import { query } from 'express-validator'; import { Inject, Service } from 'typedi'; -import { - AbilitySubject, - ITransactionsByCustomersStatement, - ReportsAction, -} from '@/interfaces'; +import { AbilitySubject, ReportsAction } from '@/interfaces'; import asyncMiddleware from '@/api/middleware/asyncMiddleware'; import BaseFinancialReportController from '../BaseFinancialReportController'; -import TransactionsByCustomersService from '@/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersService'; -import TransactionsByCustomersTableRows from '@/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersTableRows'; -import HasTenancyService from '@/services/Tenancy/TenancyService'; import CheckPolicies from '@/api/middleware/CheckPolicies'; +import { TransactionsByCustomerApplication } from '@/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersApplication'; +import { ACCEPT_TYPE } from '@/interfaces/Http'; @Service() export default class TransactionsByCustomersReportController extends BaseFinancialReportController { @Inject() - transactionsByCustomersService: TransactionsByCustomersService; - - @Inject() - tenancy: HasTenancyService; + private transactionsByCustomersApp: TransactionsByCustomerApplication; /** * Router constructor. */ - router() { + public router() { const router = Router(); router.get( @@ -58,45 +50,13 @@ export default class TransactionsByCustomersReportController extends BaseFinanci ]; } - /** - * Transformes the statement to table rows response. - * @param {ITransactionsByCustomersStatement} statement - - */ - private transformToTableResponse(customersTransactions, tenantId) { - const i18n = this.tenancy.i18n(tenantId); - const table = new TransactionsByCustomersTableRows( - customersTransactions, - i18n - ); - return { - table: { - rows: table.tableRows(), - }, - }; - } - - /** - * Transformes the statement to json response. - * @param {ITransactionsByCustomersStatement} statement - - */ - private transfromToJsonResponse( - data, - columns - ): ITransactionsByCustomersStatement { - return { - data: this.transfromToResponse(data), - columns: this.transfromToResponse(columns), - query: this.transfromToResponse(query), - }; - } - /** * Retrieve payable aging summary report. * @param {Request} req - * @param {Response} res - * @param {NextFunction} next - */ - async transactionsByCustomers( + private async transactionsByCustomers( req: Request, res: Response, next: NextFunction @@ -104,25 +64,51 @@ export default class TransactionsByCustomersReportController extends BaseFinanci const { tenantId } = req; const filter = this.matchedQueryData(req); + const accept = this.accepts(req); + const acceptType = accept.types([ + ACCEPT_TYPE.APPLICATION_JSON, + ACCEPT_TYPE.APPLICATION_JSON_TABLE, + ACCEPT_TYPE.APPLICATION_CSV, + ACCEPT_TYPE.APPLICATION_XLSX, + ]); try { - const report = - await this.transactionsByCustomersService.transactionsByCustomers( + // Retrieves the json table format. + if (ACCEPT_TYPE.APPLICATION_JSON_TABLE === acceptType) { + const table = await this.transactionsByCustomersApp.table( tenantId, filter ); - const accept = this.accepts(req); - const acceptType = accept.types(['json', 'application/json+table']); + return res.status(200).send(table); + // Retrieve the csv format. + } else if (ACCEPT_TYPE.APPLICATION_CSV === acceptType) { + const csv = await this.transactionsByCustomersApp.csv(tenantId, filter); + + res.setHeader('Content-Disposition', 'attachment; filename=output.csv'); + res.setHeader('Content-Type', 'text/csv'); - switch (acceptType) { - case 'json': - return res - .status(200) - .send(this.transfromToJsonResponse(report.data, report.columns)); - case 'application/json+table': - default: - return res - .status(200) - .send(this.transformToTableResponse(report.data, tenantId)); + return res.send(csv); + // Retrieve the xlsx format. + } else if (ACCEPT_TYPE.APPLICATION_XLSX === acceptType) { + const buffer = await this.transactionsByCustomersApp.xlsx( + tenantId, + filter + ); + res.setHeader( + 'Content-Disposition', + 'attachment; filename=output.xlsx' + ); + res.setHeader( + 'Content-Type', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + ); + return res.send(buffer); + // Retrieve the json format. + } else { + const sheet = await this.transactionsByCustomersApp.sheet( + tenantId, + filter + ); + return res.status(200).send(sheet); } } catch (error) { next(error); diff --git a/packages/server/src/api/controllers/FinancialStatements/TransactionsByVendors/index.ts b/packages/server/src/api/controllers/FinancialStatements/TransactionsByVendors/index.ts index eaf8e67253..a0c1bf0374 100644 --- a/packages/server/src/api/controllers/FinancialStatements/TransactionsByVendors/index.ts +++ b/packages/server/src/api/controllers/FinancialStatements/TransactionsByVendors/index.ts @@ -3,27 +3,19 @@ import { query, ValidationChain } from 'express-validator'; import { Inject } from 'typedi'; import asyncMiddleware from '@/api/middleware/asyncMiddleware'; import BaseFinancialReportController from '../BaseFinancialReportController'; -import TransactionsByVendorsTableRows from '@/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorTableRows'; -import TransactionsByVendorsService from '@/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorService'; -import { - AbilitySubject, - ITransactionsByVendorsStatement, - ReportsAction, -} from '@/interfaces'; -import HasTenancyService from '@/services/Tenancy/TenancyService'; +import { AbilitySubject, ReportsAction } from '@/interfaces'; import CheckPolicies from '@/api/middleware/CheckPolicies'; +import { ACCEPT_TYPE } from '@/interfaces/Http'; +import { TransactionsByVendorApplication } from '@/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorApplication'; export default class TransactionsByVendorsReportController extends BaseFinancialReportController { @Inject() - transactionsByVendorsService: TransactionsByVendorsService; - - @Inject() - tenancy: HasTenancyService; + private transactionsByVendorsApp: TransactionsByVendorApplication; /** * Router constructor. */ - router() { + public router() { const router = Router(); router.get( @@ -42,7 +34,7 @@ export default class TransactionsByVendorsReportController extends BaseFinancial /** * Validation schema. */ - get validationSchema(): ValidationChain[] { + private get validationSchema(): ValidationChain[] { return [ ...this.sheetNumberFormatValidationSchema, @@ -58,64 +50,64 @@ export default class TransactionsByVendorsReportController extends BaseFinancial ]; } - /** - * Transformes the report statement to table rows. - * @param {ITransactionsByVendorsStatement} statement - - */ - private transformToTableRows(tenantId: number, transactions: any[]) { - const i18n = this.tenancy.i18n(tenantId); - const table = new TransactionsByVendorsTableRows(transactions, i18n); - - return { - table: { - data: table.tableRows(), - }, - }; - } - - /** - * Transformes the report statement to json response. - * @param {ITransactionsByVendorsStatement} statement - - */ - private transformToJsonResponse({ - data, - columns, - query, - }: ITransactionsByVendorsStatement) { - return { - data: this.transfromToResponse(data), - columns: this.transfromToResponse(columns), - query: this.transfromToResponse(query), - }; - } - /** * Retrieve payable aging summary report. * @param {Request} req - * @param {Response} res - * @param {NextFunction} next - */ - async transactionsByVendors(req: Request, res: Response, next: NextFunction) { + private async transactionsByVendors( + req: Request, + res: Response, + next: NextFunction + ) { const { tenantId } = req; const filter = this.matchedQueryData(req); try { - const report = - await this.transactionsByVendorsService.transactionsByVendors( + const accept = this.accepts(req); + const acceptType = accept.types([ + ACCEPT_TYPE.APPLICATION_JSON, + ACCEPT_TYPE.APPLICATION_JSON_TABLE, + ACCEPT_TYPE.APPLICATION_CSV, + ACCEPT_TYPE.APPLICATION_XLSX, + ]); + + // Retrieves the xlsx format. + if (ACCEPT_TYPE.APPLICATION_XLSX === acceptType) { + const buffer = await this.transactionsByVendorsApp.xlsx( tenantId, filter ); - const accept = this.accepts(req); - const acceptType = accept.types(['json', 'application/json+table']); - - switch (acceptType) { - case 'application/json+table': - return res - .status(200) - .send(this.transformToTableRows(tenantId, report.data)); - case 'json': - default: - return res.status(200).send(this.transformToJsonResponse(report)); + res.setHeader('Content-Type', 'application/vnd.openxmlformats'); + res.setHeader( + 'Content-Disposition', + 'attachment; filename=report.xlsx' + ); + return res.send(buffer); + // Retrieves the csv format. + } else if (ACCEPT_TYPE.APPLICATION_CSV === acceptType) { + const buffer = await this.transactionsByVendorsApp.csv( + tenantId, + filter + ); + res.setHeader('Content-Type', 'text/csv'); + res.setHeader('Content-Disposition', 'attachment; filename=report.csv'); + return res.send(buffer); + // Retrieves the json table format. + } else if (ACCEPT_TYPE.APPLICATION_JSON_TABLE === acceptType) { + const table = await this.transactionsByVendorsApp.table( + tenantId, + filter + ); + return res.status(200).send(table); + // Retrieves the json format. + } else { + const sheet = await this.transactionsByVendorsApp.sheet( + tenantId, + filter + ); + return res.status(200).send(sheet); } } catch (error) { next(error); diff --git a/packages/server/src/api/controllers/FinancialStatements/TrialBalanceSheet.ts b/packages/server/src/api/controllers/FinancialStatements/TrialBalanceSheet.ts index da59287e41..ce23c10719 100644 --- a/packages/server/src/api/controllers/FinancialStatements/TrialBalanceSheet.ts +++ b/packages/server/src/api/controllers/FinancialStatements/TrialBalanceSheet.ts @@ -3,15 +3,17 @@ import { Request, Response, Router, NextFunction } from 'express'; import { query, ValidationChain } from 'express-validator'; import { castArray } from 'lodash'; import asyncMiddleware from '@/api/middleware/asyncMiddleware'; -import TrialBalanceSheetService from '@/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetService'; +import TrialBalanceSheetService from '@/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetInjectable'; import BaseFinancialReportController from './BaseFinancialReportController'; import { AbilitySubject, ReportsAction } from '@/interfaces'; import CheckPolicies from '@/api/middleware/CheckPolicies'; +import { TrialBalanceSheetApplication } from '@/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetApplication'; +import { ACCEPT_TYPE } from '@/interfaces/Http'; @Service() export default class TrialBalanceSheetController extends BaseFinancialReportController { @Inject() - trialBalanceSheetService: TrialBalanceSheetService; + private trialBalanceSheetApp: TrialBalanceSheetApplication; /** * Router constructor. @@ -73,21 +75,46 @@ export default class TrialBalanceSheetController extends BaseFinancialReportCont }; try { const accept = this.accepts(req); - const acceptType = accept.types(['json', 'application/json+table']); - if (acceptType === 'application/json+table') { - const { table, meta, query } = - await this.trialBalanceSheetService.trialBalanceSheetTable( - tenantId, - filter - ); + const acceptType = accept.types([ + ACCEPT_TYPE.APPLICATION_JSON, + ACCEPT_TYPE.APPLICATION_JSON_TABLE, + ACCEPT_TYPE.APPLICATION_CSV, + ACCEPT_TYPE.APPLICATION_XLSX, + ]); + // Retrieves in json table format. + if (acceptType === ACCEPT_TYPE.APPLICATION_JSON_TABLE) { + const { table, meta, query } = await this.trialBalanceSheetApp.table( + tenantId, + filter + ); return res.status(200).send({ table, meta, query }); + // Retrieves in xlsx format + } else if (acceptType === ACCEPT_TYPE.APPLICATION_XLSX) { + const buffer = await this.trialBalanceSheetApp.xlsx(tenantId, filter); + res.setHeader( + 'Content-Disposition', + 'attachment; filename=output.xlsx' + ); + res.setHeader( + 'Content-Type', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + ); + return res.send(buffer); + // Retrieves in csv format. + } else if (acceptType === ACCEPT_TYPE.APPLICATION_CSV) { + const buffer = await this.trialBalanceSheetApp.csv(tenantId, filter); + + res.setHeader('Content-Disposition', 'attachment; filename=output.csv'); + res.setHeader('Content-Type', 'text/csv'); + + return res.send(buffer); + // Retrieves in json format. } else { - const { data, query, meta } = - await this.trialBalanceSheetService.trialBalanceSheet( - tenantId, - filter - ); + const { data, query, meta } = await this.trialBalanceSheetApp.sheet( + tenantId, + filter + ); return res.status(200).send({ data, query, meta }); } } catch (error) { diff --git a/packages/server/src/api/controllers/FinancialStatements/VendorBalanceSummary/index.ts b/packages/server/src/api/controllers/FinancialStatements/VendorBalanceSummary/index.ts index e93891938c..ade69cb629 100644 --- a/packages/server/src/api/controllers/FinancialStatements/VendorBalanceSummary/index.ts +++ b/packages/server/src/api/controllers/FinancialStatements/VendorBalanceSummary/index.ts @@ -3,27 +3,19 @@ import { query } from 'express-validator'; import { Inject } from 'typedi'; import asyncMiddleware from '@/api/middleware/asyncMiddleware'; import BaseFinancialReportController from '../BaseFinancialReportController'; -import VendorBalanceSummaryTableRows from '@/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryTableRows'; -import VendorBalanceSummaryService from '@/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryService'; -import { - AbilitySubject, - IVendorBalanceSummaryStatement, - ReportsAction, -} from '@/interfaces'; +import { AbilitySubject, ReportsAction } from '@/interfaces'; import CheckPolicies from '@/api/middleware/CheckPolicies'; -import HasTenancyService from '@/services/Tenancy/TenancyService'; +import { ACCEPT_TYPE } from '@/interfaces/Http'; +import { VendorBalanceSummaryApplication } from '@/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryApplication'; export default class VendorBalanceSummaryReportController extends BaseFinancialReportController { @Inject() - vendorBalanceSummaryService: VendorBalanceSummaryService; - - @Inject() - tenancy: HasTenancyService; + private vendorBalanceSummaryApp: VendorBalanceSummaryApplication; /** * Router constructor. */ - router() { + public router() { const router = Router(); router.get( @@ -41,7 +33,7 @@ export default class VendorBalanceSummaryReportController extends BaseFinancialR /** * Validation schema. */ - get validationSchema() { + private get validationSchema() { return [ ...this.sheetNumberFormatValidationSchema, query('as_date').optional().isISO8601(), @@ -59,73 +51,62 @@ export default class VendorBalanceSummaryReportController extends BaseFinancialR ]; } - /** - * Transformes the report statement to table rows. - * @param {IVendorBalanceSummaryStatement} statement - - */ - private transformToTableRows( - tenantId: number, - { data, query }: IVendorBalanceSummaryStatement - ) { - const i18n = this.tenancy.i18n(tenantId); - const tableData = new VendorBalanceSummaryTableRows( - data, - query, - i18n - ); - return { - table: { - columns: tableData.tableColumns(), - data: tableData.tableRows(), - }, - query, - }; - } - - /** - * Transformes the report statement to raw json. - * @param {IVendorBalanceSummaryStatement} statement - - */ - private transformToJsonResponse({ - data, - columns, - }: IVendorBalanceSummaryStatement) { - return { - data: this.transfromToResponse(data), - columns: this.transfromToResponse(columns), - query: this.transfromToResponse(query), - }; - } - /** * Retrieve vendors balance summary. * @param {Request} req - * @param {Response} res - * @param {NextFunction} next - */ - async vendorBalanceSummary(req: Request, res: Response, next: NextFunction) { - const { tenantId, settings } = req; + public async vendorBalanceSummary( + req: Request, + res: Response, + next: NextFunction + ) { + const { tenantId } = req; const filter = this.matchedQueryData(req); try { - const vendorBalanceSummary = - await this.vendorBalanceSummaryService.vendorBalanceSummary( + const accept = this.accepts(req); + const acceptType = accept.types([ + ACCEPT_TYPE.APPLICATION_JSON, + ACCEPT_TYPE.APPLICATION_JSON_TABLE, + ACCEPT_TYPE.APPLICATION_CSV, + ACCEPT_TYPE.APPLICATION_XLSX, + ]); + + // Retrieves the csv format. + if (acceptType === ACCEPT_TYPE.APPLICATION_CSV) { + const buffer = await this.vendorBalanceSummaryApp.csv(tenantId, filter); + + res.setHeader('Content-Disposition', 'attachment; filename=output.csv'); + res.setHeader('Content-Type', 'text/csv'); + + return res.send(buffer); + } else if (acceptType === ACCEPT_TYPE.APPLICATION_XLSX) { + const buffer = await this.vendorBalanceSummaryApp.xlsx( tenantId, filter ); - const accept = this.accepts(req); - const acceptType = accept.types(['json', 'application/json+table']); - - switch (acceptType) { - case 'application/json+table': - return res - .status(200) - .send(this.transformToTableRows(tenantId, vendorBalanceSummary)); - case 'json': - default: - return res - .status(200) - .send(this.transformToJsonResponse(vendorBalanceSummary)); + res.setHeader( + 'Content-Disposition', + 'attachment; filename=output.xlsx' + ); + res.setHeader('Content-Type', 'application/vnd.openxmlformats'); + return res.send(buffer); + // Retrieves the json table format. + } else if (acceptType === ACCEPT_TYPE.APPLICATION_JSON_TABLE) { + const table = await this.vendorBalanceSummaryApp.table( + tenantId, + filter + ); + return res.status(200).send(table); + // Retrieves the json format. + } else { + const sheet = await this.vendorBalanceSummaryApp.sheet( + tenantId, + filter + ); + return res.status(200).send(sheet); } } catch (error) { next(error); diff --git a/packages/server/src/interfaces/APAgingSummaryReport.ts b/packages/server/src/interfaces/APAgingSummaryReport.ts index db6626167b..6bf7c83bb7 100644 --- a/packages/server/src/interfaces/APAgingSummaryReport.ts +++ b/packages/server/src/interfaces/APAgingSummaryReport.ts @@ -8,6 +8,7 @@ import { IAgingSummaryData, } from './AgingReport'; import { INumberFormatQuery } from './FinancialStatements'; +import { IFinancialTable } from './Table'; export interface IAPAgingSummaryQuery extends IAgingSummaryQuery { vendorsIds: number[]; @@ -34,3 +35,8 @@ export interface IAPAgingSummaryMeta { baseCurrency: string; organizationName: string; } + +export interface IAPAgingSummaryTable extends IFinancialTable { + query: IAPAgingSummaryQuery; + meta: IAPAgingSummaryMeta; +} diff --git a/packages/server/src/interfaces/ARAgingSummaryReport.ts b/packages/server/src/interfaces/ARAgingSummaryReport.ts index 7d25e2b2c8..d42fc8f7fc 100644 --- a/packages/server/src/interfaces/ARAgingSummaryReport.ts +++ b/packages/server/src/interfaces/ARAgingSummaryReport.ts @@ -5,6 +5,7 @@ import { IAgingSummaryContact, IAgingSummaryData, } from './AgingReport'; +import { IFinancialTable } from './Table'; export interface IARAgingSummaryQuery extends IAgingSummaryQuery { customersIds: number[]; @@ -26,3 +27,8 @@ export interface IARAgingSummaryMeta { organizationName: string; baseCurrency: string; } + +export interface IARAgingSummaryTable extends IFinancialTable { + meta: IARAgingSummaryMeta; + query: IARAgingSummaryQuery; +} diff --git a/packages/server/src/interfaces/BalanceSheet.ts b/packages/server/src/interfaces/BalanceSheet.ts index 4dad88e553..a74e48ee85 100644 --- a/packages/server/src/interfaces/BalanceSheet.ts +++ b/packages/server/src/interfaces/BalanceSheet.ts @@ -3,6 +3,7 @@ import { IFormatNumberSettings, IFinancialSheetBranchesQuery, } from './FinancialStatements'; +import { IFinancialTable } from './Table'; // Balance sheet schema nodes types. export enum BALANCE_SHEET_SCHEMA_NODE_TYPE { @@ -215,3 +216,8 @@ export enum IAccountTransactionsGroupBy { Month = 'month', Week = 'week', } + +export interface IBalanceSheetTable extends IFinancialTable { + meta: IBalanceSheetMeta; + query: IBalanceSheetQuery; +} diff --git a/packages/server/src/interfaces/CashFlow.ts b/packages/server/src/interfaces/CashFlow.ts index e9a2dc8cd8..1a4a1a6a10 100644 --- a/packages/server/src/interfaces/CashFlow.ts +++ b/packages/server/src/interfaces/CashFlow.ts @@ -1,7 +1,7 @@ import { INumberFormatQuery } from './FinancialStatements'; import { IAccount } from './Account'; import { ILedger } from './Ledger'; -import { ITableRow } from './Table'; +import { IFinancialTable, ITableRow } from './Table'; export interface ICashFlowStatementQuery { fromDate: Date | string; @@ -101,6 +101,11 @@ export interface ICashFlowStatementDOO { query: ICashFlowStatementQuery; } +export interface ICashFlowStatementTable extends IFinancialTable { + meta: ICashFlowStatementMeta; + query: ICashFlowStatementQuery; +} + export interface ICashFlowStatementService { cashFlow( tenantId: number, diff --git a/packages/server/src/interfaces/CustomerBalanceSummary.ts b/packages/server/src/interfaces/CustomerBalanceSummary.ts index cda13f7c9e..cf5b5900d2 100644 --- a/packages/server/src/interfaces/CustomerBalanceSummary.ts +++ b/packages/server/src/interfaces/CustomerBalanceSummary.ts @@ -1,11 +1,10 @@ -import { INumberFormatQuery } from './FinancialStatements'; - import { IContactBalanceSummaryQuery, IContactBalanceSummaryAmount, IContactBalanceSummaryPercentage, IContactBalanceSummaryTotal, } from './ContactBalanceSummary'; +import { IFinancialTable } from './Table'; export interface ICustomerBalanceSummaryQuery extends IContactBalanceSummaryQuery { @@ -19,7 +18,7 @@ export interface ICustomerBalanceSummaryPercentage extends IContactBalanceSummaryPercentage {} export interface ICustomerBalanceSummaryCustomer { - id: number, + id: number; customerName: string; total: ICustomerBalanceSummaryAmount; percentageOfColumn?: ICustomerBalanceSummaryPercentage; @@ -47,3 +46,7 @@ export interface ICustomerBalanceSummaryService { query: ICustomerBalanceSummaryQuery ): Promise; } + +export interface ICustomerBalanceSummaryTable extends IFinancialTable { + query: ICustomerBalanceSummaryQuery; +} diff --git a/packages/server/src/interfaces/Http.ts b/packages/server/src/interfaces/Http.ts new file mode 100644 index 0000000000..2189cb106c --- /dev/null +++ b/packages/server/src/interfaces/Http.ts @@ -0,0 +1,7 @@ +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', +}; diff --git a/packages/server/src/interfaces/InventoryDetails.ts b/packages/server/src/interfaces/InventoryDetails.ts index 733cb588a6..033ec269db 100644 --- a/packages/server/src/interfaces/InventoryDetails.ts +++ b/packages/server/src/interfaces/InventoryDetails.ts @@ -1,13 +1,12 @@ -import { - INumberFormatQuery, -} from './FinancialStatements'; +import { INumberFormatQuery } from './FinancialStatements'; +import { IFinancialTable } from './Table'; export interface IInventoryDetailsQuery { fromDate: Date | string; toDate: Date | string; numberFormat: INumberFormatQuery; noneTransactions: boolean; - itemsIds: number[] + itemsIds: number[]; warehousesIds?: number[]; branchesIds?: number[]; @@ -66,7 +65,7 @@ export interface IInventoryDetailsItemTransaction { cost: IInventoryDetailsNumber; value: IInventoryDetailsNumber; profitMargin: IInventoryDetailsNumber; - + rate: IInventoryDetailsNumber; runningQuantity: IInventoryDetailsNumber; @@ -80,7 +79,6 @@ export type IInventoryDetailsNode = | IInventoryDetailsItemTransaction; export type IInventoryDetailsData = IInventoryDetailsItem[]; - export interface IInventoryItemDetailMeta { isCostComputeRunning: boolean; organizationName: string; @@ -91,4 +89,9 @@ export interface IInvetoryItemDetailDOO { data: IInventoryDetailsData; query: IInventoryDetailsQuery; meta: IInventoryItemDetailMeta; -} \ No newline at end of file +} + +export interface IInvetoryItemDetailsTable extends IFinancialTable { + query: IInventoryDetailsQuery; + meta: IInventoryItemDetailMeta; +} diff --git a/packages/server/src/interfaces/ProfitLossSheet.ts b/packages/server/src/interfaces/ProfitLossSheet.ts index 4f2eec6565..944a0a9504 100644 --- a/packages/server/src/interfaces/ProfitLossSheet.ts +++ b/packages/server/src/interfaces/ProfitLossSheet.ts @@ -2,6 +2,7 @@ import { IFinancialSheetBranchesQuery, INumberFormatQuery, } from './FinancialStatements'; +import { IFinancialTable } from './Table'; export enum ProfitLossAggregateNodeId { INCOME = 'INCOME', @@ -177,3 +178,9 @@ export enum ProfitLossSheetRowType { ACCOUNT = 'ACCOUNT', TOTAL = 'TOTAL', } + + +export interface IProfitLossSheetTable extends IFinancialTable{ + meta: IProfitLossSheetMeta; + query: IProfitLossSheetQuery; +} \ No newline at end of file diff --git a/packages/server/src/interfaces/SalesTaxLiabilitySummary.ts b/packages/server/src/interfaces/SalesTaxLiabilitySummary.ts index 8b04c97190..2fbc9f13d5 100644 --- a/packages/server/src/interfaces/SalesTaxLiabilitySummary.ts +++ b/packages/server/src/interfaces/SalesTaxLiabilitySummary.ts @@ -1,3 +1,5 @@ +import { IFinancialTable } from "./Table"; + export interface SalesTaxLiabilitySummaryQuery { fromDate: Date; toDate: Date; @@ -49,3 +51,8 @@ export interface SalesTaxLiabilitySummaryMeta { organizationName: string; baseCurrency: string; } + +export interface ISalesTaxLiabilitySummaryTable extends IFinancialTable { + query: SalesTaxLiabilitySummaryQuery; + meta: SalesTaxLiabilitySummaryMeta; +} \ No newline at end of file diff --git a/packages/server/src/interfaces/Table.ts b/packages/server/src/interfaces/Table.ts index 28ff72f5c8..a567d2d92c 100644 --- a/packages/server/src/interfaces/Table.ts +++ b/packages/server/src/interfaces/Table.ts @@ -10,7 +10,7 @@ export interface ITableCell { } export type ITableRow = { - rows: ITableCell[]; + cells: ITableCell[]; }; export interface ITableColumn { @@ -28,4 +28,13 @@ export interface ITable { export interface ITableColumnAccessor { key: string; accessor: string; -} \ No newline at end of file +} + +export interface ITableData { + columns: ITableColumn[]; + rows: ITableRow[]; +} + +export interface IFinancialTable { + table: ITableData; +} diff --git a/packages/server/src/interfaces/TransactionsByCustomers.ts b/packages/server/src/interfaces/TransactionsByCustomers.ts index fe2fbf5e2a..fcfb01ea63 100644 --- a/packages/server/src/interfaces/TransactionsByCustomers.ts +++ b/packages/server/src/interfaces/TransactionsByCustomers.ts @@ -1,3 +1,4 @@ +import { IFinancialTable, ITableData } from './Table'; import { ITransactionsByContactsAmount, ITransactionsByContactsTransaction, @@ -26,6 +27,11 @@ export type ITransactionsByCustomersData = ITransactionsByCustomersCustomer[]; export interface ITransactionsByCustomersStatement { data: ITransactionsByCustomersData; + query: ITransactionsByCustomersFilter; +} + +export interface ITransactionsByCustomersTable extends IFinancialTable { + query: ITransactionsByCustomersFilter; } export interface ITransactionsByCustomersService { diff --git a/packages/server/src/interfaces/TransactionsByVendors.ts b/packages/server/src/interfaces/TransactionsByVendors.ts index 107c7662e7..ae129bc79b 100644 --- a/packages/server/src/interfaces/TransactionsByVendors.ts +++ b/packages/server/src/interfaces/TransactionsByVendors.ts @@ -1,3 +1,4 @@ +import { IFinancialTable } from './Table'; import { ITransactionsByContactsAmount, ITransactionsByContactsTransaction, @@ -34,3 +35,7 @@ export interface ITransactionsByVendorsService { filter: ITransactionsByVendorsFilter ): Promise; } + +export interface ITransactionsByVendorTable extends IFinancialTable { + query: ITransactionsByVendorsFilter; +} \ No newline at end of file diff --git a/packages/server/src/interfaces/TrialBalanceSheet.ts b/packages/server/src/interfaces/TrialBalanceSheet.ts index 56f13e7fa4..f423503aea 100644 --- a/packages/server/src/interfaces/TrialBalanceSheet.ts +++ b/packages/server/src/interfaces/TrialBalanceSheet.ts @@ -1,4 +1,5 @@ import { INumberFormatQuery } from './FinancialStatements'; +import { IFinancialTable } from './Table'; export interface ITrialBalanceSheetQuery { fromDate: Date | string; @@ -48,3 +49,8 @@ export interface ITrialBalanceStatement { query: ITrialBalanceSheetQuery; meta: ITrialBalanceSheetMeta; } + +export interface ITrialBalanceSheetTable extends IFinancialTable { + meta: ITrialBalanceSheetMeta; + query: ITrialBalanceSheetQuery; +} diff --git a/packages/server/src/interfaces/VendorBalanceSummary.ts b/packages/server/src/interfaces/VendorBalanceSummary.ts index af75b2d678..d214202df3 100644 --- a/packages/server/src/interfaces/VendorBalanceSummary.ts +++ b/packages/server/src/interfaces/VendorBalanceSummary.ts @@ -1,8 +1,9 @@ import { INumberFormatQuery } from './FinancialStatements'; +import { IFinancialTable } from './Table'; export interface IVendorBalanceSummaryQuery { asDate: Date; - vendorsIds: number[], + vendorsIds: number[]; numberFormat: INumberFormatQuery; percentageColumn: boolean; noneTransactions: boolean; @@ -45,6 +46,10 @@ export interface IVendorBalanceSummaryStatement { export interface IVendorBalanceSummaryService { vendorBalanceSummary( tenantId: number, - query: IVendorBalanceSummaryQuery, + query: IVendorBalanceSummaryQuery ): Promise; } + +export interface IVendorBalanceSummaryTable extends IFinancialTable { + query: IVendorBalanceSummaryQuery; +} diff --git a/packages/server/src/lib/Xlsx/TableSheet.tsx b/packages/server/src/lib/Xlsx/TableSheet.tsx new file mode 100644 index 0000000000..5bffd1bcfb --- /dev/null +++ b/packages/server/src/lib/Xlsx/TableSheet.tsx @@ -0,0 +1,134 @@ +import xlsx, { WorkBook } from 'xlsx'; +import { IFinancialTable, ITableData } from '@/interfaces'; +import { FinancialTableStructure } from '@/services/FinancialStatements/FinancialTableStructure'; + +interface ITableSheet { + convertToXLSX(): WorkBook; + convertToCSV(): string; + convertToBuffer(workbook: WorkBook, fileType: string): Buffer; +} + +export class TableSheet implements ITableSheet { + private table: ITableData; + + constructor(table: ITableData) { + this.table = table; + } + + /** + * Retrieves the columns labels. + * @returns {string[]} + */ + private get columns() { + return this.table.columns.map((col) => col.label); + } + + /** + * Retrieves the columns accessors. + * @returns {string[]} + */ + private get columnsAccessors() { + return this.table.columns.map((col, index) => { + return `${index}`; + }); + } + + /** + * Retrieves the rows data cellIndex/Value. + * @returns {Record} + */ + private get rows() { + const computedRows = FinancialTableStructure.flatNestedTree( + this.table.rows + ); + return computedRows.map((row) => { + const entries = row.cells.map((cell, index) => { + return [`${index}`, cell.value]; + }); + return Object.fromEntries(entries); + }); + } + + /** + * Converts the table to a CSV string. + * @returns {string} + */ + public convertToCSV(): string { + // Define custom headers + const headers = this.columns; + + // Convert data to worksheet with headers + const worksheet = xlsx.utils.json_to_sheet(this.rows, { + header: this.columnsAccessors, + }); + // Add custom headers to the worksheet + xlsx.utils.sheet_add_aoa(worksheet, [headers], { origin: 'A1' }); + + // Convert worksheet to CSV format + const csvOutput = xlsx.utils.sheet_to_csv(worksheet); + + return csvOutput; + } + + /** + * Convert the array of objects to an XLSX file with styled headers + * @returns {Workbook} + */ + public convertToXLSX(): WorkBook { + // Create a new workbook and a worksheet + const workbook = xlsx.utils.book_new(); + const worksheet = xlsx.utils.json_to_sheet(this.rows, { + header: this.columnsAccessors, + }); + // Add custom headers to the worksheet + xlsx.utils.sheet_add_aoa(worksheet, [this.columns], { + origin: 'A1', + }); + // Adjust column width. + worksheet['!cols'] = this.computeXlsxColumnsWidths(this.rows); + + // Append the worksheet to the workbook + xlsx.utils.book_append_sheet(workbook, worksheet, 'Sheet1'); + + return workbook; + } + + /** + * Converts the given workbook to buffer of the given file type + * @param {WorkBook} workbook + * @param {string} fileType + * @returns {Promise} + */ + public convertToBuffer(workbook: WorkBook, fileType: 'xlsx' | 'csv'): Buffer { + return xlsx.write(workbook, { + type: 'buffer', + bookType: fileType, + cellStyles: true, + }); + } + + /** + * Adjusts and computes the columns width. + * @param {} rows + * @returns {{wch: number}[]} + */ + private computeXlsxColumnsWidths = (rows): { wch: number }[] => { + const cols = [{ wch: 60 }]; + + this.columns.map((column) => { + cols.push({ wch: column.length }); + }); + rows.forEach((row) => { + const entries = Object.entries(row); + + entries.forEach(([key, value]) => { + if (cols[key]) { + cols[key].wch = Math.max(cols[key].wch, String(value).length); + } else { + cols[key] = { wch: String(value).length }; + } + }); + }); + return cols; + }; +} diff --git a/packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryApplication.ts b/packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryApplication.ts new file mode 100644 index 0000000000..73c08b2d84 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryApplication.ts @@ -0,0 +1,53 @@ +import { Inject, Service } from 'typedi'; +import { APAgingSummaryExportInjectable } from './APAgingSummaryExportInjectable'; +import { APAgingSummaryTableInjectable } from './APAgingSummaryTableInjectable'; +import { IAPAgingSummaryQuery } from '@/interfaces'; +import { APAgingSummaryService } from './APAgingSummaryService'; + +@Service() +export class APAgingSummaryApplication { + @Inject() + private APAgingSummaryTable: APAgingSummaryTableInjectable; + + @Inject() + private APAgingSummaryExport: APAgingSummaryExportInjectable; + + @Inject() + private APAgingSummarySheet: APAgingSummaryService; + + /** + * Retrieve the A/P aging summary in sheet format. + * @param {number} tenantId + * @param {IAPAgingSummaryQuery} query + */ + public sheet(tenantId: number, query: IAPAgingSummaryQuery) { + return this.APAgingSummarySheet.APAgingSummary(tenantId, query); + } + + /** + * Retrieve the A/P aging summary in table format. + * @param {number} tenantId + * @param {IAPAgingSummaryQuery} query + */ + public table(tenantId: number, query: IAPAgingSummaryQuery) { + return this.APAgingSummaryTable.table(tenantId, query); + } + + /** + * Retrieve the A/P aging summary in CSV format. + * @param {number} tenantId + * @param {IAPAgingSummaryQuery} query + */ + public csv(tenantId: number, query: IAPAgingSummaryQuery) { + return this.APAgingSummaryExport.csv(tenantId, query); + } + + /** + * Retrieve the A/P aging summary in XLSX format. + * @param {number} tenantId + * @param {IAPAgingSummaryQuery} query + */ + public xlsx(tenantId: number, query: IAPAgingSummaryQuery) { + return this.APAgingSummaryExport.xlsx(tenantId, query); + } +} diff --git a/packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryExportInjectable.ts b/packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryExportInjectable.ts new file mode 100644 index 0000000000..4561687e7b --- /dev/null +++ b/packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryExportInjectable.ts @@ -0,0 +1,43 @@ +import { Inject, Service } from 'typedi'; +import { APAgingSummaryTableInjectable } from './APAgingSummaryTableInjectable'; +import { TableSheet } from '@/lib/Xlsx/TableSheet'; +import { IAPAgingSummaryQuery } from '@/interfaces'; + +@Service() +export class APAgingSummaryExportInjectable { + @Inject() + private APAgingSummaryTable: APAgingSummaryTableInjectable; + + /** + * Retrieves the A/P aging summary sheet in XLSX format. + * @param {number} tenantId + * @param {IAPAgingSummaryQuery} query + * @returns {Promise} + */ + public async xlsx(tenantId: number, query: IAPAgingSummaryQuery) { + const table = await this.APAgingSummaryTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToXLSX(); + + return tableSheet.convertToBuffer(tableCsv, 'xlsx'); + } + + /** + * Retrieves the A/P aging summary sheet in CSV format. + * @param {number} tenantId + * @param {IAPAgingSummaryQuery} query + * @returns {Promise} + */ + public async csv( + tenantId: number, + query: IAPAgingSummaryQuery + ): Promise { + const table = await this.APAgingSummaryTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToCSV(); + + return tableCsv; + } +} diff --git a/packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryService.ts b/packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryService.ts index 73860c9a56..fa3e6a2b3c 100644 --- a/packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryService.ts +++ b/packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryService.ts @@ -1,14 +1,13 @@ import moment from 'moment'; import { Inject, Service } from 'typedi'; +import { isEmpty } from 'lodash'; import { IAPAgingSummaryQuery, IARAgingSummaryMeta } from '@/interfaces'; import TenancyService from '@/services/Tenancy/TenancyService'; import APAgingSummarySheet from './APAgingSummarySheet'; import { Tenant } from '@/system/models'; -import { isEmpty } from 'lodash'; -import APAgingSummaryTable from './APAgingSummaryTable'; @Service() -export default class PayableAgingSummaryService { +export class APAgingSummaryService { @Inject() tenancy: TenancyService; @@ -18,7 +17,7 @@ export default class PayableAgingSummaryService { /** * Default report query. */ - get defaultQuery(): IAPAgingSummaryQuery { + private get defaultQuery(): IAPAgingSummaryQuery { return { asDate: moment().format('YYYY-MM-DD'), agingDaysBefore: 30, @@ -119,21 +118,4 @@ export default class PayableAgingSummaryService { meta: this.reportMetadata(tenantId), }; } - - /** - * Retrieves A/P aging summary in table format. - * @param {number} tenantId - * @param {IAPAgingSummaryQuery} query - */ - async APAgingSummaryTable(tenantId: number, query: IAPAgingSummaryQuery) { - const report = await this.APAgingSummary(tenantId, query); - const table = new APAgingSummaryTable(report.data, query, {}); - - return { - columns: table.tableColumns(), - rows: table.tableRows(), - meta: report.meta, - query: report.query, - }; - } } diff --git a/packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryTableInjectable.ts b/packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryTableInjectable.ts new file mode 100644 index 0000000000..f9eda16132 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryTableInjectable.ts @@ -0,0 +1,36 @@ +import { Inject, Service } from 'typedi'; +import { IAPAgingSummaryQuery, IAPAgingSummaryTable } from '@/interfaces'; +import { APAgingSummaryService } from './APAgingSummaryService'; +import APAgingSummaryTable from './APAgingSummaryTable'; + +@Service() +export class APAgingSummaryTableInjectable { + @Inject() + private APAgingSummarySheet: APAgingSummaryService; + + /** + * Retrieves A/P aging summary in table format. + * @param {number} tenantId + * @param {IAPAgingSummaryQuery} query + * @returns {Promise} + */ + public async table( + tenantId: number, + query: IAPAgingSummaryQuery + ): Promise { + const report = await this.APAgingSummarySheet.APAgingSummary( + tenantId, + query + ); + const table = new APAgingSummaryTable(report.data, query, {}); + + return { + table: { + columns: table.tableColumns(), + rows: table.tableRows(), + }, + meta: report.meta, + query: report.query, + }; + } +} diff --git a/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryApplication.ts b/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryApplication.ts new file mode 100644 index 0000000000..d3282ca4bf --- /dev/null +++ b/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryApplication.ts @@ -0,0 +1,53 @@ +import { Inject, Service } from 'typedi'; +import { IARAgingSummaryQuery } from '@/interfaces'; +import { ARAgingSummaryTableInjectable } from './ARAgingSummaryTableInjectable'; +import { ARAgingSummaryExportInjectable } from './ARAgingSummaryExportInjectable'; +import ARAgingSummaryService from './ARAgingSummaryService'; + +@Service() +export class ARAgingSummaryApplication { + @Inject() + private ARAgingSummaryTable: ARAgingSummaryTableInjectable; + + @Inject() + private ARAgingSummaryExport: ARAgingSummaryExportInjectable; + + @Inject() + private ARAgingSummarySheet: ARAgingSummaryService; + + /** + * Retrieve the A/R aging summary sheet. + * @param {number} tenantId + * @param {IAPAgingSummaryQuery} query + */ + public sheet(tenantId: number, query: IARAgingSummaryQuery) { + return this.ARAgingSummarySheet.ARAgingSummary(tenantId, query); + } + + /** + * Retrieve the A/R aging summary in table format. + * @param {number} tenantId + * @param {IAPAgingSummaryQuery} query + */ + public table(tenantId: number, query: IARAgingSummaryQuery) { + return this.ARAgingSummaryTable.table(tenantId, query); + } + + /** + * Retrieve the A/R aging summary in XLSX format. + * @param {number} tenantId + * @param {IAPAgingSummaryQuery} query + */ + public xlsx(tenantId: number, query: IARAgingSummaryQuery) { + return this.ARAgingSummaryExport.xlsx(tenantId, query); + } + + /** + * Retrieve the A/R aging summary in CSV format. + * @param {number} tenantId + * @param {IAPAgingSummaryQuery} query + */ + public csv(tenantId: number, query: IARAgingSummaryQuery) { + return this.ARAgingSummaryExport.csv(tenantId, query); + } +} diff --git a/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryExportInjectable.ts b/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryExportInjectable.ts new file mode 100644 index 0000000000..25c3dd0643 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryExportInjectable.ts @@ -0,0 +1,46 @@ +import { Inject, Service } from 'typedi'; +import { TableSheet } from '@/lib/Xlsx/TableSheet'; +import { ARAgingSummaryTableInjectable } from './ARAgingSummaryTableInjectable'; +import { IARAgingSummaryQuery } from '@/interfaces'; + +@Service() +export class ARAgingSummaryExportInjectable { + @Inject() + private ARAgingSummaryTable: ARAgingSummaryTableInjectable; + + /** + * Retrieves the A/R aging summary sheet in XLSX format. + * @param {number} tenantId + * @param {IARAgingSummaryQuery} query + * @returns {Promise} + */ + public async xlsx( + tenantId: number, + query: IARAgingSummaryQuery + ): Promise { + const table = await this.ARAgingSummaryTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToXLSX(); + + return tableSheet.convertToBuffer(tableCsv, 'xlsx'); + } + + /** + * Retrieves the A/R aging summary sheet in CSV format. + * @param {number} tenantId + * @param {ICashFlowStatementQuery} query + * @returns {Promise} + */ + public async csv( + tenantId: number, + query: IARAgingSummaryQuery + ): Promise { + const table = await this.ARAgingSummaryTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToCSV(); + + return tableCsv; + } +} diff --git a/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryService.ts b/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryService.ts index 60bdb86754..e13dfc2763 100644 --- a/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryService.ts +++ b/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryService.ts @@ -5,7 +5,6 @@ import { IARAgingSummaryQuery, IARAgingSummaryMeta } from '@/interfaces'; import TenancyService from '@/services/Tenancy/TenancyService'; import ARAgingSummarySheet from './ARAgingSummarySheet'; import { Tenant } from '@/system/models'; -import ARAgingSummaryTable from './ARAgingSummaryTable'; @Service() export default class ARAgingSummaryService { @@ -118,21 +117,4 @@ export default class ARAgingSummaryService { meta: this.reportMetadata(tenantId), }; } - - /** - * Retrieves A/R aging summary in table format. - * @param {number} tenantId - * @param {IARAgingSummaryQuery} query - */ - async ARAgingSummaryTable(tenantId: number, query: IARAgingSummaryQuery) { - const report = await this.ARAgingSummary(tenantId, query); - const table = new ARAgingSummaryTable(report.data, query, {}); - - return { - columns: table.tableColumns(), - rows: table.tableRows(), - meta: report.meta, - query, - }; - } } diff --git a/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryTableInjectable.ts b/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryTableInjectable.ts new file mode 100644 index 0000000000..10ac9ee8c0 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryTableInjectable.ts @@ -0,0 +1,36 @@ +import { IARAgingSummaryQuery, IARAgingSummaryTable } from '@/interfaces'; +import { Inject, Service } from 'typedi'; +import ARAgingSummaryTable from './ARAgingSummaryTable'; +import ARAgingSummaryService from './ARAgingSummaryService'; + +@Service() +export class ARAgingSummaryTableInjectable { + @Inject() + private ARAgingSummarySheet: ARAgingSummaryService; + + /** + * Retrieves A/R aging summary in table format. + * @param {number} tenantId + * @param {IARAgingSummaryQuery} query + * @returns {Promise} + */ + public async table( + tenantId: number, + query: IARAgingSummaryQuery + ): Promise { + const report = await this.ARAgingSummarySheet.ARAgingSummary( + tenantId, + query + ); + const table = new ARAgingSummaryTable(report.data, query, {}); + + return { + table: { + columns: table.tableColumns(), + rows: table.tableRows(), + }, + meta: report.meta, + query, + }; + } +} diff --git a/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetApplication.ts b/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetApplication.ts new file mode 100644 index 0000000000..01ab77bfec --- /dev/null +++ b/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetApplication.ts @@ -0,0 +1,57 @@ +import { Inject, Service } from 'typedi'; +import { IBalanceSheetQuery } from '@/interfaces'; +import { BalanceSheetExportInjectable } from './BalanceSheetExportInjectable'; +import { BalanceSheetTableInjectable } from './BalanceSheetTableInjectable'; +import BalanceSheetStatementService from './BalanceSheetInjectable'; + +@Service() +export class BalanceSheetApplication { + @Inject() + public balanceSheetExport: BalanceSheetExportInjectable; + + @Inject() + public balanceSheetTable: BalanceSheetTableInjectable; + + @Inject() + public balanceSheet: BalanceSheetStatementService; + + /** + * Retrieves the balnace sheet in json format. + * @param {numnber} tenantId + * @param {IBalanceSheetQuery} query + * @returns {Promise} + */ + public sheet(tenantId: number, query: IBalanceSheetQuery) { + return this.balanceSheet.balanceSheet(tenantId, query); + } + + /** + * Retrieves the balance sheet in table format. + * @param {number} tenantId + * @param {IBalanceSheetQuery} query + * @returns {Promise} + */ + public table(tenantId: number, query: IBalanceSheetQuery) { + return this.balanceSheetTable.table(tenantId, query); + } + + /** + * Retrieves the balance sheet in XLSX format. + * @param {number} tenantId + * @param {IBalanceSheetQuery} query + * @returns {Promise} + */ + public xlsx(tenantId: number, query: IBalanceSheetQuery) { + return this.balanceSheetExport.xlsx(tenantId, query); + } + + /** + * Retrieves the balance sheet in CSV format. + * @param {number} tenantId + * @param {IBalanceSheetQuery} query + * @returns {Promise} + */ + public csv(tenantId: number, query: IBalanceSheetQuery): Promise { + return this.balanceSheetExport.csv(tenantId, query); + } +} diff --git a/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetExportInjectable.ts b/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetExportInjectable.ts new file mode 100644 index 0000000000..2c43d5f800 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetExportInjectable.ts @@ -0,0 +1,43 @@ +import { Inject, Service } from 'typedi'; +import { BalanceSheetTableInjectable } from './BalanceSheetTableInjectable'; +import { TableSheet } from '@/lib/Xlsx/TableSheet'; +import { IBalanceSheetQuery } from '@/interfaces'; + +@Service() +export class BalanceSheetExportInjectable { + @Inject() + private balanceSheetTable: BalanceSheetTableInjectable; + + /** + * Retrieves the trial balance sheet in XLSX format. + * @param {number} tenantId + * @param {ITrialBalanceSheetQuery} query + * @returns {Promise} + */ + public async xlsx(tenantId: number, query: IBalanceSheetQuery) { + const table = await this.balanceSheetTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToXLSX(); + + return tableSheet.convertToBuffer(tableCsv, 'xlsx'); + } + + /** + * Retrieves the trial balance sheet in CSV format. + * @param {number} tenantId + * @param {ITrialBalanceSheetQuery} query + * @returns {Promise} + */ + public async csv( + tenantId: number, + query: IBalanceSheetQuery + ): Promise { + const table = await this.balanceSheetTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToCSV(); + + return tableCsv; + } +} diff --git a/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetService.ts b/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetInjectable.ts similarity index 96% rename from packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetService.ts rename to packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetInjectable.ts index b0470c7457..02e136ca1d 100644 --- a/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetService.ts +++ b/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetInjectable.ts @@ -19,13 +19,10 @@ export default class BalanceSheetStatementService implements IBalanceSheetStatementService { @Inject() - tenancy: TenancyService; - - @Inject('logger') - logger: any; + private tenancy: TenancyService; @Inject() - inventoryService: InventoryService; + private inventoryService: InventoryService; /** * Defaults balance sheet filter query. @@ -94,10 +91,8 @@ export default class BalanceSheetStatementService /** * Retrieve balance sheet statement. - * ------------- * @param {number} tenantId * @param {IBalanceSheetQuery} query - * * @return {IBalanceSheetStatement} */ public async balanceSheet( diff --git a/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetTableInjectable.ts b/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetTableInjectable.ts new file mode 100644 index 0000000000..3eb7693502 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetTableInjectable.ts @@ -0,0 +1,42 @@ +import { Inject, Service } from 'typedi'; +import BalanceSheetStatementService from './BalanceSheetInjectable'; +import BalanceSheetTable from './BalanceSheetTable'; +import { IBalanceSheetQuery, IBalanceSheetTable } from '@/interfaces'; +import HasTenancyService from '@/services/Tenancy/TenancyService'; + +@Service() +export class BalanceSheetTableInjectable { + @Inject() + private tenancy: HasTenancyService; + + @Inject() + private balanceSheetService: BalanceSheetStatementService; + + /** + * Retrieves the balance sheet in table format. + * @param {number} tenantId + * @param {number} query + * @returns {Promise} + */ + public async table( + tenantId: number, + filter: IBalanceSheetQuery + ): Promise { + const i18n = this.tenancy.i18n(tenantId); + + const { data, query, meta } = await this.balanceSheetService.balanceSheet( + tenantId, + filter + ); + const table = new BalanceSheetTable(data, query, i18n); + + return { + table: { + columns: table.tableColumns(), + rows: table.tableRows(), + }, + query, + meta, + }; + } +} diff --git a/packages/server/src/services/FinancialStatements/CashFlow/CashflowExportInjectable.ts b/packages/server/src/services/FinancialStatements/CashFlow/CashflowExportInjectable.ts new file mode 100644 index 0000000000..8562cfbf56 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/CashFlow/CashflowExportInjectable.ts @@ -0,0 +1,46 @@ +import { Inject, Service } from 'typedi'; +import { ICashFlowStatementQuery } from '@/interfaces'; +import { TableSheet } from '@/lib/Xlsx/TableSheet'; +import { CashflowTableInjectable } from './CashflowTableInjectable'; + +@Service() +export class CashflowExportInjectable { + @Inject() + private cashflowSheetTable: CashflowTableInjectable; + + /** + * Retrieves the cashflow sheet in XLSX format. + * @param {number} tenantId + * @param {ICashFlowStatementQuery} query + * @returns {Promise} + */ + public async xlsx( + tenantId: number, + query: ICashFlowStatementQuery + ): Promise { + const table = await this.cashflowSheetTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToXLSX(); + + return tableSheet.convertToBuffer(tableCsv, 'xlsx'); + } + + /** + * Retrieves the cashflow sheet in CSV format. + * @param {number} tenantId + * @param {ICashFlowStatementQuery} query + * @returns {Promise} + */ + public async csv( + tenantId: number, + query: ICashFlowStatementQuery + ): Promise { + const table = await this.cashflowSheetTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToCSV(); + + return tableCsv; + } +} diff --git a/packages/server/src/services/FinancialStatements/CashFlow/CashflowSheetApplication.ts b/packages/server/src/services/FinancialStatements/CashFlow/CashflowSheetApplication.ts new file mode 100644 index 0000000000..0fd8b73577 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/CashFlow/CashflowSheetApplication.ts @@ -0,0 +1,58 @@ +import { Inject, Service } from 'typedi'; +import { CashflowExportInjectable } from './CashflowExportInjectable'; +import { ICashFlowStatementQuery } from '@/interfaces'; +import CashFlowStatementService from './CashFlowService'; +import { CashflowTableInjectable } from './CashflowTableInjectable'; + +@Service() +export class CashflowSheetApplication { + @Inject() + private cashflowExport: CashflowExportInjectable; + + @Inject() + private cashflowSheet: CashFlowStatementService; + + @Inject() + private cashflowTable: CashflowTableInjectable; + + /** + * Retrieves the cashflow sheet + * @param {number} tenantId + * @param {ICashFlowStatementQuery} query + */ + public async sheet(tenantId: number, query: ICashFlowStatementQuery) { + return this.cashflowSheet.cashFlow(tenantId, query); + } + + /** + * Retrieves the cashflow sheet in table format. + * @param {number} tenantId + * @param {ICashFlowStatementQuery} query + */ + public async table(tenantId: number, query: ICashFlowStatementQuery) { + return this.cashflowTable.table(tenantId, query); + } + + /** + * Retrieves the cashflow sheet in XLSX format. + * @param {number} tenantId + * @param {ICashFlowStatementQuery} query + * @returns {Promise} + */ + public async xlsx(tenantId: number, query: ICashFlowStatementQuery) { + return this.cashflowExport.xlsx(tenantId, query); + } + + /** + * Retrieves the cashflow sheet in CSV format. + * @param {number} tenantId + * @param {ICashFlowStatementQuery} query + * @returns {Promise} + */ + public async csv( + tenantId: number, + query: ICashFlowStatementQuery + ): Promise { + return this.cashflowExport.csv(tenantId, query); + } +} diff --git a/packages/server/src/services/FinancialStatements/CashFlow/CashflowTableInjectable.ts b/packages/server/src/services/FinancialStatements/CashFlow/CashflowTableInjectable.ts new file mode 100644 index 0000000000..0a54071f20 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/CashFlow/CashflowTableInjectable.ts @@ -0,0 +1,37 @@ +import { Inject, Service } from "typedi"; +import { ICashFlowStatementQuery, ICashFlowStatementTable } from "@/interfaces"; +import HasTenancyService from "@/services/Tenancy/TenancyService"; +import CashFlowTable from "./CashFlowTable"; +import CashFlowStatementService from "./CashFlowService"; + +@Service() +export class CashflowTableInjectable { + @Inject() + private tenancy: HasTenancyService; + + @Inject() + private cashflowSheet: CashFlowStatementService; + + /** + * Retrieves the cash flow table. + * @returns {Promise} + */ + public async table( + tenantId: number, + query: ICashFlowStatementQuery + ): Promise { + const i18n = this.tenancy.i18n(tenantId); + + const cashflowDOO = await this.cashflowSheet.cashFlow(tenantId, query); + const cashflowTable = new CashFlowTable(cashflowDOO, i18n); + + return { + table: { + columns: cashflowTable.tableColumns(), + rows: cashflowTable.tableRows(), + }, + query: cashflowDOO.query, + meta: cashflowDOO.meta, + }; + } +} diff --git a/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryApplication.ts b/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryApplication.ts new file mode 100644 index 0000000000..964cd91a90 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryApplication.ts @@ -0,0 +1,60 @@ +import { Inject, Service } from 'typedi'; +import { CustomerBalanceSummaryExportInjectable } from './CustomerBalanceSummaryExportInjectable'; +import { CustomerBalanceSummaryTableInjectable } from './CustomerBalanceSummaryTableInjectable'; +import { ICustomerBalanceSummaryQuery } from '@/interfaces'; +import { CustomerBalanceSummaryService } from './CustomerBalanceSummaryService'; + +@Service() +export class CustomerBalanceSummaryApplication { + @Inject() + private customerBalanceSummaryTable: CustomerBalanceSummaryTableInjectable; + + @Inject() + private customerBalanceSummaryExport: CustomerBalanceSummaryExportInjectable; + + @Inject() + private customerBalanceSummarySheet: CustomerBalanceSummaryService; + + /** + * Retrieves the customer balance sheet in json format. + * @param {number} tenantId + * @param {ICustomerBalanceSummaryQuery} query + * @returns {Promise} + */ + public sheet(tenantId: number, query: ICustomerBalanceSummaryQuery) { + return this.customerBalanceSummarySheet.customerBalanceSummary( + tenantId, + query + ); + } + + /** + * Retrieves the customer balance sheet in json format. + * @param {number} tenantId + * @param {ICustomerBalanceSummaryQuery} query + * @returns {Promise} + */ + public table(tenantId: number, query: ICustomerBalanceSummaryQuery) { + return this.customerBalanceSummaryTable.table(tenantId, query); + } + + /** + * Retrieves the customer balance sheet in XLSX format. + * @param {number} tenantId + * @param {ICustomerBalanceSummaryQuery} query + * @returns {Promise} + */ + public xlsx(tenantId: number, query: ICustomerBalanceSummaryQuery) { + return this.customerBalanceSummaryExport.xlsx(tenantId, query); + } + + /** + * Retrieves the customer balance sheet in CSV format. + * @param {number} tenantId + * @param {ICustomerBalanceSummaryQuery} query + * @returns {Promise} + */ + public csv(tenantId: number, query: ICustomerBalanceSummaryQuery) { + return this.customerBalanceSummaryExport.csv(tenantId, query); + } +} diff --git a/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryExportInjectable.ts b/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryExportInjectable.ts new file mode 100644 index 0000000000..97fec14d88 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryExportInjectable.ts @@ -0,0 +1,43 @@ +import { Inject, Service } from 'typedi'; +import { ICustomerBalanceSummaryQuery } from '@/interfaces'; +import { CustomerBalanceSummaryTableInjectable } from './CustomerBalanceSummaryTableInjectable'; +import { TableSheet } from '@/lib/Xlsx/TableSheet'; + +@Service() +export class CustomerBalanceSummaryExportInjectable { + @Inject() + private customerBalanceSummaryTable: CustomerBalanceSummaryTableInjectable; + + /** + * Retrieves the cashflow sheet in XLSX format. + * @param {number} tenantId + * @param {ICustomerBalanceSummaryQuery} query + * @returns {Promise} + */ + public async xlsx(tenantId: number, query: ICustomerBalanceSummaryQuery) { + const table = await this.customerBalanceSummaryTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToXLSX(); + + return tableSheet.convertToBuffer(tableCsv, 'xlsx'); + } + + /** + * Retrieves the cashflow sheet in CSV format. + * @param {number} tenantId + * @param {ICustomerBalanceSummaryQuery} query + * @returns {Promise} + */ + public async csv( + tenantId: number, + query: ICustomerBalanceSummaryQuery + ): Promise { + const table = await this.customerBalanceSummaryTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToCSV(); + + return tableCsv; + } +} diff --git a/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryService.ts b/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryService.ts index 01ec0e0507..78afc3bb2e 100644 --- a/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryService.ts +++ b/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryService.ts @@ -1,7 +1,5 @@ import { Inject } from 'typedi'; import moment from 'moment'; -import { isEmpty, map } from 'lodash'; -import TenancyService from '@/services/Tenancy/TenancyService'; import * as R from 'ramda'; import { ICustomerBalanceSummaryService, @@ -11,28 +9,21 @@ import { ILedgerEntry, } from '@/interfaces'; import { CustomerBalanceSummaryReport } from './CustomerBalanceSummary'; - import Ledger from '@/services/Accounting/Ledger'; import CustomerBalanceSummaryRepository from './CustomerBalanceSummaryRepository'; import { Tenant } from '@/system/models'; -export default class CustomerBalanceSummaryService +export class CustomerBalanceSummaryService implements ICustomerBalanceSummaryService { @Inject() - tenancy: TenancyService; - - @Inject('logger') - logger: any; - - @Inject() - reportRepository: CustomerBalanceSummaryRepository; + private reportRepository: CustomerBalanceSummaryRepository; /** * Defaults balance sheet filter query. * @return {ICustomerBalanceSummaryQuery} */ - get defaultQuery(): ICustomerBalanceSummaryQuery { + private get defaultQuery(): ICustomerBalanceSummaryQuery { return { asDate: moment().format('YYYY-MM-DD'), numberFormat: { @@ -43,13 +34,12 @@ export default class CustomerBalanceSummaryService negativeFormat: 'mines', }, percentageColumn: false, - + noneZero: false, noneTransactions: true, }; } - /** * Retrieve the customers ledger entries mapped from accounts transactions. * @param {number} tenantId @@ -75,7 +65,7 @@ export default class CustomerBalanceSummaryService * @param {ICustomerBalanceSummaryQuery} query * @return {Promise} */ - async customerBalanceSummary( + public async customerBalanceSummary( tenantId: number, query: ICustomerBalanceSummaryQuery ): Promise { @@ -86,13 +76,6 @@ export default class CustomerBalanceSummaryService // Merges the default query and request query. const filter = { ...this.defaultQuery, ...query }; - this.logger.info( - '[customer_balance_summary] trying to calculate the report.', - { - filter, - tenantId, - } - ); // Retrieve the customers list ordered by the display name. const customers = await this.reportRepository.getCustomers( tenantId, @@ -111,7 +94,7 @@ export default class CustomerBalanceSummaryService ledger, customers, filter, - tenant.metadata.baseCurrency, + tenant.metadata.baseCurrency ); return { diff --git a/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryTableInjectable.ts b/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryTableInjectable.ts new file mode 100644 index 0000000000..56450d4cae --- /dev/null +++ b/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryTableInjectable.ts @@ -0,0 +1,44 @@ +import { Inject, Service } from 'typedi'; +import { CustomerBalanceSummaryService } from './CustomerBalanceSummaryService'; +import HasTenancyService from '@/services/Tenancy/TenancyService'; +import { + ICustomerBalanceSummaryQuery, + ICustomerBalanceSummaryTable, +} from '@/interfaces'; +import { CustomerBalanceSummaryTable } from './CustomerBalanceSummaryTableRows'; + +@Service() +export class CustomerBalanceSummaryTableInjectable { + @Inject() + private customerBalanceSummaryService: CustomerBalanceSummaryService; + + @Inject() + private tenancy: HasTenancyService; + + /** + * Retrieves the customer balance sheet in table format. + * @param {number} tenantId + * @param {ICustomerBalanceSummaryQuery} filter + * @returns {Promise} + */ + public async table( + tenantId: number, + filter: ICustomerBalanceSummaryQuery + ): Promise { + const i18n = this.tenancy.i18n(tenantId); + const { data, query } = + await this.customerBalanceSummaryService.customerBalanceSummary( + tenantId, + filter + ); + const tableRows = new CustomerBalanceSummaryTable(data, filter, i18n); + + return { + table: { + columns: tableRows.tableColumns(), + rows: tableRows.tableRows(), + }, + query, + }; + } +} diff --git a/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryTableRows.ts b/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryTableRows.ts index b55a126137..e6cdc64151 100644 --- a/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryTableRows.ts +++ b/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryTableRows.ts @@ -15,7 +15,7 @@ enum TABLE_ROWS_TYPES { TOTAL = 'TOTAL', } -export default class CustomerBalanceSummaryTable { +export class CustomerBalanceSummaryTable { report: ICustomerBalanceSummaryData; query: ICustomerBalanceSummaryQuery; i18n: any; diff --git a/packages/server/src/services/FinancialStatements/FinancialTableStructure.ts b/packages/server/src/services/FinancialStatements/FinancialTableStructure.ts new file mode 100644 index 0000000000..6b3bb38b77 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/FinancialTableStructure.ts @@ -0,0 +1,48 @@ +import { ITableRow } from '@/interfaces'; +import { flatNestedTree } from '@/utils/deepdash'; +import { repeat } from 'lodash'; + +interface FlatNestTreeOpts { + nestedPrefix?: string; + nestedPrefixIndex?: number; +} + +export class FinancialTableStructure { + /** + * Converts the given table object with nested rows in flat rows. + * @param {ITableRow[]} + * @param {FlatNestTreeOpts} + * @returns {ITableRow[]} + */ + public static flatNestedTree = ( + obj: ITableRow[], + options?: FlatNestTreeOpts + ): ITableRow[] => { + const parsedOptions = { + nestedPrefix: ' ', + nestedPrefixIndex: 0, + ...options, + }; + const { nestedPrefixIndex, nestedPrefix } = parsedOptions; + + return flatNestedTree( + obj, + (item, key, context) => { + const cells = item.cells.map((cell, index) => { + return { + ...cell, + value: + (context.depth > 1 && nestedPrefixIndex === index + ? repeat(nestedPrefix, context.depth) + : '') + cell.value, + }; + }); + return { + ...item, + cells, + }; + }, + parsedOptions + ); + }; +} diff --git a/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetails.ts b/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetails.ts index d09cf19cd3..489acff3e5 100644 --- a/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetails.ts +++ b/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetails.ts @@ -29,7 +29,7 @@ enum INodeTypes { CLOSING_ENTRY = 'CLOSING_ENTRY', } -export default class InventoryDetails extends FinancialSheet { +export class InventoryDetails extends FinancialSheet { readonly inventoryTransactionsByItemId: Map; readonly openingBalanceTransactions: Map; readonly query: IInventoryDetailsQuery; diff --git a/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsApplication.ts b/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsApplication.ts new file mode 100644 index 0000000000..a2639094ef --- /dev/null +++ b/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsApplication.ts @@ -0,0 +1,66 @@ +import { + IInventoryDetailsQuery, + IInvetoryItemDetailsTable, +} from '@/interfaces'; +import { Inject, Service } from 'typedi'; +import { InventoryDetailsExportInjectable } from './InventoryDetailsExportInjectable'; +import { InventoryDetailsTableInjectable } from './InventoryDetailsTableInjectable'; +import { InventoryDetailsService } from './InventoryDetailsService'; + +@Service() +export class InventortyDetailsApplication { + @Inject() + private inventoryDetailsExport: InventoryDetailsExportInjectable; + + @Inject() + private inventoryDetailsTable: InventoryDetailsTableInjectable; + + @Inject() + private inventoryDetails: InventoryDetailsService; + + /** + * Retrieves the inventory details report in sheet format. + * @param {number} tenantId + * @param {IInventoryDetailsQuery} query + * @returns {Promise} + */ + public sheet(tenantId: number, query: IInventoryDetailsQuery) { + return this.inventoryDetails.inventoryDetails(tenantId, query); + } + + /** + * Retrieve the inventory details report in table format. + * @param {number} tenantId + * @param {IInventoryDetailsQuery} query + * @returns + */ + public table( + tenantId: number, + query: IInventoryDetailsQuery + ): Promise { + return this.inventoryDetailsTable.table(tenantId, query); + } + + /** + * Retrieves the inventory details report in XLSX format. + * @param {number} tenantId + * @param {IInventoryDetailsQuery} query + * @returns {Promise} + */ + public xlsx( + tenantId: number, + query: IInventoryDetailsQuery + ): Promise { + return this.inventoryDetailsExport.xlsx(tenantId, query); + } + + /** + * Retrieves the inventory details report in CSV format. + * @param {number} tenantId + * @param {IInventoryDetailsQuery} query + * @returns {Promise} + */ + public csv(tenantId: number, query: IInventoryDetailsQuery): Promise { + return this.inventoryDetailsExport.csv(tenantId, query); + } +} diff --git a/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsExportInjectable.ts b/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsExportInjectable.ts new file mode 100644 index 0000000000..bede24eb42 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsExportInjectable.ts @@ -0,0 +1,43 @@ +import { Inject, Service } from 'typedi'; +import { IInventoryDetailsQuery } from '@/interfaces'; +import { TableSheet } from '@/lib/Xlsx/TableSheet'; +import { InventoryDetailsTableInjectable } from './InventoryDetailsTableInjectable'; + +@Service() +export class InventoryDetailsExportInjectable { + @Inject() + private inventoryDetailsTable: InventoryDetailsTableInjectable; + + /** + * Retrieves the trial balance sheet in XLSX format. + * @param {number} tenantId + * @param {IInventoryDetailsQuery} query + * @returns {Promise} + */ + public async xlsx(tenantId: number, query: IInventoryDetailsQuery) { + const table = await this.inventoryDetailsTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToXLSX(); + + return tableSheet.convertToBuffer(tableCsv, 'xlsx'); + } + + /** + * Retrieves the trial balance sheet in CSV format. + * @param {number} tenantId + * @param {IInventoryDetailsQuery} query + * @returns {Promise} + */ + public async csv( + tenantId: number, + query: IInventoryDetailsQuery + ): Promise { + const table = await this.inventoryDetailsTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToCSV(); + + return tableCsv; + } +} diff --git a/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsService.ts b/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsService.ts index cdeca4f39d..d74137753c 100644 --- a/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsService.ts +++ b/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsService.ts @@ -6,7 +6,7 @@ import { IInventoryItemDetailMeta, } from '@/interfaces'; import TenancyService from '@/services/Tenancy/TenancyService'; -import InventoryDetails from './InventoryDetails'; +import { InventoryDetails } from './InventoryDetails'; import FinancialSheet from '../FinancialSheet'; import InventoryDetailsRepository from './InventoryDetailsRepository'; import InventoryService from '@/services/Inventory/Inventory'; @@ -14,7 +14,7 @@ import { parseBoolean } from 'utils'; import { Tenant } from '@/system/models'; @Service() -export default class InventoryDetailsService extends FinancialSheet { +export class InventoryDetailsService extends FinancialSheet { @Inject() private tenancy: TenancyService; diff --git a/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsTable.ts b/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsTable.ts index 98d5522f24..1fa6d602dc 100644 --- a/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsTable.ts +++ b/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsTable.ts @@ -20,13 +20,13 @@ enum IROW_TYPE { const MAP_CONFIG = { childrenPath: 'children', pathFormat: 'array' }; -export default class InventoryDetailsTable { +export class InventoryDetailsTable { i18n: any; report: any; /** * Constructor method. - * @param {ICashFlowStatement} reportStatement - Report statement. + * @param {ICashFlowStatement} report - Report statement. */ constructor(reportStatement, i18n) { this.report = reportStatement; @@ -172,7 +172,7 @@ export default class InventoryDetailsTable { * Retrieve the table rows of the inventory item details. * @returns {ITableRow[]} */ - public tableData = (): ITableRow[] => { + public tableRows = (): ITableRow[] => { return this.itemsMapper(this.report.data); }; diff --git a/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsTableInjectable.ts b/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsTableInjectable.ts new file mode 100644 index 0000000000..7cf803b464 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsTableInjectable.ts @@ -0,0 +1,45 @@ +import HasTenancyService from '@/services/Tenancy/TenancyService'; +import { Inject, Service } from 'typedi'; +import { InventoryDetailsTable } from './InventoryDetailsTable'; +import { + IInventoryDetailsQuery, + IInvetoryItemDetailsTable, +} from '@/interfaces'; +import { InventoryDetailsService } from './InventoryDetailsService'; + +@Service() +export class InventoryDetailsTableInjectable { + @Inject() + private tenancy: HasTenancyService; + + @Inject() + private inventoryDetails: InventoryDetailsService; + + /** + * Retrieves the inventory item details in table format. + * @param {number} tenantId + * @param {IInventoryDetailsQuery} query + * @returns {Promise} + */ + public async table( + tenantId: number, + query: IInventoryDetailsQuery + ): Promise { + const i18n = this.tenancy.i18n(tenantId); + + const inventoryDetails = await this.inventoryDetails.inventoryDetails( + tenantId, + query + ); + const table = new InventoryDetailsTable(inventoryDetails, i18n); + + return { + table: { + rows: table.tableRows(), + columns: table.tableColumns(), + }, + query: inventoryDetails.query, + meta: inventoryDetails.meta, + }; + } +} diff --git a/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetApplication.ts b/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetApplication.ts new file mode 100644 index 0000000000..eee89e73a0 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetApplication.ts @@ -0,0 +1,60 @@ +import { Inject, Service } from 'typedi'; +import { ProfitLossSheetExportInjectable } from './ProfitLossSheetExportInjectable'; +import { ProfitLossSheetTableInjectable } from './ProfitLossSheetTableInjectable'; +import { IProfitLossSheetQuery, IProfitLossSheetTable } from '@/interfaces'; +import ProfitLossSheetService from './ProfitLossSheetService'; + +@Service() +export class ProfitLossSheetApplication { + @Inject() + private profitLossTable: ProfitLossSheetTableInjectable; + + @Inject() + private profitLossExport: ProfitLossSheetExportInjectable; + + @Inject() + private profitLossSheet: ProfitLossSheetService; + + /** + * Retreives the profit/loss sheet. + * @param {number} tenantId + * @param {IProfitLossSheetQuery} query + * @returns {} + */ + public sheet(tenantId: number, query: IProfitLossSheetQuery) { + return this.profitLossSheet.profitLossSheet(tenantId, query); + } + + /** + * Retrieves the profit/loss sheet table format. + * @param {number} tenantId + * @param {IProfitLossSheetQuery} query + * @returns {Promise} + */ + public table( + tenantId: number, + query: IProfitLossSheetQuery + ): Promise { + return this.profitLossTable.table(tenantId, query); + } + + /** + * Retrieves the profit/loss sheet in csv format. + * @param {number} tenantId + * @param {IProfitLossSheetQuery} query + * @returns {Promise} + */ + public csv(tenantId: number, query: IProfitLossSheetQuery): Promise { + return this.profitLossExport.csv(tenantId, query); + } + + /** + * Retrieves the profit/loss sheet in xlsx format. + * @param {number} tenantId + * @param {IProfitLossSheetQuery} query + * @returns {Promise} + */ + public xlsx(tenantId: number, query: IProfitLossSheetQuery): Promise { + return this.profitLossExport.xlsx(tenantId, query); + } +} diff --git a/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetExportInjectable.ts b/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetExportInjectable.ts new file mode 100644 index 0000000000..ba23717972 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetExportInjectable.ts @@ -0,0 +1,43 @@ +import { Inject, Service } from 'typedi'; +import { IProfitLossSheetQuery } from '@/interfaces'; +import { TableSheet } from '@/lib/Xlsx/TableSheet'; +import { ProfitLossSheetTableInjectable } from './ProfitLossSheetTableInjectable'; + +@Service() +export class ProfitLossSheetExportInjectable { + @Inject() + private profitLossSheetTable: ProfitLossSheetTableInjectable; + + /** + * Retrieves the profit/loss sheet in XLSX format. + * @param {number} tenantId + * @param {IProfitLossSheetQuery} query + * @returns {Promise} + */ + public async xlsx(tenantId: number, query: IProfitLossSheetQuery) { + const table = await this.profitLossSheetTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToXLSX(); + + return tableSheet.convertToBuffer(tableCsv, 'xlsx'); + } + + /** + * Retrieves the profit/loss sheet in CSV format. + * @param {number} tenantId + * @param {IProfitLossSheetQuery} query + * @returns {Promise} + */ + public async csv( + tenantId: number, + query: IProfitLossSheetQuery + ): Promise { + const table = await this.profitLossSheetTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToCSV(); + + return tableCsv; + } +} diff --git a/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetService.ts b/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetService.ts index 14d17fc5aa..20cf9a170f 100644 --- a/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetService.ts +++ b/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetService.ts @@ -16,39 +16,10 @@ import { ProfitLossSheetRepository } from './ProfitLossSheetRepository'; @Service() export default class ProfitLossSheetService { @Inject() - tenancy: TenancyService; - - @Inject('logger') - logger: any; + private tenancy: TenancyService; @Inject() - inventoryService: InventoryService; - - /** - * Retrieve the trial balance sheet meta. - * @param {number} tenantId - Tenant id. - * @returns {ITrialBalanceSheetMeta} - */ - reportMetadata(tenantId: number): IProfitLossSheetMeta { - const settings = this.tenancy.settings(tenantId); - - const isCostComputeRunning = - this.inventoryService.isItemsCostComputeRunning(tenantId); - const organizationName = settings.get({ - group: 'organization', - key: 'name', - }); - const baseCurrency = settings.get({ - group: 'organization', - key: 'base_currency', - }); - - return { - isCostComputeRunning: parseBoolean(isCostComputeRunning, false), - organizationName, - baseCurrency, - }; - } + private inventoryService: InventoryService; /** * Retrieve profit/loss sheet statement. @@ -56,7 +27,7 @@ export default class ProfitLossSheetService { * @param {IProfitLossSheetQuery} query * @return { } */ - profitLossSheet = async ( + public profitLossSheet = async ( tenantId: number, query: IProfitLossSheetQuery ): Promise<{ @@ -70,13 +41,6 @@ export default class ProfitLossSheetService { // Merges the given query with default filter query. const filter = mergeQueryWithDefaults(query); - // Get the given accounts or throw not found service error. - // if (filter.accountsIds.length > 0) { - // await this.accountsService.getAccountsOrThrowError( - // tenantId, - // filter.accountsIds - // ); - // } const tenant = await Tenant.query() .findById(tenantId) .withGraphFetched('metadata'); @@ -101,4 +65,30 @@ export default class ProfitLossSheetService { meta: this.reportMetadata(tenantId), }; }; + + /** + * Retrieve the trial balance sheet meta. + * @param {number} tenantId - Tenant id. + * @returns {ITrialBalanceSheetMeta} + */ + private reportMetadata(tenantId: number): IProfitLossSheetMeta { + const settings = this.tenancy.settings(tenantId); + + const isCostComputeRunning = + this.inventoryService.isItemsCostComputeRunning(tenantId); + const organizationName = settings.get({ + group: 'organization', + key: 'name', + }); + const baseCurrency = settings.get({ + group: 'organization', + key: 'base_currency', + }); + + return { + isCostComputeRunning: parseBoolean(isCostComputeRunning, false), + organizationName, + baseCurrency, + }; + } } diff --git a/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetTableInjectable.ts b/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetTableInjectable.ts new file mode 100644 index 0000000000..326e7aaefe --- /dev/null +++ b/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetTableInjectable.ts @@ -0,0 +1,42 @@ +import { Inject, Service } from 'typedi'; +import ProfitLossSheetService from './ProfitLossSheetService'; +import { ProfitLossSheetTable } from './ProfitLossSheetTable'; +import { IProfitLossSheetQuery, IProfitLossSheetTable } from '@/interfaces'; +import HasTenancyService from '@/services/Tenancy/TenancyService'; + +@Service() +export class ProfitLossSheetTableInjectable { + @Inject() + private profitLossSheet: ProfitLossSheetService; + + @Inject() + private tenancy: HasTenancyService; + + /** + * Retrieves the profit/loss sheet in table format. + * @param {number} tenantId + * @param {IProfitLossSheetQuery} filter + * @returns {Promise} + */ + public async table( + tenantId: number, + filter: IProfitLossSheetQuery + ): Promise { + const i18n = this.tenancy.i18n(tenantId); + + const { data, query, meta } = await this.profitLossSheet.profitLossSheet( + tenantId, + filter + ); + const table = new ProfitLossSheetTable(data, query, i18n); + + return { + table: { + rows: table.tableRows(), + columns: table.tableColumns(), + }, + query, + meta, + }; + } +} diff --git a/packages/server/src/services/FinancialStatements/SalesByItems/SalesByItemsService.ts b/packages/server/src/services/FinancialStatements/SalesByItems/SalesByItemsService.ts index 7570ef572f..6f81e1489d 100644 --- a/packages/server/src/services/FinancialStatements/SalesByItems/SalesByItemsService.ts +++ b/packages/server/src/services/FinancialStatements/SalesByItems/SalesByItemsService.ts @@ -87,10 +87,6 @@ export default class SalesByItemsReportService { ...this.defaultQuery, ...query, }; - this.logger.info('[sales_by_items] trying to calculate the report.', { - filter, - tenantId, - }); // Inventory items for sales report. const inventoryItems = await Item.query().onBuild((q) => { q.where('type', 'inventory'); diff --git a/packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryApplication.ts b/packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryApplication.ts new file mode 100644 index 0000000000..f0e5a5248e --- /dev/null +++ b/packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryApplication.ts @@ -0,0 +1,63 @@ +import { Inject, Service } from 'typedi'; +import { SalesTaxLiabilitySummaryQuery } from '@/interfaces/SalesTaxLiabilitySummary'; +import { SalesTaxLiabilitySummaryTableInjectable } from './SalesTaxLiabilitySummaryTableInjectable'; +import { SalesTaxLiabilitySummaryExportInjectable } from './SalesTaxLiabilitySummaryExportInjectable'; +import { SalesTaxLiabilitySummaryService } from './SalesTaxLiabilitySummaryService'; + +@Service() +export class SalesTaxLiabilitySummaryApplication { + @Inject() + private salesTaxLiabilitySheet: SalesTaxLiabilitySummaryService; + + @Inject() + private salesTaxLiabilityExport: SalesTaxLiabilitySummaryExportInjectable; + + @Inject() + private salesTaxLiabilityTable: SalesTaxLiabilitySummaryTableInjectable; + + /** + * Retrieves the sales tax liability summary in json format. + * @param {number} tenantId + * @param {SalesTaxLiabilitySummaryQuery} query + * @returns {Promise} + */ + public sheet(tenantId: number, query: SalesTaxLiabilitySummaryQuery) { + return this.salesTaxLiabilitySheet.salesTaxLiability(tenantId, query); + } + + /** + * Retrieves the sales tax liability summary in table format. + * @param {number} tenantId + * @param {SalesTaxLiabilitySummaryQuery} query + * @return {Promise} + */ + public table(tenantId: number, query: SalesTaxLiabilitySummaryQuery) { + return this.salesTaxLiabilityTable.table(tenantId, query); + } + + /** + * Retrieves the sales tax liability summary in XLSX format. + * @param {number} tenantId + * @param {SalesTaxLiabilitySummaryQuery} query + * @returns {Promise} + */ + public xlsx( + tenantId: number, + query: SalesTaxLiabilitySummaryQuery + ): Promise { + return this.salesTaxLiabilityExport.xlsx(tenantId, query); + } + + /** + * Retrieves the sales tax liability summary in CSV format. + * @param {number} tenantId + * @param {SalesTaxLiabilitySummaryQuery} query + * @returns {Promise} + */ + public csv( + tenantId: number, + query: SalesTaxLiabilitySummaryQuery + ): Promise { + return this.salesTaxLiabilityExport.csv(tenantId, query); + } +} diff --git a/packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryExportInjectable.ts b/packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryExportInjectable.ts new file mode 100644 index 0000000000..9327436795 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryExportInjectable.ts @@ -0,0 +1,46 @@ +import { SalesTaxLiabilitySummaryQuery } from '@/interfaces/SalesTaxLiabilitySummary'; +import { TableSheet } from '@/lib/Xlsx/TableSheet'; +import { Inject, Service } from 'typedi'; +import { SalesTaxLiabilitySummaryTableInjectable } from './SalesTaxLiabilitySummaryTableInjectable'; + +@Service() +export class SalesTaxLiabilitySummaryExportInjectable { + @Inject() + private salesTaxLiabilityTable: SalesTaxLiabilitySummaryTableInjectable; + + /** + * Retrieves the cashflow sheet in XLSX format. + * @param {number} tenantId + * @param {ICashFlowStatementQuery} query + * @returns {Promise} + */ + public async xlsx( + tenantId: number, + query: SalesTaxLiabilitySummaryQuery + ): Promise { + const table = await this.salesTaxLiabilityTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToXLSX(); + + return tableSheet.convertToBuffer(tableCsv, 'xlsx'); + } + + /** + * Retrieves the cashflow sheet in CSV format. + * @param {number} tenantId + * @param {ICashFlowStatementQuery} query + * @returns {Promise} + */ + public async csv( + tenantId: number, + query: SalesTaxLiabilitySummaryQuery + ): Promise { + const table = await this.salesTaxLiabilityTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToCSV(); + + return tableCsv; + } +} diff --git a/packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryService.ts b/packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryService.ts index 09fa9283b0..a1ec7a7714 100644 --- a/packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryService.ts +++ b/packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryService.ts @@ -5,7 +5,6 @@ import { SalesTaxLiabilitySummaryQuery, } from '@/interfaces/SalesTaxLiabilitySummary'; import { SalesTaxLiabilitySummary } from './SalesTaxLiabilitySummary'; -import { SalesTaxLiabilitySummaryTable } from './SalesTaxLiabilitySummaryTable'; import HasTenancyService from '@/services/Tenancy/TenancyService'; @Service() @@ -47,32 +46,6 @@ export class SalesTaxLiabilitySummaryService { }; } - /** - * Retrieve sales tax liability summary table. - * @param {number} tenantId - * @param {SalesTaxLiabilitySummaryQuery} query - * @returns - */ - public async salesTaxLiabilitySummaryTable( - tenantId: number, - query: SalesTaxLiabilitySummaryQuery - ) { - const report = await this.salesTaxLiability(tenantId, query); - - // Creates the sales tax liability summary table. - const table = new SalesTaxLiabilitySummaryTable(report.data, query); - - return { - table: { - rows: table.tableRows(), - columns: table.tableColumns(), - }, - data: report.data, - query: report.query, - meta: report.meta, - }; - } - /** * Retrieve the report meta. * @param {number} tenantId - diff --git a/packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryTableInjectable.ts b/packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryTableInjectable.ts new file mode 100644 index 0000000000..907cab2ad5 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryTableInjectable.ts @@ -0,0 +1,40 @@ +import { Inject, Service } from 'typedi'; +import { + ISalesTaxLiabilitySummaryTable, + SalesTaxLiabilitySummaryQuery, +} from '@/interfaces/SalesTaxLiabilitySummary'; +import { SalesTaxLiabilitySummaryTable } from './SalesTaxLiabilitySummaryTable'; +import { SalesTaxLiabilitySummaryService } from './SalesTaxLiabilitySummaryService'; + +@Service() +export class SalesTaxLiabilitySummaryTableInjectable { + @Inject() + private salesTaxLiability: SalesTaxLiabilitySummaryService; + + /** + * Retrieve sales tax liability summary table. + * @param {number} tenantId + * @param {SalesTaxLiabilitySummaryQuery} query + * @returns {Promise} + */ + public async table( + tenantId: number, + query: SalesTaxLiabilitySummaryQuery + ): Promise { + const report = await this.salesTaxLiability.salesTaxLiability( + tenantId, + query + ); + // Creates the sales tax liability summary table. + const table = new SalesTaxLiabilitySummaryTable(report.data, query); + + return { + table: { + rows: table.tableRows(), + columns: table.tableColumns(), + }, + query: report.query, + meta: report.meta, + }; + } +} diff --git a/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomers.ts b/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomers.ts index 3ab624830a..e35692bd52 100644 --- a/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomers.ts +++ b/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomers.ts @@ -139,11 +139,4 @@ export default class TransactionsByCustomers extends TransactionsByContact { public reportData(): ITransactionsByCustomersData { return this.customersMapper(this.customers); } - - /** - * Retrieve the report columns. - */ - public reportColumns() { - return []; - } } diff --git a/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersApplication.ts b/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersApplication.ts new file mode 100644 index 0000000000..b729c219ab --- /dev/null +++ b/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersApplication.ts @@ -0,0 +1,72 @@ +import { Inject, Service } from 'typedi'; +import { + ITransactionsByCustomersFilter, + ITransactionsByCustomersStatement, +} from '@/interfaces'; +import { TransactionsByCustomersTableInjectable } from './TransactionsByCustomersTableInjectable'; +import { TransactionsByCustomersExportInjectable } from './TransactionsByCustomersExportInjectable'; +import { TransactionsByCustomersSheet } from './TransactionsByCustomersService'; + +@Service() +export class TransactionsByCustomerApplication { + @Inject() + private transactionsByCustomersTable: TransactionsByCustomersTableInjectable; + + @Inject() + private transactionsByCustomersExport: TransactionsByCustomersExportInjectable; + + @Inject() + private transactionsByCustomersSheet: TransactionsByCustomersSheet; + + /** + * Retrieves the transactions by customers sheet in json format. + * @param {number} tenantId + * @param {ITransactionsByCustomersFilter} query + * @returns {Promise} + */ + public sheet( + tenantId: number, + query: ITransactionsByCustomersFilter + ): Promise { + return this.transactionsByCustomersSheet.transactionsByCustomers( + tenantId, + query + ); + } + + /** + * Retrieves the transactions by vendors sheet in table format. + * @param {number} tenantId + * @param {ITransactionsByCustomersFilter} query + * @returns {Promise} + */ + public table(tenantId: number, query: ITransactionsByCustomersFilter) { + return this.transactionsByCustomersTable.table(tenantId, query); + } + + /** + * Retrieves the transactions by vendors sheet in CSV format. + * @param {number} tenantId + * @param {ITransactionsByCustomersFilter} query + * @returns {Promise} + */ + public csv( + tenantId: number, + query: ITransactionsByCustomersFilter + ): Promise { + return this.transactionsByCustomersExport.csv(tenantId, query); + } + + /** + * Retrieves the transactions by vendors sheet in XLSX format. + * @param {number} tenantId + * @param {ITransactionsByCustomersFilter} query + * @returns {Promise} + */ + public xlsx( + tenantId: number, + query: ITransactionsByCustomersFilter + ): Promise { + return this.transactionsByCustomersExport.xlsx(tenantId, query); + } +} diff --git a/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersExportInjectable.ts b/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersExportInjectable.ts new file mode 100644 index 0000000000..d5dbffcff7 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersExportInjectable.ts @@ -0,0 +1,46 @@ +import { Inject, Service } from 'typedi'; +import { ITransactionsByCustomersFilter } from '@/interfaces'; +import { TableSheet } from '@/lib/Xlsx/TableSheet'; +import { TransactionsByCustomersTableInjectable } from './TransactionsByCustomersTableInjectable'; + +@Service() +export class TransactionsByCustomersExportInjectable { + @Inject() + private transactionsByCustomerTable: TransactionsByCustomersTableInjectable; + + /** + * Retrieves the cashflow sheet in XLSX format. + * @param {number} tenantId + * @param {ITransactionsByCustomersFilter} query + * @returns {Promise} + */ + public async xlsx( + tenantId: number, + query: ITransactionsByCustomersFilter + ): Promise { + const table = await this.transactionsByCustomerTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToXLSX(); + + return tableSheet.convertToBuffer(tableCsv, 'xlsx'); + } + + /** + * Retrieves the cashflow sheet in CSV format. + * @param {number} tenantId + * @param {ITransactionsByCustomersFilter} query + * @returns {Promise} + */ + public async csv( + tenantId: number, + query: ITransactionsByCustomersFilter + ): Promise { + const table = await this.transactionsByCustomerTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToCSV(); + + return tableCsv; + } +} diff --git a/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersRepository.ts b/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersRepository.ts index fd66d8f1e0..09579e2b21 100644 --- a/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersRepository.ts +++ b/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersRepository.ts @@ -1,16 +1,16 @@ +import { Inject } from 'typedi'; import { isEmpty, map } from 'lodash'; import { IAccount, IAccountTransaction } from '@/interfaces'; import { ACCOUNT_TYPE } from '@/data/AccountTypes'; import HasTenancyService from '@/services/Tenancy/TenancyService'; -import { Inject } from 'typedi'; export default class TransactionsByCustomersRepository { @Inject() - tenancy: HasTenancyService; + private tenancy: HasTenancyService; /** * Retrieve the report customers. - * @param {number} tenantId + * @param {number} tenantId * @returns {Promise} */ public async getCustomers(tenantId: number, customersIds?: number[]) { diff --git a/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersService.ts b/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersService.ts index a6f56d9fe4..3fbf8cf060 100644 --- a/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersService.ts +++ b/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersService.ts @@ -13,23 +13,20 @@ import Ledger from '@/services/Accounting/Ledger'; import TransactionsByCustomersRepository from './TransactionsByCustomersRepository'; import { Tenant } from '@/system/models'; -export default class TransactionsByCustomersService +export class TransactionsByCustomersSheet implements ITransactionsByCustomersService { @Inject() - tenancy: TenancyService; - - @Inject('logger') - logger: any; + private tenancy: TenancyService; @Inject() - reportRepository: TransactionsByCustomersRepository; + private reportRepository: TransactionsByCustomersRepository; /** * Defaults balance sheet filter query. * @return {ICustomerBalanceSummaryQuery} */ - get defaultQuery(): ITransactionsByCustomersFilter { + private get defaultQuery(): ITransactionsByCustomersFilter { return { fromDate: moment().startOf('month').format('YYYY-MM-DD'), toDate: moment().format('YYYY-MM-DD'), @@ -165,7 +162,6 @@ export default class TransactionsByCustomersService return { data: reportInstance.reportData(), - columns: reportInstance.reportColumns(), query: filter, }; } diff --git a/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersTableRows.ts b/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersTable.ts similarity index 81% rename from packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersTableRows.ts rename to packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersTable.ts index 5c4e1ceb3b..7016cf8533 100644 --- a/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersTableRows.ts +++ b/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersTable.ts @@ -1,6 +1,6 @@ import * as R from 'ramda'; -import { tableRowMapper, tableMapper } from 'utils'; -import { ITransactionsByCustomersCustomer, ITableRow } from '@/interfaces'; +import { tableRowMapper } from 'utils'; +import { ITransactionsByCustomersCustomer, ITableRow, ITableColumn } from '@/interfaces'; import TransactionsByContactsTableRows from '../TransactionsByContact/TransactionsByContactTableRows'; enum ROW_TYPE { @@ -10,17 +10,14 @@ enum ROW_TYPE { CUSTOMER = 'CUSTOMER', } -export default class TransactionsByCustomersTableRows extends TransactionsByContactsTableRows { +export class TransactionsByCustomersTable extends TransactionsByContactsTableRows { private customersTransactions: ITransactionsByCustomersCustomer[]; /** * Constructor method. * @param {ITransactionsByCustomersCustomer[]} customersTransactions - Customers transactions. */ - constructor( - customersTransactions: ITransactionsByCustomersCustomer[], - i18n - ) { + constructor(customersTransactions: ITransactionsByCustomersCustomer[], i18n) { super(); this.customersTransactions = customersTransactions; this.i18n = i18n; @@ -75,4 +72,12 @@ export default class TransactionsByCustomersTableRows extends TransactionsByCont this.customersTransactions ); }; + + /** + * Retrieve the table columns of transactions by customers report. + * @returns {ITableColumn[]} + */ + public tableColumns = (): ITableColumn[] => { + return []; + } } diff --git a/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersTableInjectable.ts b/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersTableInjectable.ts new file mode 100644 index 0000000000..fb1c61311c --- /dev/null +++ b/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersTableInjectable.ts @@ -0,0 +1,44 @@ +import { Inject, Service } from 'typedi'; +import { ITransactionsByCustomersFilter, ITransactionsByCustomersTable } from '@/interfaces'; +import { TransactionsByCustomersSheet } from './TransactionsByCustomersService'; +import HasTenancyService from '@/services/Tenancy/TenancyService'; +import { TransactionsByCustomersTable } from './TransactionsByCustomersTable'; + +@Service() +export class TransactionsByCustomersTableInjectable { + @Inject() + private transactionsByCustomerService: TransactionsByCustomersSheet; + + @Inject() + private tenancy: HasTenancyService; + + /** + * Retrieves the transactions by customers sheet in table format. + * @param {number} tenantId + * @param {ITransactionsByCustomersFilter} filter + * @returns {Promise} + */ + public async table( + tenantId: number, + filter: ITransactionsByCustomersFilter + ): Promise { + const i18n = this.tenancy.i18n(tenantId); + + const customersTransactions = + await this.transactionsByCustomerService.transactionsByCustomers( + tenantId, + filter + ); + const table = new TransactionsByCustomersTable( + customersTransactions.data, + i18n + ); + return { + table: { + rows: table.tableRows(), + columns: table.tableColumns(), + }, + query: customersTransactions.query, + }; + } +} diff --git a/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendor.ts b/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendor.ts index 5bc9276c08..500e548f7b 100644 --- a/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendor.ts +++ b/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendor.ts @@ -137,11 +137,4 @@ export default class TransactionsByVendors extends TransactionsByContact { public reportData(): ITransactionsByVendorsData { return this.vendorsMapper(this.contacts); } - - /** - * Retrieve the report columns. - */ - public reportColumns() { - return []; - } } diff --git a/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorApplication.ts b/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorApplication.ts new file mode 100644 index 0000000000..d8d424a30e --- /dev/null +++ b/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorApplication.ts @@ -0,0 +1,75 @@ +import { Inject, Service } from 'typedi'; +import { + ITransactionsByVendorTable, + ITransactionsByVendorsFilter, + ITransactionsByVendorsStatement, +} from '@/interfaces'; +import { TransactionsByVendorExportInjectable } from './TransactionsByVendorExportInjectable'; +import { TransactionsByVendorTableInjectable } from './TransactionsByVendorTableInjectable'; +import { TransactionsByVendorsInjectable } from './TransactionsByVendorInjectable'; + +@Service() +export class TransactionsByVendorApplication { + @Inject() + private transactionsByVendorTable: TransactionsByVendorTableInjectable; + + @Inject() + private transactionsByVendorExport: TransactionsByVendorExportInjectable; + + @Inject() + private transactionsByVendorSheet: TransactionsByVendorsInjectable; + + /** + * Retrieves the transactions by vendor in sheet format. + * @param {number} tenantId + * @param {ITransactionsByVendorsFilter} query + * @returns {Promise} + */ + public sheet( + tenantId: number, + query: ITransactionsByVendorsFilter + ): Promise { + return this.transactionsByVendorSheet.transactionsByVendors( + tenantId, + query + ); + } + + /** + * Retrieves the transactions by vendor in table format. + * @param {number} tenantId + * @param {ITransactionsByVendorsFilter} query + * @returns {Promise} + */ + public table( + tenantId: number, + query: ITransactionsByVendorsFilter + ): Promise { + return this.transactionsByVendorTable.table(tenantId, query); + } + + /** + * Retrieves the transactions by vendor in CSV format. + * @param {number} tenantId + * @param {ITransactionsByVendorsFilter} query + * @returns {Promise} + */ + public csv( + tenantId: number, + query: ITransactionsByVendorsFilter + ): Promise { + return this.transactionsByVendorExport.csv(tenantId, query); + } + + /** + * Retrieves the transactions by vendor in XLSX format. + * @param {number} tenantId + * @param {ITransactionsByVendorsFilter} query + */ + public xlsx( + tenantId: number, + query: ITransactionsByVendorsFilter + ): Promise { + return this.transactionsByVendorExport.xlsx(tenantId, query); + } +} diff --git a/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorExportInjectable.ts b/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorExportInjectable.ts new file mode 100644 index 0000000000..1d547e752a --- /dev/null +++ b/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorExportInjectable.ts @@ -0,0 +1,46 @@ +import { Inject, Service } from 'typedi'; +import { ITransactionsByVendorsFilter } from '@/interfaces'; +import { TableSheet } from '@/lib/Xlsx/TableSheet'; +import { TransactionsByVendorTableInjectable } from './TransactionsByVendorTableInjectable'; + +@Service() +export class TransactionsByVendorExportInjectable { + @Inject() + private transactionsByVendorTable: TransactionsByVendorTableInjectable; + + /** + * Retrieves the cashflow sheet in XLSX format. + * @param {number} tenantId + * @param {ITransactionsByVendorsFilter} query + * @returns {Promise} + */ + public async xlsx( + tenantId: number, + query: ITransactionsByVendorsFilter + ): Promise { + const table = await this.transactionsByVendorTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToXLSX(); + + return tableSheet.convertToBuffer(tableCsv, 'xlsx'); + } + + /** + * Retrieves the cashflow sheet in CSV format. + * @param {number} tenantId + * @param {ICashFlowStatementQuery} query + * @returns {Promise} + */ + public async csv( + tenantId: number, + query: ITransactionsByVendorsFilter + ): Promise { + const table = await this.transactionsByVendorTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToCSV(); + + return tableCsv; + } +} diff --git a/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorService.ts b/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorInjectable.ts similarity index 94% rename from packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorService.ts rename to packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorInjectable.ts index c112a059a6..a240419291 100644 --- a/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorService.ts +++ b/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorInjectable.ts @@ -1,7 +1,6 @@ import { Inject } from 'typedi'; import moment from 'moment'; import * as R from 'ramda'; -import { map } from 'lodash'; import TenancyService from '@/services/Tenancy/TenancyService'; import { ITransactionsByVendorsService, @@ -14,17 +13,14 @@ import Ledger from '@/services/Accounting/Ledger'; import TransactionsByVendorRepository from './TransactionsByVendorRepository'; import { Tenant } from '@/system/models'; -export default class TransactionsByVendorsService +export class TransactionsByVendorsInjectable implements ITransactionsByVendorsService { @Inject() - tenancy: TenancyService; - - @Inject('logger') - logger: any; + private tenancy: TenancyService; @Inject() - reportRepository: TransactionsByVendorRepository; + private reportRepository: TransactionsByVendorRepository; /** * Defaults balance sheet filter query. @@ -136,7 +132,7 @@ export default class TransactionsByVendorsService const { accountRepository } = this.tenancy.repositories(tenantId); const i18n = this.tenancy.i18n(tenantId); - + const tenant = await Tenant.query() .findById(tenantId) .withGraphFetched('metadata'); @@ -171,7 +167,6 @@ export default class TransactionsByVendorsService ); return { data: reportInstance.reportData(), - columns: reportInstance.reportColumns(), query: filter, }; } diff --git a/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorTableRows.ts b/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorTable.ts similarity index 76% rename from packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorTableRows.ts rename to packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorTable.ts index e37eeb8fed..14ad3c1b47 100644 --- a/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorTableRows.ts +++ b/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorTable.ts @@ -1,6 +1,10 @@ import * as R from 'ramda'; import { tableRowMapper } from 'utils'; -import { ITransactionsByVendorsVendor, ITableRow } from '@/interfaces'; +import { + ITransactionsByVendorsVendor, + ITableRow, + ITableColumn, +} from '@/interfaces'; import TransactionsByContactsTableRows from '../TransactionsByContact/TransactionsByContactTableRows'; enum ROW_TYPE { @@ -10,16 +14,15 @@ enum ROW_TYPE { VENDOR = 'VENDOR', } -export default class TransactionsByVendorsTableRows extends TransactionsByContactsTableRows { - vendorsTransactions: ITransactionsByVendorsVendor[]; +export class TransactionsByVendorsTable extends TransactionsByContactsTableRows { + private vendorsTransactions: ITransactionsByVendorsVendor[]; /** * Constructor method. + * @param {ITransactionsByVendorsVendor[]} vendorsTransactions - + * @param {any} i18n */ - constructor( - vendorsTransactions: ITransactionsByVendorsVendor[], - i18n - ) { + constructor(vendorsTransactions: ITransactionsByVendorsVendor[], i18n) { super(); this.vendorsTransactions = vendorsTransactions; @@ -73,4 +76,12 @@ export default class TransactionsByVendorsTableRows extends TransactionsByContac public tableRows = (): ITableRow[] => { return R.map(this.vendorRowsMapper)(this.vendorsTransactions); }; + + /** + * Retrieve the table columns of transactions by vendors report. + * @returns {ITableColumn[]} + */ + public tableColumns = (): ITableColumn[] => { + return []; + }; } diff --git a/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorTableInjectable.ts b/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorTableInjectable.ts new file mode 100644 index 0000000000..5b42b88e74 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorTableInjectable.ts @@ -0,0 +1,44 @@ +import { Inject, Service } from 'typedi'; +import HasTenancyService from '@/services/Tenancy/TenancyService'; +import { TransactionsByVendorsTable } from './TransactionsByVendorTable'; +import { + ITransactionsByVendorTable, + ITransactionsByVendorsFilter, +} from '@/interfaces'; +import { TransactionsByVendorsInjectable } from './TransactionsByVendorInjectable'; + +@Service() +export class TransactionsByVendorTableInjectable { + @Inject() + private tenancy: HasTenancyService; + + @Inject() + private transactionsByVendor: TransactionsByVendorsInjectable; + + /** + * Retrieves the transactions by vendor in table format. + * @param {number} tenantId + * @param {ITransactionsByReferenceQuery} query + * @returns {Promise} + */ + public async table( + tenantId: number, + query: ITransactionsByVendorsFilter + ): Promise { + const i18n = this.tenancy.i18n(tenantId); + + const sheet = await this.transactionsByVendor.transactionsByVendors( + tenantId, + query + ); + const table = new TransactionsByVendorsTable(sheet.data, i18n); + + return { + table: { + rows: table.tableRows(), + columns: table.tableColumns(), + }, + query, + }; + } +} diff --git a/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceExportInjectable.ts b/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceExportInjectable.ts new file mode 100644 index 0000000000..a515f1beb2 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceExportInjectable.ts @@ -0,0 +1,43 @@ +import { TableSheet } from '@/lib/Xlsx/TableSheet'; +import { ITrialBalanceSheetQuery } from '@/interfaces'; +import { Inject, Service } from 'typedi'; +import { TrialBalanceSheetTableInjectable } from './TrialBalanceSheetTableInjectable'; + +@Service() +export class TrialBalanceExportInjectable { + @Inject() + private trialBalanceSheetTable: TrialBalanceSheetTableInjectable; + + /** + * Retrieves the trial balance sheet in XLSX format. + * @param {number} tenantId + * @param {ITrialBalanceSheetQuery} query + * @returns {Promise} + */ + public async xlsx(tenantId: number, query: ITrialBalanceSheetQuery) { + const table = await this.trialBalanceSheetTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToXLSX(); + + return tableSheet.convertToBuffer(tableCsv, 'xlsx'); + } + + /** + * Retrieves the trial balance sheet in CSV format. + * @param {number} tenantId + * @param {ITrialBalanceSheetQuery} query + * @returns {Promise} + */ + public async csv( + tenantId: number, + query: ITrialBalanceSheetQuery + ): Promise { + const table = await this.trialBalanceSheetTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToCSV(); + + return tableCsv; + } +} diff --git a/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetApplication.ts b/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetApplication.ts new file mode 100644 index 0000000000..a771c8f15d --- /dev/null +++ b/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetApplication.ts @@ -0,0 +1,60 @@ +import { Inject, Service } from 'typedi'; +import { TrialBalanceSheetTableInjectable } from './TrialBalanceSheetTableInjectable'; +import { TrialBalanceExportInjectable } from './TrialBalanceExportInjectable'; +import { ITrialBalanceSheetQuery, ITrialBalanceStatement } from '@/interfaces'; +import TrialBalanceSheetService from './TrialBalanceSheetInjectable'; + +@Service() +export class TrialBalanceSheetApplication { + @Inject() + private sheetService: TrialBalanceSheetService; + + @Inject() + private tablable: TrialBalanceSheetTableInjectable; + + @Inject() + private exportable: TrialBalanceExportInjectable; + + /** + * Retrieves the trial balance sheet. + * @param {number} tenantId + * @param {ITrialBalanceSheetQuery} query + * @returns {Promise} + */ + public sheet( + tenantId: number, + query: ITrialBalanceSheetQuery + ): Promise { + return this.sheetService.trialBalanceSheet(tenantId, query); + } + + /** + * Retrieves the trial balance sheet in table format. + * @param {number} tenantId + * @param {ITrialBalanceSheetQuery} query + * @returns {Promise} + */ + public table(tenantId: number, query: ITrialBalanceSheetQuery) { + return this.tablable.table(tenantId, query); + } + + /** + * Retrieve the trial balance sheet in CSV format. + * @param {number} tenantId + * @param {ITrialBalanceSheetQuery} query + * @returns {Promise} + */ + public csv(tenantId: number, query: ITrialBalanceSheetQuery) { + return this.exportable.csv(tenantId, query); + } + + /** + * Retrieve the trial balance sheet in XLSX format. + * @param {number} tenantId + * @param {ITrialBalanceSheetQuery} query + * @returns {Promise} + */ + public async xlsx(tenantId: number, query: ITrialBalanceSheetQuery) { + return this.exportable.xlsx(tenantId, query); + } +} diff --git a/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetService.ts b/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetInjectable.ts similarity index 78% rename from packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetService.ts rename to packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetInjectable.ts index 150f160b00..bc880ec993 100644 --- a/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetService.ts +++ b/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetInjectable.ts @@ -1,7 +1,6 @@ import { Service, Inject } from 'typedi'; import moment from 'moment'; import TenancyService from '@/services/Tenancy/TenancyService'; -import Journal from '@/services/Accounting/JournalPoster'; import { ITrialBalanceSheetMeta, ITrialBalanceSheetQuery, @@ -13,7 +12,6 @@ import InventoryService from '@/services/Inventory/Inventory'; import { parseBoolean } from 'utils'; import { Tenant } from '@/system/models'; import { TrialBalanceSheetRepository } from './TrialBalanceSheetRepository'; -import { TrialBalanceSheetTable } from './TrialBalanceSheetTable'; @Service() export default class TrialBalanceSheetService extends FinancialSheet { @@ -30,7 +28,7 @@ export default class TrialBalanceSheetService extends FinancialSheet { * Defaults trial balance sheet filter query. * @return {IBalanceSheetQuery} */ - get defaultQuery(): ITrialBalanceSheetQuery { + private get defaultQuery(): ITrialBalanceSheetQuery { return { fromDate: moment().startOf('year').format('YYYY-MM-DD'), toDate: moment().format('YYYY-MM-DD'), @@ -54,7 +52,7 @@ export default class TrialBalanceSheetService extends FinancialSheet { * @param {number} tenantId - Tenant id. * @returns {ITrialBalanceSheetMeta} */ - reportMetadata(tenantId: number): ITrialBalanceSheetMeta { + private reportMetadata(tenantId: number): ITrialBalanceSheetMeta { const settings = this.tenancy.settings(tenantId); const isCostComputeRunning = @@ -89,7 +87,6 @@ export default class TrialBalanceSheetService extends FinancialSheet { ...this.defaultQuery, ...query, }; - const tenant = await Tenant.query() .findById(tenantId) .withGraphFetched('metadata'); @@ -120,27 +117,4 @@ export default class TrialBalanceSheetService extends FinancialSheet { meta: this.reportMetadata(tenantId), }; } - - /** - * Retrieves the trial balance sheet table. - * @param {number} tenantId - * @param {ITrialBalanceSheetQuery} query - * @returns {Promise} - */ - public async trialBalanceSheetTable( - tenantId: number, - query: ITrialBalanceSheetQuery - ) { - const trialBalance = await this.trialBalanceSheet(tenantId, query); - const table = new TrialBalanceSheetTable(trialBalance.data, query, {}); - - return { - table: { - columns: table.tableColumns(), - rows: table.tableRows(), - }, - meta: trialBalance.meta, - query: trialBalance.query, - }; - } } diff --git a/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetTableInjectable.ts b/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetTableInjectable.ts new file mode 100644 index 0000000000..e62a1dde29 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetTableInjectable.ts @@ -0,0 +1,33 @@ +import { Inject, Service } from 'typedi'; +import { ITrialBalanceSheetQuery, ITrialBalanceSheetTable } from '@/interfaces'; +import { TrialBalanceSheetTable } from './TrialBalanceSheetTable'; +import TrialBalanceSheetService from './TrialBalanceSheetInjectable'; + +@Service() +export class TrialBalanceSheetTableInjectable { + @Inject() + private sheet: TrialBalanceSheetService; + + /** + * Retrieves the trial balance sheet table. + * @param {number} tenantId + * @param {ITrialBalanceSheetQuery} query + * @returns {Promise} + */ + public async table( + tenantId: number, + query: ITrialBalanceSheetQuery + ): Promise { + const trialBalance = await this.sheet.trialBalanceSheet(tenantId, query); + const table = new TrialBalanceSheetTable(trialBalance.data, query, {}); + + return { + table: { + columns: table.tableColumns(), + rows: table.tableRows(), + }, + meta: trialBalance.meta, + query: trialBalance.query, + }; + } +} diff --git a/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummary.ts b/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummary.ts index 1d84d593f4..2e5e09aa40 100644 --- a/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummary.ts +++ b/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummary.ts @@ -101,8 +101,4 @@ export class VendorBalanceSummaryReport extends ContactBalanceSummaryReport { return { vendors, total }; } - - reportColumns() { - return []; - } } diff --git a/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryApplication.ts b/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryApplication.ts new file mode 100644 index 0000000000..5fe4bc74d3 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryApplication.ts @@ -0,0 +1,62 @@ +import { Inject, Service } from 'typedi'; +import { IVendorBalanceSummaryQuery } from '@/interfaces'; +import { VendorBalanceSummaryTableInjectable } from './VendorBalanceSummaryTableInjectable'; +import { VendorBalanceSummaryExportInjectable } from './VendorBalanceSummaryExportInjectable'; +import { VendorBalanceSummaryService } from './VendorBalanceSummaryService'; + +@Service() +export class VendorBalanceSummaryApplication { + @Inject() + private vendorBalanceSummaryTable: VendorBalanceSummaryTableInjectable; + + @Inject() + private vendorBalanceSummarySheet: VendorBalanceSummaryService; + + @Inject() + private vendorBalanceSummaryExport: VendorBalanceSummaryExportInjectable; + + /** + * Retrieves the vendor balance summary sheet in sheet format. + * @param {number} tenantId + * @param {IVendorBalanceSummaryQuery} query + */ + public sheet(tenantId: number, query: IVendorBalanceSummaryQuery) { + return this.vendorBalanceSummarySheet.vendorBalanceSummary(tenantId, query); + } + + /** + * Retrieves the vendor balance summary sheet in table format. + * @param {number} tenantId + * @param {IVendorBalanceSummaryQuery} query + * @returns {} + */ + public table(tenantId: number, query: IVendorBalanceSummaryQuery) { + return this.vendorBalanceSummaryTable.table(tenantId, query); + } + + /** + * Retrieves the vendor balance summary sheet in xlsx format. + * @param {number} tenantId + * @param {IVendorBalanceSummaryQuery} query + * @returns {Promise} + */ + public xlsx( + tenantId: number, + query: IVendorBalanceSummaryQuery + ): Promise { + return this.vendorBalanceSummaryExport.xlsx(tenantId, query); + } + + /** + * Retrieves the vendor balance summary sheet in csv format. + * @param {number} tenantId + * @param {IVendorBalanceSummaryQuery} query + * @returns {Promise} + */ + public csv( + tenantId: number, + query: IVendorBalanceSummaryQuery + ): Promise { + return this.vendorBalanceSummaryExport.csv(tenantId, query); + } +} diff --git a/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryExportInjectable.ts b/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryExportInjectable.ts new file mode 100644 index 0000000000..ba278f88db --- /dev/null +++ b/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryExportInjectable.ts @@ -0,0 +1,43 @@ +import { Inject, Service } from 'typedi'; +import { IVendorBalanceSummaryQuery } from '@/interfaces'; +import { VendorBalanceSummaryTableInjectable } from './VendorBalanceSummaryTableInjectable'; +import { TableSheet } from '@/lib/Xlsx/TableSheet'; + +@Service() +export class VendorBalanceSummaryExportInjectable { + @Inject() + private customerBalanceSummaryTable: VendorBalanceSummaryTableInjectable; + + /** + * Retrieves the vendor balance summary sheet in XLSX format. + * @param {number} tenantId + * @param {IVendorBalanceSummaryQuery} query + * @returns {Promise} + */ + public async xlsx(tenantId: number, query: IVendorBalanceSummaryQuery) { + const table = await this.customerBalanceSummaryTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToXLSX(); + + return tableSheet.convertToBuffer(tableCsv, 'xlsx'); + } + + /** + * Retrieves the vendor balance summary sheet in CSV format. + * @param {number} tenantId + * @param {IVendorBalanceSummaryQuery} query + * @returns {Promise} + */ + public async csv( + tenantId: number, + query: IVendorBalanceSummaryQuery + ): Promise { + const table = await this.customerBalanceSummaryTable.table(tenantId, query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToCSV(); + + return tableCsv; + } +} diff --git a/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryRepository.ts b/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryRepository.ts index a8d67089dd..721291b7dc 100644 --- a/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryRepository.ts +++ b/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryRepository.ts @@ -7,7 +7,7 @@ import { ACCOUNT_TYPE } from '@/data/AccountTypes'; @Service() export default class VendorBalanceSummaryRepository { @Inject() - tenancy: HasTenancyService; + private tenancy: HasTenancyService; /** * Retrieve the report vendors. diff --git a/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryService.ts b/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryService.ts index 82dc0475dd..b1a361b87f 100644 --- a/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryService.ts +++ b/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryService.ts @@ -1,10 +1,8 @@ import { Inject } from 'typedi'; import moment from 'moment'; -import { map } from 'lodash'; import * as R from 'ramda'; import TenancyService from '@/services/Tenancy/TenancyService'; import { - IVendor, IVendorBalanceSummaryService, IVendorBalanceSummaryQuery, IVendorBalanceSummaryStatement, @@ -15,15 +13,12 @@ import Ledger from '@/services/Accounting/Ledger'; import VendorBalanceSummaryRepository from './VendorBalanceSummaryRepository'; import { Tenant } from '@/system/models'; -export default class VendorBalanceSummaryService +export class VendorBalanceSummaryService implements IVendorBalanceSummaryService { @Inject() tenancy: TenancyService; - @Inject('logger') - logger: any; - @Inject() reportRepo: VendorBalanceSummaryRepository; @@ -31,7 +26,7 @@ export default class VendorBalanceSummaryService * Defaults balance sheet filter query. * @return {IVendorBalanceSummaryQuery} */ - get defaultQuery(): IVendorBalanceSummaryQuery { + private get defaultQuery(): IVendorBalanceSummaryQuery { return { asDate: moment().format('YYYY-MM-DD'), numberFormat: { @@ -72,7 +67,7 @@ export default class VendorBalanceSummaryService * @param {IVendorBalanceSummaryQuery} query - * @return {Promise} */ - async vendorBalanceSummary( + public async vendorBalanceSummary( tenantId: number, query: IVendorBalanceSummaryQuery ): Promise { @@ -81,13 +76,7 @@ export default class VendorBalanceSummaryService .withGraphFetched('metadata'); const filter = { ...this.defaultQuery, ...query }; - this.logger.info( - '[customer_balance_summary] trying to calculate the report.', - { - filter, - tenantId, - } - ); + // Retrieve the vendors transactions. const vendorsEntries = await this.getReportVendorsEntries( tenantId, @@ -111,7 +100,6 @@ export default class VendorBalanceSummaryService return { data: reportInstance.reportData(), - columns: reportInstance.reportColumns(), query: filter, }; } diff --git a/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryTableInjectable.ts b/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryTableInjectable.ts new file mode 100644 index 0000000000..aec97e6f13 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryTableInjectable.ts @@ -0,0 +1,44 @@ +import { + IVendorBalanceSummaryQuery, + IVendorBalanceSummaryTable, +} from '@/interfaces'; +import HasTenancyService from '@/services/Tenancy/TenancyService'; +import { Inject, Service } from 'typedi'; +import { VendorBalanceSummaryTable } from './VendorBalanceSummaryTableRows'; +import { VendorBalanceSummaryService } from './VendorBalanceSummaryService'; + +@Service() +export class VendorBalanceSummaryTableInjectable { + @Inject() + private tenancy: HasTenancyService; + + @Inject() + private vendorBalanceSummarySheet: VendorBalanceSummaryService; + + /** + * Retrieves the vendor balance summary sheet in table format. + * @param {number} tenantId + * @param {IVendorBalanceSummaryQuery} query + * @returns {Promise} + */ + public async table( + tenantId: number, + query: IVendorBalanceSummaryQuery + ): Promise { + const i18n = this.tenancy.i18n(tenantId); + + const { data } = await this.vendorBalanceSummarySheet.vendorBalanceSummary( + tenantId, + query + ); + const table = new VendorBalanceSummaryTable(data, query, i18n); + + return { + table: { + columns: table.tableColumns(), + rows: table.tableRows(), + }, + query, + }; + } +} diff --git a/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryTableRows.ts b/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryTableRows.ts index d65ced56e4..2095ea087c 100644 --- a/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryTableRows.ts +++ b/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryTableRows.ts @@ -15,7 +15,7 @@ enum TABLE_ROWS_TYPES { TOTAL = 'TOTAL', } -export default class VendorBalanceSummaryTable { +export class VendorBalanceSummaryTable { i18n: any; report: IVendorBalanceSummaryData; query: IVendorBalanceSummaryQuery; diff --git a/packages/server/src/utils/deepdash.ts b/packages/server/src/utils/deepdash.ts index 6a97209e0b..0ce65216a4 100644 --- a/packages/server/src/utils/deepdash.ts +++ b/packages/server/src/utils/deepdash.ts @@ -78,6 +78,27 @@ const filterNodesDeep = (predicate, nodes) => { ); }; +const flatNestedTree = (obj, mapper, options) => { + return reduceDeep( + obj, + (accumulator, value, key, parentValue, context) => { + const computedValue = _.omit(value, ['children']); + const mappedValue = mapper + ? mapper(computedValue, key, context) + : computedValue; + + accumulator.push(mappedValue); + return accumulator; + }, + [], + { + childrenPath: 'children', + pathFormat: 'array', + ...options, + } + ); +}; + export { iteratee, condense, @@ -103,4 +124,5 @@ export { someDeep, mapValuesDeepReverse, filterNodesDeep, + flatNestedTree, }; diff --git a/packages/server/src/utils/table.ts b/packages/server/src/utils/table.ts index a6d39be942..74f5c31709 100644 --- a/packages/server/src/utils/table.ts +++ b/packages/server/src/utils/table.ts @@ -22,7 +22,9 @@ export function tableRowMapper( ): ITableRow { const cells = columns.map((column) => ({ key: column.key, - value: column.value ? column.value : getAccessor(object, column.accessor), + value: column.value + ? column.value + : getAccessor(object, column.accessor) || '', })); return { diff --git a/packages/webapp/src/containers/FinancialStatements/APAgingSummary/APAgingSummaryActionsBar.tsx b/packages/webapp/src/containers/FinancialStatements/APAgingSummary/APAgingSummaryActionsBar.tsx index de806ab2f3..f0473ab586 100644 --- a/packages/webapp/src/containers/FinancialStatements/APAgingSummary/APAgingSummaryActionsBar.tsx +++ b/packages/webapp/src/containers/FinancialStatements/APAgingSummary/APAgingSummaryActionsBar.tsx @@ -15,6 +15,7 @@ import { DashboardActionsBar, FormattedMessage as T, Icon } from '@/components'; import { useAPAgingSummaryContext } from './APAgingSummaryProvider'; import NumberFormatDropdown from '@/components/NumberFormatDropdown'; +import { APAgingSummaryExportMenu } from './components'; import withAPAgingSummary from './withAPAgingSummary'; import withAPAgingSummaryActions from './withAPAgingSummaryActions'; @@ -106,11 +107,18 @@ function APAgingSummaryActionsBar({ icon={} text={} /> -