diff --git a/packages/server/resources/scss/modules/financial-sheet.scss b/packages/server/resources/scss/modules/financial-sheet.scss new file mode 100644 index 000000000..bceb51dc0 --- /dev/null +++ b/packages/server/resources/scss/modules/financial-sheet.scss @@ -0,0 +1,57 @@ +@import "../base.scss"; + +html, +body { + font-size: 14px; +} +body{ + font-weight: 400; + letter-spacing: 0; + line-height: 1.28581; + text-transform: none; + color: #000; + font-family: Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Open Sans, Helvetica Neue, Icons16, sans-serif; +} +.sheet{ + padding: 20px; +} +.sheet__company-name{ + margin: 0; + font-size: 1.4rem; +} +.sheet__sheet-type { + margin: 0 +} +.sheet__sheet-date { + margin-top: 0.35rem; +} + +.sheet__header { + text-align: center; + margin-bottom: 1rem; +} + +.sheet__table { + border-top: 1px solid #000; + table-layout: fixed; + border-spacing: 0; + text-align: left; + font-size: inherit; + width: 100%; +} + +.sheet__table thead th { + color: #000; + border-bottom: 1px solid #000000; + padding: 0.5rem; +} + +.sheet__table tbody td { + border-bottom: 0; + padding-top: 0.28rem; + padding-bottom: 0.28rem; + padding-left: 0.5rem; + padding-right: 0.5rem; + color: #252A31; + border-bottom: 1px solid transparent; +} \ No newline at end of file diff --git a/packages/server/resources/views/modules/financial-sheet.pug b/packages/server/resources/views/modules/financial-sheet.pug new file mode 100644 index 000000000..f4c59ec3a --- /dev/null +++ b/packages/server/resources/views/modules/financial-sheet.pug @@ -0,0 +1,24 @@ +block head + style + include ../../css/modules/financial-sheet.css + +style. + !{customCSS} + +block content + .sheet + .sheet__header + .sheet__company-name=organizationName + .sheet__sheet-type=sheetName + .sheet__sheet-date=sheetDate + + table.sheet__table + thead + tr + each column in table.columns + th(style=column.style class='column--' + column.key)= column.label + tbody + each row in table.rows + tr(class=row.classNames) + each cell in row.cells + td(class='cell--' + cell.key)!= cell.value \ No newline at end of file diff --git a/packages/server/scripts/gulpConfig.js b/packages/server/scripts/gulpConfig.js index 51bbc3aff..1caa9af23 100644 --- a/packages/server/scripts/gulpConfig.js +++ b/packages/server/scripts/gulpConfig.js @@ -66,12 +66,10 @@ module.exports = { // sourcemaps: true, // Allow to enable/disable sourcemaps or pass object to configure it. // minify: true, // Allow to enable/disable minify the source. }, - // { - // src: './assets/sass/editor-style.scss', - // dest: './assets/css', - // sourcemaps: true, - // minify: true, - // }, + { + src: `${RESOURCES_PATH}/scss/modules/financial-sheet.scss`, + dest: `${RESOURCES_PATH}/css/modules`, + }, ], // RTL builds. rtl: [ @@ -114,7 +112,7 @@ module.exports = { // SASS Configuration for all builds. sass: { errLogToConsole: true, - // outputStyle: 'compact', + // outputStyle: 'compact', }, // CSS MQ Packer configuration for all builds and style tasks. diff --git a/packages/server/src/api/controllers/FinancialStatements/APAgingSummary.ts b/packages/server/src/api/controllers/FinancialStatements/APAgingSummary.ts index 5d626896c..d87873a2b 100644 --- a/packages/server/src/api/controllers/FinancialStatements/APAgingSummary.ts +++ b/packages/server/src/api/controllers/FinancialStatements/APAgingSummary.ts @@ -71,6 +71,7 @@ export default class APAgingSummaryReportController extends BaseFinancialReportC ACCEPT_TYPE.APPLICATION_JSON_TABLE, ACCEPT_TYPE.APPLICATION_CSV, ACCEPT_TYPE.APPLICATION_XLSX, + ACCEPT_TYPE.APPLICATION_PDF ]); // Retrieves the json table format. if (ACCEPT_TYPE.APPLICATION_JSON_TABLE === acceptType) { @@ -98,6 +99,15 @@ export default class APAgingSummaryReportController extends BaseFinancialReportC 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' ); return res.send(buffer); + // Retrieves the pdf format. + } else if (ACCEPT_TYPE.APPLICATION_PDF === acceptType) { + const pdfContent = await this.APAgingSummaryApp.pdf(tenantId, filter); + + res.set({ + 'Content-Type': 'application/pdf', + 'Content-Length': pdfContent.length, + }); + return res.send(pdfContent); // Retrieves the json format. } else { const sheet = await this.APAgingSummaryApp.sheet(tenantId, filter); diff --git a/packages/server/src/api/controllers/FinancialStatements/ARAgingSummary.ts b/packages/server/src/api/controllers/FinancialStatements/ARAgingSummary.ts index 10e42e900..86b4b920a 100644 --- a/packages/server/src/api/controllers/FinancialStatements/ARAgingSummary.ts +++ b/packages/server/src/api/controllers/FinancialStatements/ARAgingSummary.ts @@ -11,7 +11,7 @@ import { ACCEPT_TYPE } from '@/interfaces/Http'; @Service() export default class ARAgingSummaryReportController extends BaseFinancialReportController { @Inject() - ARAgingSummaryApp: ARAgingSummaryApplication; + private ARAgingSummaryApp: ARAgingSummaryApplication; /** * Router constructor. @@ -69,6 +69,7 @@ export default class ARAgingSummaryReportController extends BaseFinancialReportC ACCEPT_TYPE.APPLICATION_JSON_TABLE, ACCEPT_TYPE.APPLICATION_CSV, ACCEPT_TYPE.APPLICATION_XLSX, + ACCEPT_TYPE.APPLICATION_PDF ]); // Retrieves the xlsx format. if (ACCEPT_TYPE.APPLICATION_XLSX === acceptType) { @@ -96,6 +97,15 @@ export default class ARAgingSummaryReportController extends BaseFinancialReportC res.setHeader('Content-Type', 'text/csv'); return res.send(buffer); + // Retrieves the pdf format. + } else if (ACCEPT_TYPE.APPLICATION_PDF === acceptType) { + const pdfContent = await this.ARAgingSummaryApp.pdf(tenantId, filter); + + res.set({ + 'Content-Type': 'application/pdf', + 'Content-Length': pdfContent.length, + }); + return res.send(pdfContent); // Retrieves the json format. } else { const sheet = await this.ARAgingSummaryApp.sheet(tenantId, filter); diff --git a/packages/server/src/api/controllers/FinancialStatements/BalanceSheet.ts b/packages/server/src/api/controllers/FinancialStatements/BalanceSheet.ts index 0af53d723..fda717a38 100644 --- a/packages/server/src/api/controllers/FinancialStatements/BalanceSheet.ts +++ b/packages/server/src/api/controllers/FinancialStatements/BalanceSheet.ts @@ -101,6 +101,7 @@ export default class BalanceSheetStatementController extends BaseFinancialReport ACCEPT_TYPE.APPLICATION_JSON_TABLE, ACCEPT_TYPE.APPLICATION_XLSX, ACCEPT_TYPE.APPLICATION_CSV, + ACCEPT_TYPE.APPLICATION_PDF, ]); // Retrieves the json table format. if (ACCEPT_TYPE.APPLICATION_JSON_TABLE == acceptType) { @@ -128,6 +129,15 @@ export default class BalanceSheetStatementController extends BaseFinancialReport 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' ); return res.send(buffer); + // Retrieves the pdf format. + } else if (ACCEPT_TYPE.APPLICATION_PDF === acceptType) { + const pdfContent = await this.balanceSheetApp.pdf(tenantId, filter); + + res.set({ + 'Content-Type': 'application/pdf', + 'Content-Length': pdfContent.length, + }); + res.send(pdfContent); } else { const sheet = await this.balanceSheetApp.sheet(tenantId, filter); diff --git a/packages/server/src/api/controllers/FinancialStatements/CashFlow/CashFlow.ts b/packages/server/src/api/controllers/FinancialStatements/CashFlow/CashFlow.ts index bab04246d..bc24b5379 100644 --- a/packages/server/src/api/controllers/FinancialStatements/CashFlow/CashFlow.ts +++ b/packages/server/src/api/controllers/FinancialStatements/CashFlow/CashFlow.ts @@ -79,6 +79,7 @@ export default class CashFlowController extends BaseFinancialReportController { ACCEPT_TYPE.APPLICATION_JSON_TABLE, ACCEPT_TYPE.APPLICATION_CSV, ACCEPT_TYPE.APPLICATION_XLSX, + ACCEPT_TYPE.APPLICATION_PDF ]); // Retrieves the json table format. if (ACCEPT_TYPE.APPLICATION_JSON_TABLE === acceptType) { @@ -106,6 +107,15 @@ export default class CashFlowController extends BaseFinancialReportController { 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' ); return res.send(buffer); + // Retrieves the pdf format. + } else if (ACCEPT_TYPE.APPLICATION_PDF === acceptType) { + const pdfContent = await this.cashflowSheetApp.pdf(tenantId, filter); + + res.set({ + 'Content-Type': 'application/pdf', + 'Content-Length': pdfContent.length, + }); + return res.send(pdfContent); // Retrieves the json format. } else { const cashflow = await this.cashflowSheetApp.sheet(tenantId, filter); diff --git a/packages/server/src/api/controllers/FinancialStatements/CustomerBalanceSummary/index.ts b/packages/server/src/api/controllers/FinancialStatements/CustomerBalanceSummary/index.ts index 6c10543f5..e69fcdc1c 100644 --- a/packages/server/src/api/controllers/FinancialStatements/CustomerBalanceSummary/index.ts +++ b/packages/server/src/api/controllers/FinancialStatements/CustomerBalanceSummary/index.ts @@ -75,6 +75,7 @@ export default class CustomerBalanceSummaryReportController extends BaseFinancia ACCEPT_TYPE.APPLICATION_JSON_TABLE, ACCEPT_TYPE.APPLICATION_CSV, ACCEPT_TYPE.APPLICATION_XLSX, + ACCEPT_TYPE.APPLICATION_PDF, ]); // Retrieves the xlsx format. @@ -109,6 +110,19 @@ export default class CustomerBalanceSummaryReportController extends BaseFinancia filter ); return res.status(200).send(table); + // Retrieves the pdf format. + } else if (ACCEPT_TYPE.APPLICATION_PDF === acceptType) { + const buffer = await this.customerBalanceSummaryApp.pdf( + tenantId, + filter + ); + + res.set({ + 'Content-Type': 'application/pdf', + 'Content-Length': buffer.length, + }); + return res.send(buffer); + // Retrieves the json format. } else { const sheet = await this.customerBalanceSummaryApp.sheet( tenantId, diff --git a/packages/server/src/api/controllers/FinancialStatements/GeneralLedger.ts b/packages/server/src/api/controllers/FinancialStatements/GeneralLedger.ts index c86da8eae..188178a01 100644 --- a/packages/server/src/api/controllers/FinancialStatements/GeneralLedger.ts +++ b/packages/server/src/api/controllers/FinancialStatements/GeneralLedger.ts @@ -16,7 +16,7 @@ export default class GeneralLedgerReportController extends BaseFinancialReportCo /** * Router constructor. */ - router() { + public router() { const router = Router(); router.get( @@ -32,7 +32,7 @@ export default class GeneralLedgerReportController extends BaseFinancialReportCo /** * Validation schema. */ - get validationSchema(): ValidationChain[] { + private get validationSchema(): ValidationChain[] { return [ query('from_date').optional().isISO8601(), query('to_date').optional().isISO8601(), @@ -61,7 +61,7 @@ export default class GeneralLedgerReportController extends BaseFinancialReportCo * @param {Request} req - * @param {Response} res - */ - async generalLedger(req: Request, res: Response, next: NextFunction) { + private async generalLedger(req: Request, res: Response, next: NextFunction) { const { tenantId } = req; const filter = this.matchedQueryData(req); const accept = this.accepts(req); @@ -71,6 +71,7 @@ export default class GeneralLedgerReportController extends BaseFinancialReportCo ACCEPT_TYPE.APPLICATION_JSON_TABLE, ACCEPT_TYPE.APPLICATION_XLSX, ACCEPT_TYPE.APPLICATION_CSV, + ACCEPT_TYPE.APPLICATION_PDF, ]); // Retrieves the table format. if (ACCEPT_TYPE.APPLICATION_JSON_TABLE === acceptType) { @@ -95,6 +96,17 @@ export default class GeneralLedgerReportController extends BaseFinancialReportCo 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' ); return res.send(buffer); + // Retrieves the pdf format. + } else if (ACCEPT_TYPE.APPLICATION_PDF === acceptType) { + const pdfContent = await this.generalLedgerApplication.pdf( + tenantId, + filter + ); + res.set({ + 'Content-Type': 'application/pdf', + 'Content-Length': pdfContent.length, + }); + return res.send(pdfContent); // Retrieves the json format. } else { const sheet = await this.generalLedgerApplication.sheet(tenantId, filter); diff --git a/packages/server/src/api/controllers/FinancialStatements/InventoryDetails/index.ts b/packages/server/src/api/controllers/FinancialStatements/InventoryDetails/index.ts index 07f91af4a..3288ee847 100644 --- a/packages/server/src/api/controllers/FinancialStatements/InventoryDetails/index.ts +++ b/packages/server/src/api/controllers/FinancialStatements/InventoryDetails/index.ts @@ -96,6 +96,7 @@ export default class InventoryDetailsController extends BaseController { ACCEPT_TYPE.APPLICATION_JSON_TABLE, ACCEPT_TYPE.APPLICATION_CSV, ACCEPT_TYPE.APPLICATION_XLSX, + ACCEPT_TYPE.APPLICATION_PDF, ]); // Retrieves the csv format. if (acceptType === ACCEPT_TYPE.APPLICATION_CSV) { @@ -127,6 +128,15 @@ export default class InventoryDetailsController extends BaseController { filter ); return res.status(200).send(table); + // Retrieves the pdf format. + } else if (acceptType === ACCEPT_TYPE.APPLICATION_PDF) { + const buffer = await this.inventoryItemDetailsApp.pdf(tenantId, filter); + + res.set({ + 'Content-Type': 'application/pdf', + 'Content-Length': buffer.length, + }); + return res.send(buffer); } else { const sheet = await this.inventoryItemDetailsApp.sheet( tenantId, diff --git a/packages/server/src/api/controllers/FinancialStatements/InventoryValuationSheet.ts b/packages/server/src/api/controllers/FinancialStatements/InventoryValuationSheet.ts index 3a2d3c196..b31a911a2 100644 --- a/packages/server/src/api/controllers/FinancialStatements/InventoryValuationSheet.ts +++ b/packages/server/src/api/controllers/FinancialStatements/InventoryValuationSheet.ts @@ -79,6 +79,7 @@ export default class InventoryValuationReportController extends BaseFinancialRep ACCEPT_TYPE.APPLICATION_JSON_TABLE, ACCEPT_TYPE.APPLICATION_XLSX, ACCEPT_TYPE.APPLICATION_CSV, + ACCEPT_TYPE.APPLICATION_PDF, ]); // Retrieves the json table format. @@ -104,6 +105,15 @@ export default class InventoryValuationReportController extends BaseFinancialRep 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' ); return res.send(buffer); + // Retrieves the pdf format. + } else if (ACCEPT_TYPE.APPLICATION_PDF === acceptType) { + const pdfContent = await this.inventoryValuationApp.pdf(tenantId, filter); + + res.set({ + 'Content-Type': 'application/pdf', + 'Content-Length': pdfContent.length, + }); + return res.status(200).send(pdfContent); // Retrieves the json format. } else { const { data, query, meta } = await this.inventoryValuationApp.sheet( diff --git a/packages/server/src/api/controllers/FinancialStatements/JournalSheet.ts b/packages/server/src/api/controllers/FinancialStatements/JournalSheet.ts index 871bc9af8..561f69329 100644 --- a/packages/server/src/api/controllers/FinancialStatements/JournalSheet.ts +++ b/packages/server/src/api/controllers/FinancialStatements/JournalSheet.ts @@ -72,6 +72,7 @@ export default class JournalSheetController extends BaseFinancialReportControlle ACCEPT_TYPE.APPLICATION_JSON_TABLE, ACCEPT_TYPE.APPLICATION_XLSX, ACCEPT_TYPE.APPLICATION_CSV, + ACCEPT_TYPE.APPLICATION_PDF, ]); // Retrieves the json table format. @@ -81,7 +82,7 @@ export default class JournalSheetController extends BaseFinancialReportControlle // Retrieves the csv format. } else if (ACCEPT_TYPE.APPLICATION_CSV === acceptType) { const buffer = await this.journalSheetApp.csv(tenantId, filter); - + res.setHeader('Content-Disposition', 'attachment; filename=output.csv'); res.setHeader('Content-Type', 'text/csv'); @@ -97,6 +98,14 @@ export default class JournalSheetController extends BaseFinancialReportControlle ); return res.send(buffer); // Retrieves the json format. + } else if (ACCEPT_TYPE.APPLICATION_PDF === acceptType) { + const pdfContent = await this.journalSheetApp.pdf(tenantId, filter); + + res.set({ + 'Content-Type': 'application/pdf', + 'Content-Length': pdfContent.length, + }); + res.send(pdfContent); } else { const sheet = await this.journalSheetApp.sheet(tenantId, filter); diff --git a/packages/server/src/api/controllers/FinancialStatements/ProfitLossSheet.ts b/packages/server/src/api/controllers/FinancialStatements/ProfitLossSheet.ts index 8c2404335..995df07b4 100644 --- a/packages/server/src/api/controllers/FinancialStatements/ProfitLossSheet.ts +++ b/packages/server/src/api/controllers/FinancialStatements/ProfitLossSheet.ts @@ -96,6 +96,7 @@ export default class ProfitLossSheetController extends BaseFinancialReportContro ACCEPT_TYPE.APPLICATION_JSON_TABLE, ACCEPT_TYPE.APPLICATION_CSV, ACCEPT_TYPE.APPLICATION_XLSX, + ACCEPT_TYPE.APPLICATION_PDF, ]); try { // Retrieves the csv format. @@ -125,6 +126,14 @@ export default class ProfitLossSheetController extends BaseFinancialReportContro ); return res.send(sheet); // Retrieves the json format. + } else if (acceptType === ACCEPT_TYPE.APPLICATION_PDF) { + const pdfContent = await this.profitLossSheetApp.pdf(tenantId, filter); + + res.set({ + 'Content-Type': 'application/pdf', + 'Content-Length': pdfContent.length, + }); + return res.send(pdfContent); } else { const sheet = await this.profitLossSheetApp.sheet(tenantId, filter); diff --git a/packages/server/src/api/controllers/FinancialStatements/PurchasesByItem.ts b/packages/server/src/api/controllers/FinancialStatements/PurchasesByItem.ts index 2e72587c0..2c92bdc97 100644 --- a/packages/server/src/api/controllers/FinancialStatements/PurchasesByItem.ts +++ b/packages/server/src/api/controllers/FinancialStatements/PurchasesByItem.ts @@ -75,8 +75,8 @@ export default class PurchasesByItemReportController extends BaseFinancialReport ACCEPT_TYPE.APPLICATION_JSON_TABLE, ACCEPT_TYPE.APPLICATION_XLSX, ACCEPT_TYPE.APPLICATION_CSV, + ACCEPT_TYPE.APPLICATION_PDF, ]); - // JSON table response format. if (ACCEPT_TYPE.APPLICATION_JSON_TABLE === acceptType) { const table = await this.purchasesByItemsApp.table(tenantId, filter); @@ -100,6 +100,15 @@ export default class PurchasesByItemReportController extends BaseFinancialReport 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' ); return res.send(buffer); + // PDF response format. + } else if (ACCEPT_TYPE.APPLICATION_PDF === acceptType) { + const pdfContent = await this.purchasesByItemsApp.pdf(tenantId, filter); + + res.set({ + 'Content-Type': 'application/pdf', + 'Content-Length': pdfContent.length, + }); + return res.send(pdfContent); // Json response format. } else { const sheet = await this.purchasesByItemsApp.sheet(tenantId, filter); diff --git a/packages/server/src/api/controllers/FinancialStatements/SalesByItems.ts b/packages/server/src/api/controllers/FinancialStatements/SalesByItems.ts index bac67231c..28ab611c0 100644 --- a/packages/server/src/api/controllers/FinancialStatements/SalesByItems.ts +++ b/packages/server/src/api/controllers/FinancialStatements/SalesByItems.ts @@ -11,7 +11,7 @@ import { SalesByItemsApplication } from '@/services/FinancialStatements/SalesByI @Service() export default class SalesByItemsReportController extends BaseFinancialReportController { @Inject() - salesByItemsApp: SalesByItemsApplication; + private salesByItemsApp: SalesByItemsApplication; /** * Router constructor. @@ -71,6 +71,7 @@ export default class SalesByItemsReportController extends BaseFinancialReportCon ACCEPT_TYPE.APPLICATION_JSON_TABLE, ACCEPT_TYPE.APPLICATION_CSV, ACCEPT_TYPE.APPLICATION_XLSX, + ACCEPT_TYPE.APPLICATION_PDF, ]); // Retrieves the csv format. if (ACCEPT_TYPE.APPLICATION_CSV === acceptType) { @@ -96,6 +97,14 @@ export default class SalesByItemsReportController extends BaseFinancialReportCon ); return res.send(buffer); // Retrieves the json format. + } else if (ACCEPT_TYPE.APPLICATION_PDF === acceptType) { + const pdfContent = await this.salesByItemsApp.pdf(tenantId, filter); + + res.set({ + 'Content-Type': 'application/pdf', + 'Content-Length': pdfContent.length, + }); + return res.send(pdfContent); } else { const sheet = await this.salesByItemsApp.sheet(tenantId, filter); return res.status(200).send(sheet); diff --git a/packages/server/src/api/controllers/FinancialStatements/SalesTaxLiabilitySummary/index.ts b/packages/server/src/api/controllers/FinancialStatements/SalesTaxLiabilitySummary/index.ts index 933b5c9c4..42a96aab2 100644 --- a/packages/server/src/api/controllers/FinancialStatements/SalesTaxLiabilitySummary/index.ts +++ b/packages/server/src/api/controllers/FinancialStatements/SalesTaxLiabilitySummary/index.ts @@ -62,6 +62,7 @@ export default class SalesTaxLiabilitySummary extends BaseFinancialReportControl ACCEPT_TYPE.APPLICATION_JSON_TABLE, ACCEPT_TYPE.APPLICATION_CSV, ACCEPT_TYPE.APPLICATION_XLSX, + ACCEPT_TYPE.APPLICATION_PDF, ]); // Retrieves the json table format. @@ -97,6 +98,16 @@ export default class SalesTaxLiabilitySummary extends BaseFinancialReportControl return res.send(buffer); // Retrieves the json format. + } else if (acceptType === ACCEPT_TYPE.APPLICATION_PDF) { + const pdfContent = await this.salesTaxLiabilitySummaryApp.pdf( + tenantId, + filter + ); + res.set({ + 'Content-Type': 'application/pdf', + 'Content-Length': pdfContent.length, + }); + return res.status(200).send(pdfContent); } else { const sheet = await this.salesTaxLiabilitySummaryApp.sheet( tenantId, diff --git a/packages/server/src/api/controllers/FinancialStatements/TransactionsByCustomers/index.ts b/packages/server/src/api/controllers/FinancialStatements/TransactionsByCustomers/index.ts index 4bc3b1f44..c10eeea16 100644 --- a/packages/server/src/api/controllers/FinancialStatements/TransactionsByCustomers/index.ts +++ b/packages/server/src/api/controllers/FinancialStatements/TransactionsByCustomers/index.ts @@ -70,6 +70,7 @@ export default class TransactionsByCustomersReportController extends BaseFinanci ACCEPT_TYPE.APPLICATION_JSON_TABLE, ACCEPT_TYPE.APPLICATION_CSV, ACCEPT_TYPE.APPLICATION_XLSX, + ACCEPT_TYPE.APPLICATION_PDF, ]); try { // Retrieves the json table format. @@ -103,6 +104,16 @@ export default class TransactionsByCustomersReportController extends BaseFinanci ); return res.send(buffer); // Retrieve the json format. + } else if (ACCEPT_TYPE.APPLICATION_PDF === acceptType) { + const pdfContent = await this.transactionsByCustomersApp.pdf( + tenantId, + filter + ); + res.set({ + 'Content-Type': 'application/pdf', + 'Content-Length': pdfContent.length, + }); + return res.send(pdfContent); } else { const sheet = await this.transactionsByCustomersApp.sheet( tenantId, diff --git a/packages/server/src/api/controllers/FinancialStatements/TransactionsByVendors/index.ts b/packages/server/src/api/controllers/FinancialStatements/TransactionsByVendors/index.ts index a0c1bf037..c437892f4 100644 --- a/packages/server/src/api/controllers/FinancialStatements/TransactionsByVendors/index.ts +++ b/packages/server/src/api/controllers/FinancialStatements/TransactionsByVendors/index.ts @@ -71,6 +71,7 @@ export default class TransactionsByVendorsReportController extends BaseFinancial ACCEPT_TYPE.APPLICATION_JSON_TABLE, ACCEPT_TYPE.APPLICATION_CSV, ACCEPT_TYPE.APPLICATION_XLSX, + ACCEPT_TYPE.APPLICATION_PDF, ]); // Retrieves the xlsx format. @@ -101,6 +102,17 @@ export default class TransactionsByVendorsReportController extends BaseFinancial filter ); return res.status(200).send(table); + // Retrieves the pdf format. + } else if (ACCEPT_TYPE.APPLICATION_PDF === acceptType) { + const pdfContent = await this.transactionsByVendorsApp.pdf( + tenantId, + filter + ); + res.set({ + 'Content-Type': 'application/pdf', + 'Content-Length': pdfContent.length, + }); + return res.send(pdfContent); // Retrieves the json format. } else { const sheet = await this.transactionsByVendorsApp.sheet( diff --git a/packages/server/src/api/controllers/FinancialStatements/TrialBalanceSheet.ts b/packages/server/src/api/controllers/FinancialStatements/TrialBalanceSheet.ts index ce23c1071..b92e355a2 100644 --- a/packages/server/src/api/controllers/FinancialStatements/TrialBalanceSheet.ts +++ b/packages/server/src/api/controllers/FinancialStatements/TrialBalanceSheet.ts @@ -3,7 +3,6 @@ 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/TrialBalanceSheetInjectable'; import BaseFinancialReportController from './BaseFinancialReportController'; import { AbilitySubject, ReportsAction } from '@/interfaces'; import CheckPolicies from '@/api/middleware/CheckPolicies'; @@ -81,6 +80,7 @@ export default class TrialBalanceSheetController extends BaseFinancialReportCont ACCEPT_TYPE.APPLICATION_JSON_TABLE, ACCEPT_TYPE.APPLICATION_CSV, ACCEPT_TYPE.APPLICATION_XLSX, + ACCEPT_TYPE.APPLICATION_PDF, ]); // Retrieves in json table format. if (acceptType === ACCEPT_TYPE.APPLICATION_JSON_TABLE) { @@ -109,6 +109,17 @@ export default class TrialBalanceSheetController extends BaseFinancialReportCont res.setHeader('Content-Type', 'text/csv'); return res.send(buffer); + // Retrieves in pdf format. + } else if (acceptType === ACCEPT_TYPE.APPLICATION_PDF) { + const pdfContent = await this.trialBalanceSheetApp.pdf( + tenantId, + filter + ); + res.set({ + 'Content-Type': 'application/pdf', + 'Content-Length': pdfContent.length, + }); + res.send(pdfContent); // Retrieves in json format. } else { const { data, query, meta } = await this.trialBalanceSheetApp.sheet( diff --git a/packages/server/src/api/controllers/FinancialStatements/VendorBalanceSummary/index.ts b/packages/server/src/api/controllers/FinancialStatements/VendorBalanceSummary/index.ts index ade69cb62..f1e26a0ed 100644 --- a/packages/server/src/api/controllers/FinancialStatements/VendorBalanceSummary/index.ts +++ b/packages/server/src/api/controllers/FinancialStatements/VendorBalanceSummary/index.ts @@ -72,6 +72,7 @@ export default class VendorBalanceSummaryReportController extends BaseFinancialR ACCEPT_TYPE.APPLICATION_JSON_TABLE, ACCEPT_TYPE.APPLICATION_CSV, ACCEPT_TYPE.APPLICATION_XLSX, + ACCEPT_TYPE.APPLICATION_PDF, ]); // Retrieves the csv format. @@ -100,6 +101,17 @@ export default class VendorBalanceSummaryReportController extends BaseFinancialR filter ); return res.status(200).send(table); + // Retrieves the pdf format. + } else if (acceptType === ACCEPT_TYPE.APPLICATION_PDF) { + const pdfContent = await this.vendorBalanceSummaryApp.pdf( + tenantId, + filter + ); + res.set({ + 'Content-Type': 'application/pdf', + 'Content-Length': pdfContent.length, + }); + return res.send(pdfContent); // Retrieves the json format. } else { const sheet = await this.vendorBalanceSummaryApp.sheet( diff --git a/packages/server/src/interfaces/APAgingSummaryReport.ts b/packages/server/src/interfaces/APAgingSummaryReport.ts index 2d7a8a447..21ed036c7 100644 --- a/packages/server/src/interfaces/APAgingSummaryReport.ts +++ b/packages/server/src/interfaces/APAgingSummaryReport.ts @@ -5,6 +5,7 @@ import { IAgingSummaryContact, IAgingSummaryData, } from './AgingReport'; +import { IFinancialSheetCommonMeta } from './FinancialStatements'; import { IFinancialTable } from './Table'; export interface IAPAgingSummaryQuery extends IAgingSummaryQuery { @@ -23,17 +24,22 @@ export interface IAPAgingSummaryData extends IAgingSummaryData { export type IAPAgingSummaryColumns = IAgingPeriod[]; -export interface IARAgingSummaryMeta { - baseCurrency: string; - organizationName: string; +export interface IARAgingSummaryMeta extends IFinancialSheetCommonMeta { + formattedAsDate: string; } -export interface IAPAgingSummaryMeta { - baseCurrency: string; - organizationName: string; +export interface IAPAgingSummaryMeta extends IFinancialSheetCommonMeta { + formattedAsDate: string; } export interface IAPAgingSummaryTable extends IFinancialTable { query: IAPAgingSummaryQuery; meta: IAPAgingSummaryMeta; } + +export interface IAPAgingSummarySheet { + data: IAPAgingSummaryData; + meta: IAPAgingSummaryMeta; + query: IAPAgingSummaryQuery; + columns: any; +} diff --git a/packages/server/src/interfaces/ARAgingSummaryReport.ts b/packages/server/src/interfaces/ARAgingSummaryReport.ts index d42fc8f7f..b20753927 100644 --- a/packages/server/src/interfaces/ARAgingSummaryReport.ts +++ b/packages/server/src/interfaces/ARAgingSummaryReport.ts @@ -32,3 +32,11 @@ export interface IARAgingSummaryTable extends IFinancialTable { meta: IARAgingSummaryMeta; query: IARAgingSummaryQuery; } + +export interface IARAgingSummarySheet { + data: IARAgingSummaryData; + meta: IARAgingSummaryMeta; + query: IARAgingSummaryQuery; + columns: IARAgingSummaryColumns; +} + diff --git a/packages/server/src/interfaces/AgingReport.ts b/packages/server/src/interfaces/AgingReport.ts index c68b6b389..dc2a0dd1b 100644 --- a/packages/server/src/interfaces/AgingReport.ts +++ b/packages/server/src/interfaces/AgingReport.ts @@ -1,5 +1,7 @@ - -import { INumberFormatQuery } from './FinancialStatements'; +import { + IFinancialSheetCommonMeta, + INumberFormatQuery, +} from './FinancialStatements'; export interface IAgingPeriodTotal extends IAgingPeriod { total: IAgingAmount; @@ -42,3 +44,8 @@ export interface IAgingSummaryTotal { export interface IAgingSummaryData { total: IAgingSummaryTotal; } + +export interface IAgingSummaryMeta extends IFinancialSheetCommonMeta { + formattedAsDate: string; + formattedDateRange: string; +} diff --git a/packages/server/src/interfaces/BalanceSheet.ts b/packages/server/src/interfaces/BalanceSheet.ts index a74e48ee8..567cb8764 100644 --- a/packages/server/src/interfaces/BalanceSheet.ts +++ b/packages/server/src/interfaces/BalanceSheet.ts @@ -2,6 +2,7 @@ import { INumberFormatQuery, IFormatNumberSettings, IFinancialSheetBranchesQuery, + IFinancialSheetCommonMeta, } from './FinancialStatements'; import { IFinancialTable } from './Table'; @@ -63,10 +64,9 @@ export interface IBalanceSheetQuery extends IFinancialSheetBranchesQuery { } // Balance sheet meta. -export interface IBalanceSheetMeta { - isCostComputeRunning: boolean; - organizationName: string; - baseCurrency: string; +export interface IBalanceSheetMeta extends IFinancialSheetCommonMeta { + formattedAsDate: string; + formattedDateRange: string; } export interface IBalanceSheetFormatNumberSettings diff --git a/packages/server/src/interfaces/CashFlow.ts b/packages/server/src/interfaces/CashFlow.ts index 1a4a1a6a1..40cd50896 100644 --- a/packages/server/src/interfaces/CashFlow.ts +++ b/packages/server/src/interfaces/CashFlow.ts @@ -1,4 +1,7 @@ -import { INumberFormatQuery } from './FinancialStatements'; +import { + IFinancialSheetCommonMeta, + INumberFormatQuery, +} from './FinancialStatements'; import { IAccount } from './Account'; import { ILedger } from './Ledger'; import { IFinancialTable, ITableRow } from './Table'; @@ -79,8 +82,8 @@ export interface ICashFlowStatementAggregateSection export interface ICashFlowCashBeginningNode extends ICashFlowStatementCommonSection { - sectionType: ICashFlowStatementSectionType.CASH_AT_BEGINNING; - } + sectionType: ICashFlowStatementSectionType.CASH_AT_BEGINNING; +} export type ICashFlowStatementSection = | ICashFlowStatementAccountSection @@ -89,10 +92,10 @@ export type ICashFlowStatementSection = | ICashFlowStatementCommonSection; export interface ICashFlowStatementColumn {} -export interface ICashFlowStatementMeta { - isCostComputeRunning: boolean; - organizationName: string; - baseCurrency: string; +export interface ICashFlowStatementMeta extends IFinancialSheetCommonMeta { + formattedToDate: string; + formattedFromDate: string; + formattedDateRange: string; } export interface ICashFlowStatementDOO { diff --git a/packages/server/src/interfaces/CustomerBalanceSummary.ts b/packages/server/src/interfaces/CustomerBalanceSummary.ts index cf5b5900d..c55452d98 100644 --- a/packages/server/src/interfaces/CustomerBalanceSummary.ts +++ b/packages/server/src/interfaces/CustomerBalanceSummary.ts @@ -4,6 +4,7 @@ import { IContactBalanceSummaryPercentage, IContactBalanceSummaryTotal, } from './ContactBalanceSummary'; +import { IFinancialSheetCommonMeta } from './FinancialStatements'; import { IFinancialTable } from './Table'; export interface ICustomerBalanceSummaryQuery @@ -35,9 +36,15 @@ export interface ICustomerBalanceSummaryData { total: ICustomerBalanceSummaryTotal; } +export interface ICustomerBalanceSummaryMeta extends IFinancialSheetCommonMeta { + formattedAsDate: string; + formattedDateRange: string; +} + export interface ICustomerBalanceSummaryStatement { data: ICustomerBalanceSummaryData; query: ICustomerBalanceSummaryQuery; + meta: ICustomerBalanceSummaryMeta; } export interface ICustomerBalanceSummaryService { @@ -49,4 +56,5 @@ export interface ICustomerBalanceSummaryService { export interface ICustomerBalanceSummaryTable extends IFinancialTable { query: ICustomerBalanceSummaryQuery; + meta: ICustomerBalanceSummaryMeta; } diff --git a/packages/server/src/interfaces/FinancialStatements.ts b/packages/server/src/interfaces/FinancialStatements.ts index fb1d77452..abf2468c6 100644 --- a/packages/server/src/interfaces/FinancialStatements.ts +++ b/packages/server/src/interfaces/FinancialStatements.ts @@ -42,4 +42,13 @@ export enum ReportsAction { export interface IFinancialSheetBranchesQuery { branchesIds?: number[]; -} \ No newline at end of file +} + +export interface IFinancialSheetCommonMeta { + organizationName: string; + baseCurrency: string; + dateFormat: string; + isCostComputeRunning: boolean; + sheetName: string; + +} diff --git a/packages/server/src/interfaces/GeneralLedgerSheet.ts b/packages/server/src/interfaces/GeneralLedgerSheet.ts index 6b863a192..6de1bda3b 100644 --- a/packages/server/src/interfaces/GeneralLedgerSheet.ts +++ b/packages/server/src/interfaces/GeneralLedgerSheet.ts @@ -1,92 +1,90 @@ -import { IFinancialTable } from "./Table"; - +import { IFinancialSheetCommonMeta } from './FinancialStatements'; +import { IFinancialTable } from './Table'; export interface IGeneralLedgerSheetQuery { - fromDate: Date | string, - toDate: Date | string, - basis: string, + fromDate: Date | string; + toDate: Date | string; + basis: string; numberFormat: { - noCents: boolean, - divideOn1000: boolean, - }, - noneTransactions: boolean, - accountsIds: number[], + noCents: boolean; + divideOn1000: boolean; + }; + noneTransactions: boolean; + accountsIds: number[]; branchesIds?: number[]; -}; +} export interface IGeneralLedgerSheetAccountTransaction { - id: number, + id: number; - amount: number, - runningBalance: number, - credit: number, - debit: number, + amount: number; + runningBalance: number; + credit: number; + debit: number; - formattedAmount: string, - formattedCredit: string, - formattedDebit: string, - formattedRunningBalance: string, + formattedAmount: string; + formattedCredit: string; + formattedDebit: string; + formattedRunningBalance: string; - currencyCode: string, - note?: string, + currencyCode: string; + note?: string; - transactionType?: string, - transactionNumber: string, + transactionType?: string; + transactionNumber: string; - referenceId?: number, - referenceType?: string, + referenceId?: number; + referenceType?: string; - date: Date|string, + date: Date | string; dateFormatted: string; -}; +} export interface IGeneralLedgerSheetAccountBalance { - date: Date|string, - amount: number, - formattedAmount: string, - currencyCode: string, + date: Date | string; + amount: number; + formattedAmount: string; + currencyCode: string; } export interface IGeneralLedgerSheetAccount { - id: number, - name: string, - code: string, - index: number, - parentAccountId: number, - transactions: IGeneralLedgerSheetAccountTransaction[], - openingBalance: IGeneralLedgerSheetAccountBalance, - closingBalance: IGeneralLedgerSheetAccountBalance, + id: number; + name: string; + code: string; + index: number; + parentAccountId: number; + transactions: IGeneralLedgerSheetAccountTransaction[]; + openingBalance: IGeneralLedgerSheetAccountBalance; + closingBalance: IGeneralLedgerSheetAccountBalance; } export type IGeneralLedgerSheetData = IGeneralLedgerSheetAccount[]; export interface IAccountTransaction { - id: number, - index: number, - draft: boolean, - note: string, - accountId: number, - transactionType: string, - referenceType: string, - referenceId: number, - contactId: number, - contactType: string, - credit: number, - debit: number, - date: string|Date, - createdAt: string|Date, - updatedAt: string|Date, + id: number; + index: number; + draft: boolean; + note: string; + accountId: number; + transactionType: string; + referenceType: string; + referenceId: number; + contactId: number; + contactType: string; + credit: number; + debit: number; + date: string | Date; + createdAt: string | Date; + updatedAt: string | Date; } -export interface IGeneralLedgerMeta { - isCostComputeRunning: boolean, - organizationName: string, - baseCurrency: string, - fromDate: string; - toDate: string; -}; +export interface IGeneralLedgerMeta extends IFinancialSheetCommonMeta { + formattedFromDate: string; + formattedToDate: string; + formattedDateRange: string; +} export interface IGeneralLedgerTableData extends IFinancialTable { meta: IGeneralLedgerMeta; query: IGeneralLedgerSheetQuery; -} \ No newline at end of file +} diff --git a/packages/server/src/interfaces/IInventoryValuationSheet.ts b/packages/server/src/interfaces/IInventoryValuationSheet.ts index ab006d7b3..a5bd5d051 100644 --- a/packages/server/src/interfaces/IInventoryValuationSheet.ts +++ b/packages/server/src/interfaces/IInventoryValuationSheet.ts @@ -1,4 +1,7 @@ -import { INumberFormatQuery } from './FinancialStatements'; +import { + IFinancialSheetCommonMeta, + INumberFormatQuery, +} from './FinancialStatements'; import { IFinancialTable } from './Table'; export interface IInventoryValuationReportQuery { @@ -13,10 +16,10 @@ export interface IInventoryValuationReportQuery { branchesIds?: number[]; } -export interface IInventoryValuationSheetMeta { - organizationName: string; - baseCurrency: string; - isCostComputeRunning: boolean; +export interface IInventoryValuationSheetMeta + extends IFinancialSheetCommonMeta { + formattedAsDate: string; + formattedDateRange: string; } export interface IInventoryValuationItem { diff --git a/packages/server/src/interfaces/InventoryDetails.ts b/packages/server/src/interfaces/InventoryDetails.ts index 033ec269d..8da644540 100644 --- a/packages/server/src/interfaces/InventoryDetails.ts +++ b/packages/server/src/interfaces/InventoryDetails.ts @@ -1,4 +1,7 @@ -import { INumberFormatQuery } from './FinancialStatements'; +import { + IFinancialSheetCommonMeta, + INumberFormatQuery, +} from './FinancialStatements'; import { IFinancialTable } from './Table'; export interface IInventoryDetailsQuery { @@ -79,10 +82,10 @@ export type IInventoryDetailsNode = | IInventoryDetailsItemTransaction; export type IInventoryDetailsData = IInventoryDetailsItem[]; -export interface IInventoryItemDetailMeta { - isCostComputeRunning: boolean; - organizationName: string; - baseCurrency: string; +export interface IInventoryItemDetailMeta extends IFinancialSheetCommonMeta { + formattedFromDate: string; + formattedToDay: string; + formattedDateRange: string; } export interface IInvetoryItemDetailDOO { diff --git a/packages/server/src/interfaces/JournalReport.ts b/packages/server/src/interfaces/JournalReport.ts index c003cccf0..319bf526c 100644 --- a/packages/server/src/interfaces/JournalReport.ts +++ b/packages/server/src/interfaces/JournalReport.ts @@ -1,3 +1,4 @@ +import { IFinancialSheetCommonMeta } from './FinancialStatements'; import { IJournalEntry } from './Journal'; import { IFinancialTable } from './Table'; @@ -32,10 +33,10 @@ export interface IJournalReport { entries: IJournalReportEntriesGroup[]; } -export interface IJournalSheetMeta { - isCostComputeRunning: boolean; - organizationName: string; - baseCurrency: string; +export interface IJournalSheetMeta extends IFinancialSheetCommonMeta { + formattedDateRange: string; + formattedFromDate: string; + formattedToDate: string; } export interface IJournalTable extends IFinancialTable { diff --git a/packages/server/src/interfaces/ProfitLossSheet.ts b/packages/server/src/interfaces/ProfitLossSheet.ts index 944a0a950..64b787667 100644 --- a/packages/server/src/interfaces/ProfitLossSheet.ts +++ b/packages/server/src/interfaces/ProfitLossSheet.ts @@ -1,5 +1,6 @@ import { IFinancialSheetBranchesQuery, + IFinancialSheetCommonMeta, INumberFormatQuery, } from './FinancialStatements'; import { IFinancialTable } from './Table'; @@ -134,10 +135,10 @@ export type IProfitLossSheetNode = | IProfitLossSheetEquationNode | IProfitLossSheetAccountNode; -export interface IProfitLossSheetMeta { - isCostComputeRunning: boolean; - organizationName: string; - baseCurrency: string; +export interface IProfitLossSheetMeta extends IFinancialSheetCommonMeta{ + formattedDateRange: string; + formattedFromDate: string; + formattedToDate: string; } // ------------------------------------------------ diff --git a/packages/server/src/interfaces/PurchasesByItemsSheet.ts b/packages/server/src/interfaces/PurchasesByItemsSheet.ts index f08fb97af..fcd1ee8d9 100644 --- a/packages/server/src/interfaces/PurchasesByItemsSheet.ts +++ b/packages/server/src/interfaces/PurchasesByItemsSheet.ts @@ -1,4 +1,7 @@ -import { INumberFormatQuery } from './FinancialStatements'; +import { + IFinancialSheetCommonMeta, + INumberFormatQuery, +} from './FinancialStatements'; import { IFinancialTable } from './Table'; export interface IPurchasesByItemsReportQuery { @@ -10,9 +13,10 @@ export interface IPurchasesByItemsReportQuery { onlyActive: boolean; } -export interface IPurchasesByItemsSheetMeta { - organizationName: string; - baseCurrency: string; +export interface IPurchasesByItemsSheetMeta extends IFinancialSheetCommonMeta { + formattedFromDate: string; + formattedToDate: string; + formattedDateRange: string; } export interface IPurchasesByItemsItem { diff --git a/packages/server/src/interfaces/SalesByItemsSheet.ts b/packages/server/src/interfaces/SalesByItemsSheet.ts index 84f49960b..789ebae77 100644 --- a/packages/server/src/interfaces/SalesByItemsSheet.ts +++ b/packages/server/src/interfaces/SalesByItemsSheet.ts @@ -1,4 +1,7 @@ -import { INumberFormatQuery } from './FinancialStatements'; +import { + IFinancialSheetCommonMeta, + INumberFormatQuery, +} from './FinancialStatements'; import { IFinancialTable } from './Table'; export interface ISalesByItemsReportQuery { @@ -10,9 +13,10 @@ export interface ISalesByItemsReportQuery { onlyActive: boolean; } -export interface ISalesByItemsSheetMeta { - organizationName: string; - baseCurrency: string; +export interface ISalesByItemsSheetMeta extends IFinancialSheetCommonMeta { + formattedFromDate: string; + formattedToDate: string; + formattedDateRange: string; } export interface ISalesByItemsItem { @@ -51,4 +55,4 @@ export interface ISalesByItemsSheet { export interface ISalesByItemsTable extends IFinancialTable { query: ISalesByItemsReportQuery; meta: ISalesByItemsSheetMeta; -} \ No newline at end of file +} diff --git a/packages/server/src/interfaces/SalesTaxLiabilitySummary.ts b/packages/server/src/interfaces/SalesTaxLiabilitySummary.ts index 2fbc9f13d..b37d8a384 100644 --- a/packages/server/src/interfaces/SalesTaxLiabilitySummary.ts +++ b/packages/server/src/interfaces/SalesTaxLiabilitySummary.ts @@ -1,3 +1,4 @@ +import { IFinancialSheetCommonMeta } from "./FinancialStatements"; import { IFinancialTable } from "./Table"; export interface SalesTaxLiabilitySummaryQuery { @@ -47,9 +48,10 @@ export type SalesTaxLiabilitySummarySalesById = Record< { taxRateId: number; credit: number; debit: number } >; -export interface SalesTaxLiabilitySummaryMeta { - organizationName: string; - baseCurrency: string; +export interface SalesTaxLiabilitySummaryMeta extends IFinancialSheetCommonMeta { + formattedFromDate: string; + formattedToDate: string; + formattedDateRange: string; } export interface ISalesTaxLiabilitySummaryTable extends IFinancialTable { diff --git a/packages/server/src/interfaces/TransactionsByCustomers.ts b/packages/server/src/interfaces/TransactionsByCustomers.ts index fcfb01ea6..e47098b36 100644 --- a/packages/server/src/interfaces/TransactionsByCustomers.ts +++ b/packages/server/src/interfaces/TransactionsByCustomers.ts @@ -1,3 +1,4 @@ +import { IFinancialSheetCommonMeta } from './FinancialStatements'; import { IFinancialTable, ITableData } from './Table'; import { ITransactionsByContactsAmount, @@ -28,10 +29,12 @@ export type ITransactionsByCustomersData = ITransactionsByCustomersCustomer[]; export interface ITransactionsByCustomersStatement { data: ITransactionsByCustomersData; query: ITransactionsByCustomersFilter; + meta: ITransactionsByCustomersMeta; } export interface ITransactionsByCustomersTable extends IFinancialTable { query: ITransactionsByCustomersFilter; + meta: ITransactionsByCustomersMeta; } export interface ITransactionsByCustomersService { @@ -40,3 +43,9 @@ export interface ITransactionsByCustomersService { filter: ITransactionsByCustomersFilter ): Promise; } +export interface ITransactionsByCustomersMeta + extends IFinancialSheetCommonMeta { + formattedFromDate: string; + formattedToDate: string; + formattedDateRange: string; +} diff --git a/packages/server/src/interfaces/TransactionsByVendors.ts b/packages/server/src/interfaces/TransactionsByVendors.ts index ae129bc79..7a5b16013 100644 --- a/packages/server/src/interfaces/TransactionsByVendors.ts +++ b/packages/server/src/interfaces/TransactionsByVendors.ts @@ -1,3 +1,4 @@ +import { IFinancialSheetCommonMeta } from './FinancialStatements'; import { IFinancialTable } from './Table'; import { ITransactionsByContactsAmount, @@ -27,6 +28,8 @@ export type ITransactionsByVendorsData = ITransactionsByVendorsVendor[]; export interface ITransactionsByVendorsStatement { data: ITransactionsByVendorsData; + query: ITransactionsByVendorsFilter; + meta: ITransactionsByVendorMeta; } export interface ITransactionsByVendorsService { @@ -38,4 +41,10 @@ export interface ITransactionsByVendorsService { export interface ITransactionsByVendorTable extends IFinancialTable { query: ITransactionsByVendorsFilter; -} \ No newline at end of file + meta: ITransactionsByVendorMeta; +} +export interface ITransactionsByVendorMeta extends IFinancialSheetCommonMeta { + formattedFromDate: string; + formattedToDate: string; + formattedDateRange: string; +} diff --git a/packages/server/src/interfaces/TrialBalanceSheet.ts b/packages/server/src/interfaces/TrialBalanceSheet.ts index f423503ae..b6cd79736 100644 --- a/packages/server/src/interfaces/TrialBalanceSheet.ts +++ b/packages/server/src/interfaces/TrialBalanceSheet.ts @@ -1,4 +1,7 @@ -import { INumberFormatQuery } from './FinancialStatements'; +import { + IFinancialSheetCommonMeta, + INumberFormatQuery, +} from './FinancialStatements'; import { IFinancialTable } from './Table'; export interface ITrialBalanceSheetQuery { @@ -24,10 +27,10 @@ export interface ITrialBalanceTotal { formattedBalance: string; } -export interface ITrialBalanceSheetMeta { - isCostComputeRunning: boolean; - organizationName: string; - baseCurrency: string; +export interface ITrialBalanceSheetMeta extends IFinancialSheetCommonMeta { + formattedFromDate: string; + formattedToDate: string; + formattedDateRange: string; } export interface ITrialBalanceAccount extends ITrialBalanceTotal { diff --git a/packages/server/src/interfaces/VendorBalanceSummary.ts b/packages/server/src/interfaces/VendorBalanceSummary.ts index d214202df..5c603c51d 100644 --- a/packages/server/src/interfaces/VendorBalanceSummary.ts +++ b/packages/server/src/interfaces/VendorBalanceSummary.ts @@ -1,4 +1,7 @@ -import { INumberFormatQuery } from './FinancialStatements'; +import { + IFinancialSheetCommonMeta, + INumberFormatQuery, +} from './FinancialStatements'; import { IFinancialTable } from './Table'; export interface IVendorBalanceSummaryQuery { @@ -39,8 +42,9 @@ export interface IVendorBalanceSummaryData { export interface IVendorBalanceSummaryStatement { data: IVendorBalanceSummaryData; - columns: {}; query: IVendorBalanceSummaryQuery; + meta: IVendorBalanceSummaryMeta; + } export interface IVendorBalanceSummaryService { @@ -52,4 +56,9 @@ export interface IVendorBalanceSummaryService { export interface IVendorBalanceSummaryTable extends IFinancialTable { query: IVendorBalanceSummaryQuery; + meta: IVendorBalanceSummaryMeta; +} + +export interface IVendorBalanceSummaryMeta extends IFinancialSheetCommonMeta { + formattedAsDate: string; } diff --git a/packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryApplication.ts b/packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryApplication.ts index 73c08b2d8..52e6db251 100644 --- a/packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryApplication.ts +++ b/packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryApplication.ts @@ -3,6 +3,7 @@ import { APAgingSummaryExportInjectable } from './APAgingSummaryExportInjectable import { APAgingSummaryTableInjectable } from './APAgingSummaryTableInjectable'; import { IAPAgingSummaryQuery } from '@/interfaces'; import { APAgingSummaryService } from './APAgingSummaryService'; +import { APAgingSummaryPdfInjectable } from './APAgingSummaryPdfInjectable'; @Service() export class APAgingSummaryApplication { @@ -15,6 +16,9 @@ export class APAgingSummaryApplication { @Inject() private APAgingSummarySheet: APAgingSummaryService; + @Inject() + private APAgingSumaryPdf: APAgingSummaryPdfInjectable; + /** * Retrieve the A/P aging summary in sheet format. * @param {number} tenantId @@ -50,4 +54,14 @@ export class APAgingSummaryApplication { public xlsx(tenantId: number, query: IAPAgingSummaryQuery) { return this.APAgingSummaryExport.xlsx(tenantId, query); } + + /** + * Retrieves the A/P aging summary in pdf format. + * @param {number} tenantId + * @param {IAPAgingSummaryQuery} query + * @returns {Promise} + */ + public pdf(tenantId: number, query: IAPAgingSummaryQuery) { + return this.APAgingSumaryPdf.pdf(tenantId, query); + } } diff --git a/packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryMeta.ts b/packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryMeta.ts new file mode 100644 index 000000000..a32fe6457 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryMeta.ts @@ -0,0 +1,26 @@ +import { Inject, Service } from 'typedi'; +import { IAgingSummaryMeta, IAgingSummaryQuery } from '@/interfaces'; +import { AgingSummaryMeta } from './AgingSummaryMeta'; + +@Service() +export class APAgingSummaryMeta { + @Inject() + private agingSummaryMeta: AgingSummaryMeta; + + /** + * Retrieve the aging summary meta. + * @param {number} tenantId - + * @returns {IBalanceSheetMeta} + */ + public async meta( + tenantId: number, + query: IAgingSummaryQuery + ): Promise { + const commonMeta = await this.agingSummaryMeta.meta(tenantId, query); + + return { + ...commonMeta, + sheetName: 'A/P Aging Summary', + }; + } +} diff --git a/packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryPdfInjectable.ts b/packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryPdfInjectable.ts new file mode 100644 index 000000000..50ef588e8 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryPdfInjectable.ts @@ -0,0 +1,35 @@ +import { Inject, Service } from 'typedi'; +import { IAPAgingSummaryQuery } from '@/interfaces'; +import { TableSheetPdf } from '../TableSheetPdf'; +import { APAgingSummaryTableInjectable } from './APAgingSummaryTableInjectable'; +import { HtmlTableCss } from './_constants'; + +@Service() +export class APAgingSummaryPdfInjectable { + @Inject() + private APAgingSummaryTable: APAgingSummaryTableInjectable; + + @Inject() + private tableSheetPdf: TableSheetPdf; + + /** + * Converts the given A/P aging summary sheet table to pdf. + * @param {number} tenantId - Tenant ID. + * @param {IAPAgingSummaryQuery} query - Balance sheet query. + * @returns {Promise} + */ + public async pdf( + tenantId: number, + query: IAPAgingSummaryQuery + ): Promise { + const table = await this.APAgingSummaryTable.table(tenantId, query); + + return this.tableSheetPdf.convertToPdf( + tenantId, + table.table, + table.meta.sheetName, + table.meta.formattedAsDate, + HtmlTableCss + ); + } +} diff --git a/packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryService.ts b/packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryService.ts index fa3e6a2b3..49ee46448 100644 --- a/packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryService.ts +++ b/packages/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryService.ts @@ -1,18 +1,19 @@ import moment from 'moment'; import { Inject, Service } from 'typedi'; import { isEmpty } from 'lodash'; -import { IAPAgingSummaryQuery, IARAgingSummaryMeta } from '@/interfaces'; +import { IAPAgingSummaryQuery, IAPAgingSummarySheet } from '@/interfaces'; import TenancyService from '@/services/Tenancy/TenancyService'; import APAgingSummarySheet from './APAgingSummarySheet'; import { Tenant } from '@/system/models'; +import { APAgingSummaryMeta } from './APAgingSummaryMeta'; @Service() export class APAgingSummaryService { @Inject() - tenancy: TenancyService; + private tenancy: TenancyService; - @Inject('logger') - logger: any; + @Inject() + private APAgingSummaryMeta: APAgingSummaryMeta; /** * Default report query. @@ -35,35 +36,16 @@ export class APAgingSummaryService { }; } - /** - * Retrieve the balance sheet meta. - * @param {number} tenantId - - * @returns {IBalanceSheetMeta} - */ - reportMetadata(tenantId: number): IARAgingSummaryMeta { - const settings = this.tenancy.settings(tenantId); - - const organizationName = settings.get({ - group: 'organization', - key: 'name', - }); - const baseCurrency = settings.get({ - group: 'organization', - key: 'base_currency', - }); - - return { - organizationName, - baseCurrency, - }; - } - /** * Retrieve A/P aging summary report. * @param {number} tenantId - * @param {IAPAgingSummaryQuery} query - + * @returns {Promise} */ - async APAgingSummary(tenantId: number, query: IAPAgingSummaryQuery) { + public async APAgingSummary( + tenantId: number, + query: IAPAgingSummaryQuery + ): Promise { const { Bill } = this.tenancy.models(tenantId); const { vendorRepository } = this.tenancy.repositories(tenantId); @@ -111,11 +93,14 @@ export class APAgingSummaryService { const data = APAgingSummaryReport.reportData(); const columns = APAgingSummaryReport.reportColumns(); + // Retrieve the aging summary report meta. + const meta = await this.APAgingSummaryMeta.meta(tenantId, filter); + return { data, columns, query: filter, - meta: this.reportMetadata(tenantId), + meta, }; } } diff --git a/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryApplication.ts b/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryApplication.ts index d3282ca4b..f24932f13 100644 --- a/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryApplication.ts +++ b/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryApplication.ts @@ -3,6 +3,7 @@ import { IARAgingSummaryQuery } from '@/interfaces'; import { ARAgingSummaryTableInjectable } from './ARAgingSummaryTableInjectable'; import { ARAgingSummaryExportInjectable } from './ARAgingSummaryExportInjectable'; import ARAgingSummaryService from './ARAgingSummaryService'; +import { ARAgingSummaryPdfInjectable } from './ARAgingSummaryPdfInjectable'; @Service() export class ARAgingSummaryApplication { @@ -15,6 +16,9 @@ export class ARAgingSummaryApplication { @Inject() private ARAgingSummarySheet: ARAgingSummaryService; + @Inject() + private ARAgingSummaryPdf: ARAgingSummaryPdfInjectable; + /** * Retrieve the A/R aging summary sheet. * @param {number} tenantId @@ -50,4 +54,14 @@ export class ARAgingSummaryApplication { public csv(tenantId: number, query: IARAgingSummaryQuery) { return this.ARAgingSummaryExport.csv(tenantId, query); } + + /** + * Retrieves the A/R aging summary in pdf format. + * @param {number} tenantId + * @param {IARAgingSummaryQuery} query + * @returns {Promise} + */ + public pdf(tenantId: number, query: IARAgingSummaryQuery) { + return this.ARAgingSummaryPdf.pdf(tenantId, query); + } } diff --git a/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryMeta.ts b/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryMeta.ts new file mode 100644 index 000000000..dce2cb9d0 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryMeta.ts @@ -0,0 +1,26 @@ +import { Inject, Service } from 'typedi'; +import { IAgingSummaryMeta, IAgingSummaryQuery } from '@/interfaces'; +import { AgingSummaryMeta } from './AgingSummaryMeta'; + +@Service() +export class ARAgingSummaryMeta { + @Inject() + private agingSummaryMeta: AgingSummaryMeta; + + /** + * Retrieve the aging summary meta. + * @param {number} tenantId - + * @returns {IBalanceSheetMeta} + */ + public async meta( + tenantId: number, + query: IAgingSummaryQuery + ): Promise { + const commonMeta = await this.agingSummaryMeta.meta(tenantId, query); + + return { + ...commonMeta, + sheetName: 'A/R Aging Summary', + }; + } +} diff --git a/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryPdfInjectable.ts b/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryPdfInjectable.ts new file mode 100644 index 000000000..a3b75f6d3 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryPdfInjectable.ts @@ -0,0 +1,35 @@ +import { Inject, Service } from 'typedi'; +import { IARAgingSummaryQuery } from '@/interfaces'; +import { TableSheetPdf } from '../TableSheetPdf'; +import { ARAgingSummaryTableInjectable } from './ARAgingSummaryTableInjectable'; +import { HtmlTableCss } from './_constants'; + +@Service() +export class ARAgingSummaryPdfInjectable { + @Inject() + private ARAgingSummaryTable: ARAgingSummaryTableInjectable; + + @Inject() + private tableSheetPdf: TableSheetPdf; + + /** + * Converts the given balance sheet table to pdf. + * @param {number} tenantId - Tenant ID. + * @param {IBalanceSheetQuery} query - Balance sheet query. + * @returns {Promise} + */ + public async pdf( + tenantId: number, + query: IARAgingSummaryQuery + ): Promise { + const table = await this.ARAgingSummaryTable.table(tenantId, query); + + return this.tableSheetPdf.convertToPdf( + tenantId, + table.table, + table.meta.sheetName, + table.meta.formattedDateRange, + HtmlTableCss + ); + } +} diff --git a/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryService.ts b/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryService.ts index e13dfc276..d52709027 100644 --- a/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryService.ts +++ b/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryService.ts @@ -1,18 +1,19 @@ import moment from 'moment'; import { Inject, Service } from 'typedi'; import { isEmpty } from 'lodash'; -import { IARAgingSummaryQuery, IARAgingSummaryMeta } from '@/interfaces'; +import { IARAgingSummaryQuery } from '@/interfaces'; import TenancyService from '@/services/Tenancy/TenancyService'; import ARAgingSummarySheet from './ARAgingSummarySheet'; import { Tenant } from '@/system/models'; +import { ARAgingSummaryMeta } from './ARAgingSummaryMeta'; @Service() export default class ARAgingSummaryService { @Inject() - tenancy: TenancyService; + private tenancy: TenancyService; - @Inject('logger') - logger: any; + @Inject() + private ARAgingSummaryMeta: ARAgingSummaryMeta; /** * Default report query. @@ -35,29 +36,6 @@ export default class ARAgingSummaryService { }; } - /** - * Retrieve the balance sheet meta. - * @param {number} tenantId - - * @returns {IBalanceSheetMeta} - */ - reportMetadata(tenantId: number): IARAgingSummaryMeta { - const settings = this.tenancy.settings(tenantId); - - const organizationName = settings.get({ - group: 'organization', - key: 'name', - }); - const baseCurrency = settings.get({ - group: 'organization', - key: 'base_currency', - }); - - return { - organizationName, - baseCurrency, - }; - } - /** * Retrieve A/R aging summary report. * @param {number} tenantId - Tenant id. @@ -110,11 +88,14 @@ export default class ARAgingSummaryService { const data = ARAgingSummaryReport.reportData(); const columns = ARAgingSummaryReport.reportColumns(); + // Retrieve the aging summary report meta. + const meta = await this.ARAgingSummaryMeta.meta(tenantId, filter); + return { data, columns, query: filter, - meta: this.reportMetadata(tenantId), + meta, }; } } diff --git a/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryTableInjectable.ts b/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryTableInjectable.ts index 10ac9ee8c..6f702cfe4 100644 --- a/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryTableInjectable.ts +++ b/packages/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryTableInjectable.ts @@ -19,6 +19,7 @@ export class ARAgingSummaryTableInjectable { query: IARAgingSummaryQuery ): Promise { const report = await this.ARAgingSummarySheet.ARAgingSummary( + tenantId, query ); diff --git a/packages/server/src/services/FinancialStatements/AgingSummary/AgingSummaryMeta.ts b/packages/server/src/services/FinancialStatements/AgingSummary/AgingSummaryMeta.ts new file mode 100644 index 000000000..5d3599997 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/AgingSummary/AgingSummaryMeta.ts @@ -0,0 +1,30 @@ +import { Inject } from 'typedi'; +import { FinancialSheetMeta } from '../FinancialSheetMeta'; +import { IAgingSummaryMeta, IAgingSummaryQuery } from '@/interfaces'; +import moment from 'moment'; + +export class AgingSummaryMeta { + @Inject() + private financialSheetMeta: FinancialSheetMeta; + + /** + * Retrieve the aging summary meta. + * @param {number} tenantId - + * @returns {IBalanceSheetMeta} + */ + public async meta( + tenantId: number, + query: IAgingSummaryQuery + ): Promise { + const commonMeta = await this.financialSheetMeta.meta(tenantId); + const formattedAsDate = moment(query.asDate).format('YYYY/MM/DD'); + const formattedDateRange = `As ${formattedAsDate}`; + + return { + ...commonMeta, + sheetName: 'A/P Aging Summary', + formattedAsDate, + formattedDateRange, + }; + } +} diff --git a/packages/server/src/services/FinancialStatements/AgingSummary/_constants.ts b/packages/server/src/services/FinancialStatements/AgingSummary/_constants.ts index 961f0b7ed..4f68704cb 100644 --- a/packages/server/src/services/FinancialStatements/AgingSummary/_constants.ts +++ b/packages/server/src/services/FinancialStatements/AgingSummary/_constants.ts @@ -2,3 +2,11 @@ export enum AgingSummaryRowType { Contact = 'contact', Total = 'total', } + +export const HtmlTableCss = ` +table tr.row-type--total td{ + font-weight: 500; + border-top: 1px solid #bbb; + border-bottom: 3px double #333; +} +`; diff --git a/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetApplication.ts b/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetApplication.ts index 01ab77bfe..0c965a5f5 100644 --- a/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetApplication.ts +++ b/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetApplication.ts @@ -54,4 +54,14 @@ export class BalanceSheetApplication { public csv(tenantId: number, query: IBalanceSheetQuery): Promise { return this.balanceSheetExport.csv(tenantId, query); } + + /** + * Retrieves the balance sheet in pdf format. + * @param {number} tenantId + * @param {IBalanceSheetQuery} query + * @returns {Promise} + */ + public pdf(tenantId: number, query: IBalanceSheetQuery) { + return this.balanceSheetExport.pdf(tenantId, query); + } } diff --git a/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetExportInjectable.ts b/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetExportInjectable.ts index 2c43d5f80..9198d8536 100644 --- a/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetExportInjectable.ts +++ b/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetExportInjectable.ts @@ -2,12 +2,16 @@ import { Inject, Service } from 'typedi'; import { BalanceSheetTableInjectable } from './BalanceSheetTableInjectable'; import { TableSheet } from '@/lib/Xlsx/TableSheet'; import { IBalanceSheetQuery } from '@/interfaces'; +import { BalanceSheetPdfInjectable } from './BalanceSheetPdfInjectable'; @Service() export class BalanceSheetExportInjectable { @Inject() private balanceSheetTable: BalanceSheetTableInjectable; + @Inject() + private balanceSheetPdf: BalanceSheetPdfInjectable; + /** * Retrieves the trial balance sheet in XLSX format. * @param {number} tenantId @@ -40,4 +44,17 @@ export class BalanceSheetExportInjectable { return tableCsv; } + + /** + * Retrieves the balance sheet in pdf format. + * @param {number} tenantId + * @param {IBalanceSheetQuery} query + * @returns {Promise} + */ + public async pdf( + tenantId: number, + query: IBalanceSheetQuery + ): Promise { + return this.balanceSheetPdf.pdf(tenantId, query); + } } diff --git a/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetInjectable.ts b/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetInjectable.ts index 02e136ca1..5e171110b 100644 --- a/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetInjectable.ts +++ b/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetInjectable.ts @@ -4,15 +4,12 @@ import { IBalanceSheetStatementService, IBalanceSheetQuery, IBalanceSheetStatement, - IBalanceSheetMeta, } from '@/interfaces'; import TenancyService from '@/services/Tenancy/TenancyService'; -import Journal from '@/services/Accounting/JournalPoster'; import BalanceSheetStatement from './BalanceSheet'; -import InventoryService from '@/services/Inventory/Inventory'; -import { parseBoolean } from 'utils'; import { Tenant } from '@/system/models'; import BalanceSheetRepository from './BalanceSheetRepository'; +import { BalanceSheetMetaInjectable } from './BalanceSheetMeta'; @Service() export default class BalanceSheetStatementService @@ -22,7 +19,7 @@ export default class BalanceSheetStatementService private tenancy: TenancyService; @Inject() - private inventoryService: InventoryService; + private balanceSheetMeta: BalanceSheetMetaInjectable; /** * Defaults balance sheet filter query. @@ -62,33 +59,6 @@ export default class BalanceSheetStatementService }; } - /** - * Retrieve the balance sheet meta. - * @param {number} tenantId - - * @returns {IBalanceSheetMeta} - */ - private reportMetadata(tenantId: number): IBalanceSheetMeta { - 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, - }; - } - /** * Retrieve balance sheet statement. * @param {number} tenantId @@ -112,6 +82,7 @@ export default class BalanceSheetStatementService const models = this.tenancy.models(tenantId); const balanceSheetRepo = new BalanceSheetRepository(models, filter); + // Loads all resources. await balanceSheetRepo.asyncInitialize(); // Balance sheet report instance. @@ -122,12 +93,15 @@ export default class BalanceSheetStatementService i18n ); // Balance sheet data. - const balanceSheetData = balanceSheetInstanace.reportData(); + const data = balanceSheetInstanace.reportData(); + + // Balance sheet meta. + const meta = await this.balanceSheetMeta.meta(tenantId, filter); return { - data: balanceSheetData, query: filter, - meta: this.reportMetadata(tenantId), + data, + meta, }; } } diff --git a/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetMeta.ts b/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetMeta.ts new file mode 100644 index 000000000..c7a3e87c0 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetMeta.ts @@ -0,0 +1,32 @@ +import { Inject, Service } from 'typedi'; +import { FinancialSheetMeta } from '../FinancialSheetMeta'; +import { IBalanceSheetMeta, IBalanceSheetQuery } from '@/interfaces'; +import moment from 'moment'; + +@Service() +export class BalanceSheetMetaInjectable { + @Inject() + private financialSheetMeta: FinancialSheetMeta; + + /** + * Retrieve the balance sheet meta. + * @param {number} tenantId - + * @returns {IBalanceSheetMeta} + */ + public async meta( + tenantId: number, + query: IBalanceSheetQuery + ): Promise { + const commonMeta = await this.financialSheetMeta.meta(tenantId); + const formattedAsDate = moment(query.toDate).format('YYYY/MM/DD'); + const formattedDateRange = `As ${formattedAsDate}`; + const sheetName = 'Balance Sheet Statement'; + + return { + ...commonMeta, + sheetName, + formattedAsDate, + formattedDateRange, + }; + } +} diff --git a/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetPdfInjectable.ts b/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetPdfInjectable.ts new file mode 100644 index 000000000..4cbb43e8a --- /dev/null +++ b/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetPdfInjectable.ts @@ -0,0 +1,35 @@ +import { Inject, Service } from 'typedi'; +import { IBalanceSheetQuery } from '@/interfaces'; +import { BalanceSheetTableInjectable } from './BalanceSheetTableInjectable'; +import { TableSheetPdf } from '../TableSheetPdf'; +import { HtmlTableCustomCss } from './constants'; + +@Service() +export class BalanceSheetPdfInjectable { + @Inject() + private balanceSheetTable: BalanceSheetTableInjectable; + + @Inject() + private tableSheetPdf: TableSheetPdf; + + /** + * Converts the given balance sheet table to pdf. + * @param {number} tenantId - Tenant ID. + * @param {IBalanceSheetQuery} query - Balance sheet query. + * @returns {Promise} + */ + public async pdf( + tenantId: number, + query: IBalanceSheetQuery + ): Promise { + const table = await this.balanceSheetTable.table(tenantId, query); + + return this.tableSheetPdf.convertToPdf( + tenantId, + table.table, + table.meta.sheetName, + table.meta.formattedDateRange, + HtmlTableCustomCss + ); + } +} diff --git a/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetTable.ts b/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetTable.ts index 349b1a8f4..8e6a1f92b 100644 --- a/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetTable.ts +++ b/packages/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetTable.ts @@ -41,15 +41,16 @@ export default class BalanceSheetTable extends R.compose( BalanceSheetBase )(FinancialSheet) { /** - * @param {} + * Balance sheet data. + * @param {IBalanceSheetStatementData} */ - reportData: IBalanceSheetStatementData; + private reportData: IBalanceSheetStatementData; /** * Balance sheet query. - * @parma {} + * @parma {BalanceSheetQuery} */ - query: BalanceSheetQuery; + private query: BalanceSheetQuery; /** * Constructor method. @@ -215,13 +216,13 @@ export default class BalanceSheetTable extends R.compose( /** * Retrieves the total children columns. - * @returns {ITableColumn[]} + * @returns {ITableColumn[]} */ private totalColumnChildren = (): ITableColumn[] => { return R.compose( R.unless( R.isEmpty, - R.concat([{ key: 'total', Label: this.i18n.__('balance_sheet.total') }]) + R.concat([{ key: 'total', label: this.i18n.__('balance_sheet.total') }]) ), R.concat(this.percentageColumns()), R.concat(this.getPreviousYearColumns()), diff --git a/packages/server/src/services/FinancialStatements/BalanceSheet/constants.ts b/packages/server/src/services/FinancialStatements/BalanceSheet/constants.ts index 8862408a1..2081d2859 100644 --- a/packages/server/src/services/FinancialStatements/BalanceSheet/constants.ts +++ b/packages/server/src/services/FinancialStatements/BalanceSheet/constants.ts @@ -12,3 +12,53 @@ export enum IROW_TYPE { NET_INCOME = 'NET_INCOME', TOTAL = 'TOTAL', } + +export const HtmlTableCustomCss = ` +table tr.row-type--total td { + font-weight: 600; + border-top: 1px solid #bbb; + color: #000; +} +table tr.row-type--total.row-id--assets td, +table tr.row-type--total.row-id--liability-equity td { + border-bottom: 3px double #000; +} +table .column--name, +table .cell--name { + width: 400px; +} + +table .column--total { + width: 25%; +} + +table td.cell--total, +table td.cell--previous_year, +table td.cell--previous_year_change, +table td.cell--previous_year_percentage, + +table td.cell--previous_period, +table td.cell--previous_period_change, +table td.cell--previous_period_percentage, + +table td.cell--percentage_of_row, +table td.cell--percentage_of_column, +table td[class*="cell--date-range"] { + text-align: right; +} + +table .column--total, +table .column--previous_year, +table .column--previous_year_change, +table .column--previous_year_percentage, + +table .column--previous_period, +table .column--previous_period_change, +table .column--previous_period_percentage, + +table .column--percentage_of_row, +table .column--percentage_of_column, +table [class*="column--date-range"] { + text-align: right; +} +`; diff --git a/packages/server/src/services/FinancialStatements/CashFlow/CashFlowService.ts b/packages/server/src/services/FinancialStatements/CashFlow/CashFlowService.ts index 09fdf91ca..201a31be4 100644 --- a/packages/server/src/services/FinancialStatements/CashFlow/CashFlowService.ts +++ b/packages/server/src/services/FinancialStatements/CashFlow/CashFlowService.ts @@ -8,7 +8,7 @@ import { ICashFlowStatementQuery, ICashFlowStatementDOO, IAccountTransaction, - ICashFlowStatementMeta + ICashFlowStatementMeta, } from '@/interfaces'; import CashFlowStatement from './CashFlow'; import Ledger from '@/services/Accounting/Ledger'; @@ -16,6 +16,7 @@ import CashFlowRepository from './CashFlowRepository'; import InventoryService from '@/services/Inventory/Inventory'; import { parseBoolean } from 'utils'; import { Tenant } from '@/system/models'; +import { CashflowSheetMeta } from './CashflowSheetMeta'; @Service() export default class CashFlowStatementService @@ -31,6 +32,9 @@ export default class CashFlowStatementService @Inject() inventoryService: InventoryService; + @Inject() + private cashflowSheetMeta: CashflowSheetMeta; + /** * Defaults balance sheet filter query. * @return {IBalanceSheetQuery} @@ -138,38 +142,13 @@ export default class CashFlowStatementService tenant.metadata.baseCurrency, i18n ); + // Retrieve the cashflow sheet meta. + const meta = await this.cashflowSheetMeta.meta(tenantId, filter); return { data: cashFlowInstance.reportData(), query: filter, - meta: this.reportMetadata(tenantId), + meta, }; } - - /** - * Retrieve the balance sheet meta. - * @param {number} tenantId - - * @returns {ICashFlowStatementMeta} - */ - private reportMetadata(tenantId: number): ICashFlowStatementMeta { - 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/CashFlow/CashFlowTable.ts b/packages/server/src/services/FinancialStatements/CashFlow/CashFlowTable.ts index b3470e1a4..7b49a685c 100644 --- a/packages/server/src/services/FinancialStatements/CashFlow/CashFlowTable.ts +++ b/packages/server/src/services/FinancialStatements/CashFlow/CashFlowTable.ts @@ -76,7 +76,7 @@ export default class CashFlowTable implements ICashFlowTable { */ private commonColumns = () => { return R.compose( - R.concat([{ key: 'label', accessor: 'label' }]), + R.concat([{ key: 'name', accessor: 'label' }]), R.when( R.always(this.isDisplayColumnsBy(DISPLAY_COLUMNS_BY.DATE_PERIODS)), R.concat(this.datePeriodsColumnsAccessors()) diff --git a/packages/server/src/services/FinancialStatements/CashFlow/CashflowSheetApplication.ts b/packages/server/src/services/FinancialStatements/CashFlow/CashflowSheetApplication.ts index 0fd8b7357..72a587f52 100644 --- a/packages/server/src/services/FinancialStatements/CashFlow/CashflowSheetApplication.ts +++ b/packages/server/src/services/FinancialStatements/CashFlow/CashflowSheetApplication.ts @@ -3,6 +3,7 @@ import { CashflowExportInjectable } from './CashflowExportInjectable'; import { ICashFlowStatementQuery } from '@/interfaces'; import CashFlowStatementService from './CashFlowService'; import { CashflowTableInjectable } from './CashflowTableInjectable'; +import { CashflowTablePdfInjectable } from './CashflowTablePdfInjectable'; @Service() export class CashflowSheetApplication { @@ -15,6 +16,9 @@ export class CashflowSheetApplication { @Inject() private cashflowTable: CashflowTableInjectable; + @Inject() + private cashflowPdf: CashflowTablePdfInjectable; + /** * Retrieves the cashflow sheet * @param {number} tenantId @@ -55,4 +59,17 @@ export class CashflowSheetApplication { ): Promise { return this.cashflowExport.csv(tenantId, query); } + + /** + * Retrieves the cashflow sheet in pdf format. + * @param {number} tenantId + * @param {ICashFlowStatementQuery} query + * @returns {Promise} + */ + public async pdf( + tenantId: number, + query: ICashFlowStatementQuery + ): Promise { + return this.cashflowPdf.pdf(tenantId, query); + } } diff --git a/packages/server/src/services/FinancialStatements/CashFlow/CashflowSheetMeta.ts b/packages/server/src/services/FinancialStatements/CashFlow/CashflowSheetMeta.ts new file mode 100644 index 000000000..3a1dd40dc --- /dev/null +++ b/packages/server/src/services/FinancialStatements/CashFlow/CashflowSheetMeta.ts @@ -0,0 +1,36 @@ +import { Inject, Service } from 'typedi'; +import moment from 'moment'; +import { ICashFlowStatementMeta, ICashFlowStatementQuery } from '@/interfaces'; +import { FinancialSheetMeta } from '../FinancialSheetMeta'; + +@Service() +export class CashflowSheetMeta { + @Inject() + private financialSheetMeta: FinancialSheetMeta; + + /** + * CAshflow sheet meta. + * @param {number} tenantId + * @param {ICashFlowStatementQuery} query + * @returns {Promise} + */ + public async meta( + tenantId: number, + query: ICashFlowStatementQuery + ): Promise { + const meta = await this.financialSheetMeta.meta(tenantId); + const formattedToDate = moment(query.toDate).format('YYYY/MM/DD'); + const formattedFromDate = moment(query.fromDate).format('YYYY/MM/DD'); + const formattedDateRange = `From ${formattedFromDate} | To ${formattedToDate}`; + + const sheetName = 'Statement of Cash Flow'; + + return { + ...meta, + sheetName, + formattedToDate, + formattedFromDate, + formattedDateRange, + }; + } +} diff --git a/packages/server/src/services/FinancialStatements/CashFlow/CashflowTablePdfInjectable.ts b/packages/server/src/services/FinancialStatements/CashFlow/CashflowTablePdfInjectable.ts new file mode 100644 index 000000000..be7cb5382 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/CashFlow/CashflowTablePdfInjectable.ts @@ -0,0 +1,34 @@ +import { Inject } from 'typedi'; +import { CashflowTableInjectable } from './CashflowTableInjectable'; +import { TableSheetPdf } from '../TableSheetPdf'; +import { ICashFlowStatementQuery } from '@/interfaces'; +import { HtmlTableCustomCss } from './constants'; + +export class CashflowTablePdfInjectable { + @Inject() + private cashflowTable: CashflowTableInjectable; + + @Inject() + private tableSheetPdf: TableSheetPdf; + + /** + * Converts the given cashflow sheet table to pdf. + * @param {number} tenantId - Tenant ID. + * @param {IBalanceSheetQuery} query - Balance sheet query. + * @returns {Promise} + */ + public async pdf( + tenantId: number, + query: ICashFlowStatementQuery + ): Promise { + const table = await this.cashflowTable.table(tenantId, query); + + return this.tableSheetPdf.convertToPdf( + tenantId, + table.table, + table.meta.sheetName, + table.meta.formattedDateRange, + HtmlTableCustomCss + ); + } +} diff --git a/packages/server/src/services/FinancialStatements/CashFlow/constants.ts b/packages/server/src/services/FinancialStatements/CashFlow/constants.ts index 58a92ec19..f3f1858fb 100644 --- a/packages/server/src/services/FinancialStatements/CashFlow/constants.ts +++ b/packages/server/src/services/FinancialStatements/CashFlow/constants.ts @@ -1,8 +1,33 @@ - - export const DISPLAY_COLUMNS_BY = { DATE_PERIODS: 'date_periods', TOTAL: 'total', }; -export const MAP_CONFIG = { childrenPath: 'children', pathFormat: 'array' }; \ No newline at end of file +export const MAP_CONFIG = { childrenPath: 'children', pathFormat: 'array' }; +export const HtmlTableCustomCss = ` +table tr.row-type--accounts td { + border-top: 1px solid #bbb; +} +table tr.row-id--cash-end-period td { + border-bottom: 3px double #333; +} +table tr.row-type--total { + font-weight: 600; +} +table tr.row-type--total td { + color: #000; +} +table tr.row-type--total:not(:first-child) td { + border-top: 1px solid #bbb; +} +table .column--name, +table .cell--name { + width: 400px; +} +table .column--total, +table .cell--total, +table [class*="column--date-range"], +table [class*="cell--date-range"] { + text-align: right; +} +`; diff --git a/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryApplication.ts b/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryApplication.ts index 964cd91a9..78c532d08 100644 --- a/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryApplication.ts +++ b/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryApplication.ts @@ -3,6 +3,7 @@ import { CustomerBalanceSummaryExportInjectable } from './CustomerBalanceSummary import { CustomerBalanceSummaryTableInjectable } from './CustomerBalanceSummaryTableInjectable'; import { ICustomerBalanceSummaryQuery } from '@/interfaces'; import { CustomerBalanceSummaryService } from './CustomerBalanceSummaryService'; +import { CustomerBalanceSummaryPdf } from './CustomerBalanceSummaryPdf'; @Service() export class CustomerBalanceSummaryApplication { @@ -14,6 +15,9 @@ export class CustomerBalanceSummaryApplication { @Inject() private customerBalanceSummarySheet: CustomerBalanceSummaryService; + + @Inject() + private customerBalanceSummaryPdf: CustomerBalanceSummaryPdf; /** * Retrieves the customer balance sheet in json format. @@ -57,4 +61,14 @@ export class CustomerBalanceSummaryApplication { public csv(tenantId: number, query: ICustomerBalanceSummaryQuery) { return this.customerBalanceSummaryExport.csv(tenantId, query); } + + /** + * Retrieves the customer balance sheet in PDF format. + * @param {number} tenantId + * @param {ICustomerBalanceSummaryQuery} query + * @returns {Promise} + */ + public pdf(tenantId: number, query: ICustomerBalanceSummaryQuery) { + return this.customerBalanceSummaryPdf.pdf(tenantId, query); + } } diff --git a/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryMeta.ts b/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryMeta.ts new file mode 100644 index 000000000..7639e8c4f --- /dev/null +++ b/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryMeta.ts @@ -0,0 +1,35 @@ +import moment from 'moment'; +import { Inject, Service } from 'typedi'; +import { + ICustomerBalanceSummaryMeta, + ICustomerBalanceSummaryQuery, +} from '@/interfaces'; +import { FinancialSheetMeta } from '../FinancialSheetMeta'; + +@Service() +export class CustomerBalanceSummaryMeta { + @Inject() + private financialSheetMeta: FinancialSheetMeta; + + /** + * Retrieves the customer balance summary meta. + * @param {number} tenantId + * @param {ICustomerBalanceSummaryQuery} query + * @returns {Promise} + */ + async meta( + tenantId: number, + query: ICustomerBalanceSummaryQuery + ): Promise { + const commonMeta = await this.financialSheetMeta.meta(tenantId); + const formattedAsDate = moment(query.asDate).format('YYYY/MM/DD'); + const formattedDateRange = `As ${formattedAsDate}`; + + return { + ...commonMeta, + sheetName: 'Customer Balance Summary', + formattedAsDate, + formattedDateRange, + }; + } +} diff --git a/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryPdf.ts b/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryPdf.ts new file mode 100644 index 000000000..38d36fd48 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryPdf.ts @@ -0,0 +1,36 @@ +import { Inject, Service } from 'typedi'; +import { ICustomerBalanceSummaryQuery } from '@/interfaces'; + +import { TableSheetPdf } from '../TableSheetPdf'; +import { CustomerBalanceSummaryTableInjectable } from './CustomerBalanceSummaryTableInjectable'; +import { HtmlTableCustomCss } from './constants'; + +@Service() +export class CustomerBalanceSummaryPdf { + @Inject() + private customerBalanceSummaryTable: CustomerBalanceSummaryTableInjectable; + + @Inject() + private tableSheetPdf: TableSheetPdf; + + /** + * Converts the given customer balance summary sheet table to pdf. + * @param {number} tenantId - Tenant ID. + * @param {IAPAgingSummaryQuery} query - Balance sheet query. + * @returns {Promise} + */ + public async pdf( + tenantId: number, + query: ICustomerBalanceSummaryQuery + ): Promise { + const table = await this.customerBalanceSummaryTable.table(tenantId, query); + + return this.tableSheetPdf.convertToPdf( + tenantId, + table.table, + table.meta.sheetName, + table.meta.formattedDateRange, + HtmlTableCustomCss + ); + } +} diff --git a/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryService.ts b/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryService.ts index 78afc3bb2..38edc5174 100644 --- a/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryService.ts +++ b/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryService.ts @@ -1,4 +1,4 @@ -import { Inject } from 'typedi'; +import { Inject, Service } from 'typedi'; import moment from 'moment'; import * as R from 'ramda'; import { @@ -12,13 +12,18 @@ import { CustomerBalanceSummaryReport } from './CustomerBalanceSummary'; import Ledger from '@/services/Accounting/Ledger'; import CustomerBalanceSummaryRepository from './CustomerBalanceSummaryRepository'; import { Tenant } from '@/system/models'; +import { CustomerBalanceSummaryMeta } from './CustomerBalanceSummaryMeta'; +@Service() export class CustomerBalanceSummaryService implements ICustomerBalanceSummaryService { @Inject() private reportRepository: CustomerBalanceSummaryRepository; + @Inject() + private customerBalanceSummaryMeta: CustomerBalanceSummaryMeta; + /** * Defaults balance sheet filter query. * @return {ICustomerBalanceSummaryQuery} @@ -96,10 +101,13 @@ export class CustomerBalanceSummaryService filter, tenant.metadata.baseCurrency ); + // Retrieve the customer balance summary meta. + const meta = await this.customerBalanceSummaryMeta.meta(tenantId, filter); return { data: report.reportData(), query: filter, + meta, }; } } diff --git a/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryTableInjectable.ts b/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryTableInjectable.ts index 56450d4ca..edf4e5ea1 100644 --- a/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryTableInjectable.ts +++ b/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/CustomerBalanceSummaryTableInjectable.ts @@ -25,8 +25,9 @@ export class CustomerBalanceSummaryTableInjectable { tenantId: number, filter: ICustomerBalanceSummaryQuery ): Promise { + const i18n = this.tenancy.i18n(tenantId); - const { data, query } = + const { data, query, meta } = await this.customerBalanceSummaryService.customerBalanceSummary( tenantId, filter @@ -39,6 +40,7 @@ export class CustomerBalanceSummaryTableInjectable { rows: tableRows.tableRows(), }, query, + meta, }; } } diff --git a/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/constants.ts b/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/constants.ts new file mode 100644 index 000000000..50c3aac24 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/CustomerBalanceSummary/constants.ts @@ -0,0 +1,6 @@ +export const HtmlTableCustomCss = ` +table tr.row-type--total td { + font-weight: 600; + border-top: 1px solid #bbb; + border-bottom: 3px double #333; +}`; diff --git a/packages/server/src/services/FinancialStatements/FinancialSheetMeta.ts b/packages/server/src/services/FinancialStatements/FinancialSheetMeta.ts new file mode 100644 index 000000000..130f3caaa --- /dev/null +++ b/packages/server/src/services/FinancialStatements/FinancialSheetMeta.ts @@ -0,0 +1,34 @@ +import { TenantMetadata } from '@/system/models'; +import { Inject, Service } from 'typedi'; +import InventoryService from '../Inventory/Inventory'; +import { IFinancialSheetCommonMeta } from '@/interfaces'; + +@Service() +export class FinancialSheetMeta { + @Inject() + private inventoryService: InventoryService; + + /** + * Retrieves the common meta data of the financial sheet. + * @param {number} tenantId + * @returns {Promise} + */ + async meta(tenantId: number): Promise { + const tenantMetadata = await TenantMetadata.query().findOne({ tenantId }); + + const organizationName = tenantMetadata.name; + const baseCurrency = tenantMetadata.baseCurrency; + const dateFormat = tenantMetadata.dateFormat; + + const isCostComputeRunning = + this.inventoryService.isItemsCostComputeRunning(tenantId); + + return { + organizationName, + baseCurrency, + dateFormat, + isCostComputeRunning, + sheetName: '', + }; + } +} diff --git a/packages/server/src/services/FinancialStatements/FinancialSheetStructure.ts b/packages/server/src/services/FinancialStatements/FinancialSheetStructure.ts index 722635d9a..5e2fbba55 100644 --- a/packages/server/src/services/FinancialStatements/FinancialSheetStructure.ts +++ b/packages/server/src/services/FinancialStatements/FinancialSheetStructure.ts @@ -61,14 +61,14 @@ export const FinancialSheetStructure = (Base: Class) => }); }; - findNodeDeep = (nodes, callback) => { + public findNodeDeep = (nodes, callback) => { return findValueDeep(nodes, callback, { childrenPath: 'children', pathFormat: 'array', }); }; - mapAccNodesDeep = (nodes, callback) => { + public mapAccNodesDeep = (nodes, callback) => { return reduceDeep( nodes, (acc, value, key, parentValue, context) => { @@ -97,11 +97,11 @@ export const FinancialSheetStructure = (Base: Class) => }); }; - getTotalOfChildrenNodes = (node) => { + public getTotalOfChildrenNodes = (node) => { return this.getTotalOfNodes(node.children); }; - getTotalOfNodes = (nodes) => { + public getTotalOfNodes = (nodes) => { return sumBy(nodes, 'total.amount'); }; }; diff --git a/packages/server/src/services/FinancialStatements/GeneralLedger/GeneralLedgerApplication.ts b/packages/server/src/services/FinancialStatements/GeneralLedger/GeneralLedgerApplication.ts index 924b0da8c..6257e34d8 100644 --- a/packages/server/src/services/FinancialStatements/GeneralLedger/GeneralLedgerApplication.ts +++ b/packages/server/src/services/FinancialStatements/GeneralLedger/GeneralLedgerApplication.ts @@ -6,6 +6,7 @@ import { import { GeneralLedgerTableInjectable } from './GeneralLedgerTableInjectable'; import { GeneralLedgerExportInjectable } from './GeneralLedgerExport'; import { GeneralLedgerService } from './GeneralLedgerService'; +import { GeneralLedgerPdf } from './GeneralLedgerPdf'; export class GeneralLedgerApplication { @Inject() @@ -17,6 +18,9 @@ export class GeneralLedgerApplication { @Inject() private GLSheet: GeneralLedgerService; + @Inject() + private GLPdf: GeneralLedgerPdf; + /** * Retrieves the G/L sheet in json format. * @param {number} tenantId @@ -63,4 +67,17 @@ export class GeneralLedgerApplication { ): Promise { return this.GLExport.csv(tenantId, query); } + + /** + * Retrieves the G/L sheet in pdf format. + * @param {number} tenantId + * @param {IGeneralLedgerSheetQuery} query + * @returns {Promise} + */ + public pdf( + tenantId: number, + query: IGeneralLedgerSheetQuery + ): Promise { + return this.GLPdf.pdf(tenantId, query); + } } diff --git a/packages/server/src/services/FinancialStatements/GeneralLedger/GeneralLedgerMeta.ts b/packages/server/src/services/FinancialStatements/GeneralLedger/GeneralLedgerMeta.ts new file mode 100644 index 000000000..00f312654 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/GeneralLedger/GeneralLedgerMeta.ts @@ -0,0 +1,33 @@ +import { IGeneralLedgerMeta, IGeneralLedgerSheetQuery } from '@/interfaces'; +import moment from 'moment'; +import { Inject, Service } from 'typedi'; +import { FinancialSheetMeta } from '../FinancialSheetMeta'; + +@Service() +export class GeneralLedgerMeta { + @Inject() + private financialSheetMeta: FinancialSheetMeta; + + /** + * Retrieve the balance sheet meta. + * @param {number} tenantId - + * @returns {IBalanceSheetMeta} + */ + public async meta( + tenantId: number, + query: IGeneralLedgerSheetQuery + ): Promise { + const commonMeta = await this.financialSheetMeta.meta(tenantId); + const formattedToDate = moment(query.toDate).format('YYYY/MM/DD'); + const formattedFromDate = moment(query.fromDate).format('YYYY/MM/DD'); + const formattedDateRange = `From ${formattedFromDate} | To ${formattedToDate}`; + + return { + ...commonMeta, + sheetName: 'Balance Sheet', + formattedFromDate, + formattedToDate, + formattedDateRange, + }; + } +} diff --git a/packages/server/src/services/FinancialStatements/GeneralLedger/GeneralLedgerPdf.ts b/packages/server/src/services/FinancialStatements/GeneralLedger/GeneralLedgerPdf.ts new file mode 100644 index 000000000..efe082709 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/GeneralLedger/GeneralLedgerPdf.ts @@ -0,0 +1,35 @@ +import { Inject, Service } from 'typedi'; +import { TableSheetPdf } from '../TableSheetPdf'; +import { GeneralLedgerTableInjectable } from './GeneralLedgerTableInjectable'; +import { IGeneralLedgerSheetQuery } from '@/interfaces'; +import { HtmlTableCustomCss } from './constants'; + +@Service() +export class GeneralLedgerPdf { + @Inject() + private generalLedgerTable: GeneralLedgerTableInjectable; + + @Inject() + private tableSheetPdf: TableSheetPdf; + + /** + * Converts the general ledger sheet table to pdf. + * @param {number} tenantId - Tenant ID. + * @param {IGeneralLedgerSheetQuery} query - + * @returns {Promise} + */ + public async pdf( + tenantId: number, + query: IGeneralLedgerSheetQuery + ): Promise { + const table = await this.generalLedgerTable.table(tenantId, query); + + return this.tableSheetPdf.convertToPdf( + tenantId, + table.table, + table.meta.sheetName, + table.meta.formattedDateRange, + HtmlTableCustomCss + ); + } +} diff --git a/packages/server/src/services/FinancialStatements/GeneralLedger/GeneralLedgerService.ts b/packages/server/src/services/FinancialStatements/GeneralLedger/GeneralLedgerService.ts index 100239e39..53451d2d8 100644 --- a/packages/server/src/services/FinancialStatements/GeneralLedger/GeneralLedgerService.ts +++ b/packages/server/src/services/FinancialStatements/GeneralLedger/GeneralLedgerService.ts @@ -6,9 +6,9 @@ import { IGeneralLedgerSheetQuery, IGeneralLedgerMeta } from '@/interfaces'; import TenancyService from '@/services/Tenancy/TenancyService'; import Journal from '@/services/Accounting/JournalPoster'; import GeneralLedgerSheet from '@/services/FinancialStatements/GeneralLedger/GeneralLedger'; -import InventoryService from '@/services/Inventory/Inventory'; -import { transformToMap, parseBoolean } from 'utils'; +import { transformToMap } from 'utils'; import { Tenant } from '@/system/models'; +import { GeneralLedgerMeta } from './GeneralLedgerMeta'; const ERRORS = { ACCOUNTS_NOT_FOUND: 'ACCOUNTS_NOT_FOUND', @@ -17,13 +17,10 @@ const ERRORS = { @Service() export class GeneralLedgerService { @Inject() - tenancy: TenancyService; + private tenancy: TenancyService; @Inject() - inventoryService: InventoryService; - - @Inject('logger') - logger: any; + private generalLedgerMeta: GeneralLedgerMeta; /** * Defaults general ledger report filter query. @@ -59,40 +56,8 @@ export class GeneralLedgerService { } } - /** - * Retrieve the balance sheet meta. - * @param {number} tenantId - - * @returns {IGeneralLedgerMeta} - */ - reportMetadata(tenantId: number, filter): IGeneralLedgerMeta { - 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', - }); - const fromDate = moment(filter.fromDate).format('YYYY MMM DD'); - const toDate = moment(filter.toDate).format('YYYY MMM DD'); - - return { - isCostComputeRunning: parseBoolean(isCostComputeRunning, false), - organizationName, - baseCurrency, - fromDate, - toDate - }; - } - /** * Retrieve general ledger report statement. - * ---------- * @param {number} tenantId * @param {IGeneralLedgerSheetQuery} query * @return {IGeneralLedgerStatement} @@ -103,13 +68,10 @@ export class GeneralLedgerService { ): Promise<{ data: any; query: IGeneralLedgerSheetQuery; - meta: IGeneralLedgerMeta + meta: IGeneralLedgerMeta; }> { - const { - accountRepository, - transactionsRepository, - contactRepository - } = this.tenancy.repositories(tenantId); + const { accountRepository, transactionsRepository, contactRepository } = + this.tenancy.repositories(tenantId); const i18n = this.tenancy.i18n(tenantId); @@ -133,13 +95,13 @@ export class GeneralLedgerService { const transactions = await transactionsRepository.journal({ fromDate: filter.fromDate, toDate: filter.toDate, - branchesIds: filter.branchesIds + branchesIds: filter.branchesIds, }); // Retreive opening balance credit/debit sumation. const openingBalanceTrans = await transactionsRepository.journal({ toDate: moment(filter.fromDate).subtract(1, 'day'), sumationCreditDebit: true, - branchesIds: filter.branchesIds + branchesIds: filter.branchesIds, }); // Transform array transactions to journal collection. const transactionsJournal = Journal.fromTransactions( @@ -147,7 +109,7 @@ export class GeneralLedgerService { tenantId, accountsGraph ); - // Accounts opening transactions. + // Accounts opening transactions. const openingTransJournal = Journal.fromTransactions( openingBalanceTrans, tenantId, @@ -167,10 +129,13 @@ export class GeneralLedgerService { // Retrieve general ledger report data. const reportData = generalLedgerInstance.reportData(); + // Retrieve general ledger report metadata. + const meta = await this.generalLedgerMeta.meta(tenantId, filter); + return { data: reportData, query: filter, - meta: this.reportMetadata(tenantId, filter), + meta, }; } } diff --git a/packages/server/src/services/FinancialStatements/GeneralLedger/constants.ts b/packages/server/src/services/FinancialStatements/GeneralLedger/constants.ts new file mode 100644 index 000000000..26b5ceb8c --- /dev/null +++ b/packages/server/src/services/FinancialStatements/GeneralLedger/constants.ts @@ -0,0 +1,13 @@ +export const HtmlTableCustomCss = ` +table tr:last-child td { + border-bottom: 1px solid #ececec; +} +table tr.row-type--account td, +table tr.row-type--opening-balance td, +table tr.row-type--closing-balance td{ + font-weight: 600; +} +table tr.row-type--closing-balance td { + border-bottom: 1px solid #ececec; +} +`; diff --git a/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsApplication.ts b/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsApplication.ts index a2639094e..50cbd2a2f 100644 --- a/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsApplication.ts +++ b/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsApplication.ts @@ -6,6 +6,7 @@ import { Inject, Service } from 'typedi'; import { InventoryDetailsExportInjectable } from './InventoryDetailsExportInjectable'; import { InventoryDetailsTableInjectable } from './InventoryDetailsTableInjectable'; import { InventoryDetailsService } from './InventoryDetailsService'; +import { InventoryDetailsTablePdf } from './InventoryDetailsTablePdf'; @Service() export class InventortyDetailsApplication { @@ -18,6 +19,9 @@ export class InventortyDetailsApplication { @Inject() private inventoryDetails: InventoryDetailsService; + @Inject() + private inventoryDetailsPdf: InventoryDetailsTablePdf; + /** * Retrieves the inventory details report in sheet format. * @param {number} tenantId @@ -63,4 +67,14 @@ export class InventortyDetailsApplication { public csv(tenantId: number, query: IInventoryDetailsQuery): Promise { return this.inventoryDetailsExport.csv(tenantId, query); } + + /** + * Retrieves the inventory details report in PDF format. + * @param {number} tenantId + * @param {IInventoryDetailsQuery} query + * @returns {Promise} + */ + public pdf(tenantId: number, query: IInventoryDetailsQuery) { + return this.inventoryDetailsPdf.pdf(tenantId, query); + } } diff --git a/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsMeta.ts b/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsMeta.ts new file mode 100644 index 000000000..578954833 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsMeta.ts @@ -0,0 +1,35 @@ +import moment from 'moment'; +import { Inject, Service } from 'typedi'; +import { FinancialSheetMeta } from '../FinancialSheetMeta'; +import { IInventoryDetailsQuery, IInventoryItemDetailMeta } from '@/interfaces'; + +@Service() +export class InventoryDetailsMetaInjectable { + @Inject() + private financialSheetMeta: FinancialSheetMeta; + + /** + * Retrieve the inventoy details meta. + * @param {number} tenantId - + * @returns {IBalanceSheetMeta} + */ + public async meta( + tenantId: number, + query: IInventoryDetailsQuery + ): Promise { + const commonMeta = await this.financialSheetMeta.meta(tenantId); + const formattedFromDate = moment(query.fromDate).format('YYYY/MM/DD'); + const formattedToDay = moment(query.toDate).format('YYYY/MM/DD'); + const formattedDateRange = `From ${formattedFromDate} | To ${formattedToDay}`; + + const sheetName = 'Inventory Item Details'; + + return { + ...commonMeta, + sheetName, + formattedFromDate, + formattedToDay, + formattedDateRange, + }; + } +} diff --git a/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsService.ts b/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsService.ts index d74137753..e9b6614d6 100644 --- a/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsService.ts +++ b/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsService.ts @@ -1,17 +1,12 @@ import moment from 'moment'; import { Service, Inject } from 'typedi'; -import { - IInventoryDetailsQuery, - IInvetoryItemDetailDOO, - IInventoryItemDetailMeta, -} from '@/interfaces'; +import { IInventoryDetailsQuery, IInvetoryItemDetailDOO } from '@/interfaces'; import TenancyService from '@/services/Tenancy/TenancyService'; import { InventoryDetails } from './InventoryDetails'; import FinancialSheet from '../FinancialSheet'; import InventoryDetailsRepository from './InventoryDetailsRepository'; -import InventoryService from '@/services/Inventory/Inventory'; -import { parseBoolean } from 'utils'; import { Tenant } from '@/system/models'; +import { InventoryDetailsMetaInjectable } from './InventoryDetailsMeta'; @Service() export class InventoryDetailsService extends FinancialSheet { @@ -22,7 +17,7 @@ export class InventoryDetailsService extends FinancialSheet { private reportRepo: InventoryDetailsRepository; @Inject() - private inventoryService: InventoryService; + private inventoryDetailsMeta: InventoryDetailsMetaInjectable; /** * Defaults balance sheet filter query. @@ -46,33 +41,6 @@ export class InventoryDetailsService extends FinancialSheet { }; } - /** - * Retrieve the balance sheet meta. - * @param {number} tenantId - - * @returns {IInventoryItemDetailMeta} - */ - private reportMetadata(tenantId: number): IInventoryItemDetailMeta { - 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, - }; - } - /** * Retrieve the inventory details report data. * @param {number} tenantId - @@ -115,11 +83,12 @@ export class InventoryDetailsService extends FinancialSheet { tenant.metadata.baseCurrency, i18n ); + const meta = await this.inventoryDetailsMeta.meta(tenantId, query); return { data: inventoryDetailsInstance.reportData(), query: filter, - meta: this.reportMetadata(tenantId), + meta, }; } } diff --git a/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsTablePdf.ts b/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsTablePdf.ts new file mode 100644 index 000000000..b14b11c80 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/InventoryDetails/InventoryDetailsTablePdf.ts @@ -0,0 +1,35 @@ +import { Inject, Service } from 'typedi'; +import { InventoryDetailsTableInjectable } from './InventoryDetailsTableInjectable'; +import { TableSheetPdf } from '../TableSheetPdf'; +import { IInventoryDetailsQuery } from '@/interfaces'; +import { HtmlTableCustomCss } from './constant'; + +@Service() +export class InventoryDetailsTablePdf { + @Inject() + private inventoryDetailsTable: InventoryDetailsTableInjectable; + + @Inject() + private tableSheetPdf: TableSheetPdf; + + /** + * Converts the given inventory details sheet table to pdf. + * @param {number} tenantId - Tenant ID. + * @param {IBalanceSheetQuery} query - Balance sheet query. + * @returns {Promise} + */ + public async pdf( + tenantId: number, + query: IInventoryDetailsQuery + ): Promise { + const table = await this.inventoryDetailsTable.table(tenantId, query); + + return this.tableSheetPdf.convertToPdf( + tenantId, + table.table, + table.meta.sheetName, + table.meta.formattedDateRange, + HtmlTableCustomCss + ); + } +} diff --git a/packages/server/src/services/FinancialStatements/InventoryDetails/constant.ts b/packages/server/src/services/FinancialStatements/InventoryDetails/constant.ts new file mode 100644 index 000000000..eeb199236 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/InventoryDetails/constant.ts @@ -0,0 +1,7 @@ +export const HtmlTableCustomCss = ` +table tr.row-type--item td, +table tr.row-type--opening-entry td, +table tr.row-type--closing-entry td{ + font-weight: 500; +} +`; diff --git a/packages/server/src/services/FinancialStatements/InventoryValuationSheet/InventoryValuationSheetApplication.ts b/packages/server/src/services/FinancialStatements/InventoryValuationSheet/InventoryValuationSheetApplication.ts index 43406b0d8..7c4a65967 100644 --- a/packages/server/src/services/FinancialStatements/InventoryValuationSheet/InventoryValuationSheetApplication.ts +++ b/packages/server/src/services/FinancialStatements/InventoryValuationSheet/InventoryValuationSheetApplication.ts @@ -7,6 +7,7 @@ import { Inject, Service } from 'typedi'; import { InventoryValuationSheetService } from './InventoryValuationSheetService'; import { InventoryValuationSheetTableInjectable } from './InventoryValuationSheetTableInjectable'; import { InventoryValuationSheetExportable } from './InventoryValuationSheetExportable'; +import { InventoryValuationSheetPdf } from './InventoryValuationSheetPdf'; @Service() export class InventoryValuationSheetApplication { @@ -19,6 +20,9 @@ export class InventoryValuationSheetApplication { @Inject() private inventoryValuationExport: InventoryValuationSheetExportable; + @Inject() + private inventoryValuationPdf: InventoryValuationSheetPdf; + /** * Retrieves the inventory valuation json format. * @param {number} tenantId @@ -73,4 +77,17 @@ export class InventoryValuationSheetApplication { ): Promise { return this.inventoryValuationExport.csv(tenantId, query); } + + /** + * Retrieves the inventory valuation pdf format. + * @param {number} tenantId + * @param {IInventoryValuationReportQuery} query + * @returns {Promise} + */ + public pdf( + tenantId: number, + query: IInventoryValuationReportQuery + ): Promise { + return this.inventoryValuationPdf.pdf(tenantId, query); + } } diff --git a/packages/server/src/services/FinancialStatements/InventoryValuationSheet/InventoryValuationSheetMeta.ts b/packages/server/src/services/FinancialStatements/InventoryValuationSheet/InventoryValuationSheetMeta.ts new file mode 100644 index 000000000..822253342 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/InventoryValuationSheet/InventoryValuationSheetMeta.ts @@ -0,0 +1,33 @@ + + +import { Inject, Service } from 'typedi'; +import { FinancialSheetMeta } from '../FinancialSheetMeta'; +import { IBalanceSheetMeta, IBalanceSheetQuery, IInventoryValuationReportQuery } from '@/interfaces'; +import moment from 'moment'; + +@Service() +export class InventoryValuationMetaInjectable { + @Inject() + private financialSheetMeta: FinancialSheetMeta; + + /** + * Retrieve the balance sheet meta. + * @param {number} tenantId - + * @returns {IBalanceSheetMeta} + */ + public async meta( + tenantId: number, + query: IInventoryValuationReportQuery + ): Promise { + const commonMeta = await this.financialSheetMeta.meta(tenantId); + const formattedAsDate = moment(query.asDate).format('YYYY/MM/DD'); + const formattedDateRange = `As ${formattedAsDate}`; + + return { + ...commonMeta, + sheetName: 'Inventory Valuation Sheet', + formattedAsDate, + formattedDateRange, + }; + } +} diff --git a/packages/server/src/services/FinancialStatements/InventoryValuationSheet/InventoryValuationSheetPdf.ts b/packages/server/src/services/FinancialStatements/InventoryValuationSheet/InventoryValuationSheetPdf.ts new file mode 100644 index 000000000..449cec9cc --- /dev/null +++ b/packages/server/src/services/FinancialStatements/InventoryValuationSheet/InventoryValuationSheetPdf.ts @@ -0,0 +1,36 @@ +import { Inject, Service } from "typedi"; +import { InventoryValuationSheetTableInjectable } from "./InventoryValuationSheetTableInjectable"; +import { TableSheetPdf } from "../TableSheetPdf"; +import { IInventoryValuationReportQuery } from "@/interfaces"; +import { HtmlTableCustomCss } from "./_constants"; + + +@Service() +export class InventoryValuationSheetPdf { + @Inject() + private inventoryValuationTable: InventoryValuationSheetTableInjectable; + + @Inject() + private tableSheetPdf: TableSheetPdf; + + /** + * Converts the given balance sheet table to pdf. + * @param {number} tenantId - Tenant ID. + * @param {IBalanceSheetQuery} query - Balance sheet query. + * @returns {Promise} + */ + public async pdf( + tenantId: number, + query: IInventoryValuationReportQuery + ): Promise { + const table = await this.inventoryValuationTable.table(tenantId, query); + + return this.tableSheetPdf.convertToPdf( + tenantId, + table.table, + table.meta.sheetName, + table.meta.formattedDateRange, + HtmlTableCustomCss + ); + } +} \ No newline at end of file diff --git a/packages/server/src/services/FinancialStatements/InventoryValuationSheet/InventoryValuationSheetService.ts b/packages/server/src/services/FinancialStatements/InventoryValuationSheet/InventoryValuationSheetService.ts index 7351522e9..4da85b21d 100644 --- a/packages/server/src/services/FinancialStatements/InventoryValuationSheet/InventoryValuationSheetService.ts +++ b/packages/server/src/services/FinancialStatements/InventoryValuationSheet/InventoryValuationSheetService.ts @@ -10,6 +10,7 @@ import TenancyService from '@/services/Tenancy/TenancyService'; import { InventoryValuationSheet } from './InventoryValuationSheet'; import InventoryService from '@/services/Inventory/Inventory'; import { Tenant } from '@/system/models'; +import { InventoryValuationMetaInjectable } from './InventoryValuationSheetMeta'; @Service() export class InventoryValuationSheetService { @@ -22,6 +23,9 @@ export class InventoryValuationSheetService { @Inject() inventoryService: InventoryService; + @Inject() + private inventoryValuationMeta: InventoryValuationMetaInjectable; + /** * Defaults balance sheet filter query. * @return {IBalanceSheetQuery} @@ -46,33 +50,6 @@ export class InventoryValuationSheetService { }; } - /** - * Retrieve the balance sheet meta. - * @param {number} tenantId - - * @returns {IBalanceSheetMeta} - */ - reportMetadata(tenantId: number): IInventoryValuationSheetMeta { - 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 { - organizationName, - baseCurrency, - isCostComputeRunning, - }; - } - /** * Inventory valuation sheet. * @param {number} tenantId - Tenant id. @@ -136,10 +113,13 @@ export class InventoryValuationSheetService { // Retrieve the inventory valuation report data. const inventoryValuationData = inventoryValuationInstance.reportData(); + // Retrieves the inventorty valuation meta. + const meta = await this.inventoryValuationMeta.meta(tenantId, filter); + return { data: inventoryValuationData, query: filter, - meta: this.reportMetadata(tenantId), + meta, }; } } diff --git a/packages/server/src/services/FinancialStatements/InventoryValuationSheet/_constants.ts b/packages/server/src/services/FinancialStatements/InventoryValuationSheet/_constants.ts index a4154f92f..f41136b6f 100644 --- a/packages/server/src/services/FinancialStatements/InventoryValuationSheet/_constants.ts +++ b/packages/server/src/services/FinancialStatements/InventoryValuationSheet/_constants.ts @@ -2,3 +2,11 @@ export enum ROW_TYPE { ITEM = 'ITEM', TOTAL = 'TOTAL', } + +export const HtmlTableCustomCss = ` +table tr.row-type--total td { + border-top: 1px solid #bbb; + font-weight: 600; + border-bottom: 3px double #000; +} +`; diff --git a/packages/server/src/services/FinancialStatements/JournalSheet/JournalSheetApplication.ts b/packages/server/src/services/FinancialStatements/JournalSheet/JournalSheetApplication.ts index 4c403ff58..8d3f5d614 100644 --- a/packages/server/src/services/FinancialStatements/JournalSheet/JournalSheetApplication.ts +++ b/packages/server/src/services/FinancialStatements/JournalSheet/JournalSheetApplication.ts @@ -3,6 +3,7 @@ import { JournalSheetService } from './JournalSheetService'; import { JournalSheetTableInjectable } from './JournalSheetTableInjectable'; import { IJournalReportQuery, IJournalTable } from '@/interfaces'; import { JournalSheetExportInjectable } from './JournalSheetExport'; +import { JournalSheetPdfInjectable } from './JournalSheetPdfInjectable'; export class JournalSheetApplication { @Inject() @@ -14,6 +15,9 @@ export class JournalSheetApplication { @Inject() private journalExport: JournalSheetExportInjectable; + @Inject() + private journalPdf: JournalSheetPdfInjectable; + /** * Retrieves the journal sheet. * @param {number} tenantId @@ -56,4 +60,14 @@ export class JournalSheetApplication { public csv(tenantId: number, query: IJournalReportQuery) { return this.journalExport.csv(tenantId, query); } + + /** + * Retrieves the journal sheet in pdf format. + * @param {number} tenantId + * @param {IJournalReportQuery} query + * @returns {Promise} + */ + public pdf(tenantId: number, query: IJournalReportQuery) { + return this.journalPdf.pdf(tenantId, query); + } } diff --git a/packages/server/src/services/FinancialStatements/JournalSheet/JournalSheetMeta.ts b/packages/server/src/services/FinancialStatements/JournalSheet/JournalSheetMeta.ts new file mode 100644 index 000000000..5980e1e70 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/JournalSheet/JournalSheetMeta.ts @@ -0,0 +1,34 @@ +import { Service, Inject } from 'typedi'; +import { FinancialSheetMeta } from '../FinancialSheetMeta'; +import moment from 'moment'; +import { IJournalReportQuery, IJournalSheetMeta } from '@/interfaces'; + +@Service() +export class JournalSheetMeta { + @Inject() + private financialSheetMeta: FinancialSheetMeta; + + /** + * Retrieves the journal sheet meta. + * @param {number} tenantId + * @param {IJournalReportQuery} query + * @returns {Promise} + */ + public async meta( + tenantId: number, + query: IJournalReportQuery + ): Promise { + const common = await this.financialSheetMeta.meta(tenantId); + const formattedToDate = moment(query.toDate).format('YYYY/MM/DD'); + const formattedFromDate = moment(query.fromDate).format('YYYY/MM/DD'); + const formattedDateRange = `From ${formattedFromDate} | To ${formattedToDate}`; + + return { + ...common, + formattedDateRange, + formattedFromDate, + formattedToDate, + }; + } +} + diff --git a/packages/server/src/services/FinancialStatements/JournalSheet/JournalSheetPdfInjectable.ts b/packages/server/src/services/FinancialStatements/JournalSheet/JournalSheetPdfInjectable.ts new file mode 100644 index 000000000..6606d6705 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/JournalSheet/JournalSheetPdfInjectable.ts @@ -0,0 +1,35 @@ +import { IJournalReportQuery } from '@/interfaces'; +import { TableSheetPdf } from '../TableSheetPdf'; +import { JournalSheetTableInjectable } from './JournalSheetTableInjectable'; +import { Inject, Service } from 'typedi'; +import { HtmlTableCustomCss } from './constant'; + +@Service() +export class JournalSheetPdfInjectable { + @Inject() + private journalSheetTable: JournalSheetTableInjectable; + + @Inject() + private tableSheetPdf: TableSheetPdf; + + /** + * Converts the given journal sheet table to pdf. + * @param {number} tenantId - Tenant ID. + * @param {IBalanceSheetQuery} query - Balance sheet query. + * @returns {Promise} + */ + public async pdf( + tenantId: number, + query: IJournalReportQuery + ): Promise { + const table = await this.journalSheetTable.table(tenantId, query); + + return this.tableSheetPdf.convertToPdf( + tenantId, + table.table, + table.meta.sheetName, + table.meta.formattedDateRange, + HtmlTableCustomCss + ); + } +} diff --git a/packages/server/src/services/FinancialStatements/JournalSheet/JournalSheetService.ts b/packages/server/src/services/FinancialStatements/JournalSheet/JournalSheetService.ts index 69a319ff3..90027c3a1 100644 --- a/packages/server/src/services/FinancialStatements/JournalSheet/JournalSheetService.ts +++ b/packages/server/src/services/FinancialStatements/JournalSheet/JournalSheetService.ts @@ -1,17 +1,12 @@ import { Service, Inject } from 'typedi'; import moment from 'moment'; -import { - IJournalReportQuery, - IJournalSheet, - IJournalSheetMeta, - IJournalTableData, -} from '@/interfaces'; +import { IJournalReportQuery, IJournalSheet } from '@/interfaces'; import JournalSheet from './JournalSheet'; import TenancyService from '@/services/Tenancy/TenancyService'; import Journal from '@/services/Accounting/JournalPoster'; -import InventoryService from '@/services/Inventory/Inventory'; import { Tenant } from '@/system/models'; -import { parseBoolean, transformToMap } from 'utils'; +import { transformToMap } from 'utils'; +import { JournalSheetMeta } from './JournalSheetMeta'; @Service() export class JournalSheetService { @@ -19,7 +14,7 @@ export class JournalSheetService { private tenancy: TenancyService; @Inject() - private inventoryService: InventoryService; + private journalSheetMeta: JournalSheetMeta; /** * Default journal sheet filter queyr. @@ -38,33 +33,6 @@ export class JournalSheetService { }; } - /** - * Retrieve the balance sheet meta. - * @param {number} tenantId - - * @returns {IBalanceSheetMeta} - */ - reportMetadata(tenantId: number): IJournalSheetMeta { - 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, - }; - } - /** * Journal sheet. * @param {number} tenantId @@ -130,10 +98,13 @@ export class JournalSheetService { // Retrieve journal report columns. const journalSheetData = journalSheetInstance.reportData(); + // Retrieve the journal sheet meta. + const meta = await this.journalSheetMeta.meta(tenantId, filter); + return { data: journalSheetData, query: filter, - meta: this.reportMetadata(tenantId), + meta, }; } } diff --git a/packages/server/src/services/FinancialStatements/JournalSheet/constant.ts b/packages/server/src/services/FinancialStatements/JournalSheet/constant.ts new file mode 100644 index 000000000..58f5237f6 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/JournalSheet/constant.ts @@ -0,0 +1,17 @@ +export const HtmlTableCustomCss = ` +table tr.row-type--total td{ + font-weight: 600; +} +table tr td:not(:first-child) { + border-left: 1px solid #ececec; +} +table tr:last-child td { + border-bottom: 1px solid #ececec; +} +table .cell--credit, +table .cell--debit, +table .column--credit, +table .column--debit{ + text-align: right; +} +`; diff --git a/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetApplication.ts b/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetApplication.ts index eee89e73a..6d15e2cc6 100644 --- a/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetApplication.ts +++ b/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetApplication.ts @@ -3,6 +3,7 @@ import { ProfitLossSheetExportInjectable } from './ProfitLossSheetExportInjectab import { ProfitLossSheetTableInjectable } from './ProfitLossSheetTableInjectable'; import { IProfitLossSheetQuery, IProfitLossSheetTable } from '@/interfaces'; import ProfitLossSheetService from './ProfitLossSheetService'; +import { ProfitLossTablePdfInjectable } from './ProfitLossTablePdfInjectable'; @Service() export class ProfitLossSheetApplication { @@ -15,6 +16,9 @@ export class ProfitLossSheetApplication { @Inject() private profitLossSheet: ProfitLossSheetService; + @Inject() + private profitLossPdf: ProfitLossTablePdfInjectable; + /** * Retreives the profit/loss sheet. * @param {number} tenantId @@ -57,4 +61,14 @@ export class ProfitLossSheetApplication { public xlsx(tenantId: number, query: IProfitLossSheetQuery): Promise { return this.profitLossExport.xlsx(tenantId, query); } + + /** + * Retrieves the profit/loss sheet in pdf format. + * @param {number} tenantId + * @param {IProfitLossSheetQuery} query + * @returns {Promise} + */ + public pdf(tenantId: number, query: IProfitLossSheetQuery): Promise { + return this.profitLossPdf.pdf(tenantId, query); + } } diff --git a/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetMeta.ts b/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetMeta.ts new file mode 100644 index 000000000..c278420f5 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetMeta.ts @@ -0,0 +1,35 @@ +import moment from 'moment'; +import { Inject, Service } from 'typedi'; +import { FinancialSheetMeta } from '../FinancialSheetMeta'; +import { ICashFlowStatementMeta, ICashFlowStatementQuery } from '@/interfaces'; + +@Service() +export class ProfitLossSheetMeta { + @Inject() + private financialSheetMeta: FinancialSheetMeta; + + /** + * Retrieve the P/L sheet meta. + * @param {number} tenantId - + * @returns {IBalanceSheetMeta} + */ + public async meta( + tenantId: number, + query: ICashFlowStatementQuery + ): Promise { + const commonMeta = await this.financialSheetMeta.meta(tenantId); + const formattedToDate = moment(query.toDate).format('YYYY/MM/DD'); + const formattedFromDate = moment(query.fromDate).format('YYYY/MM/DD'); + const formattedDateRange = `From ${formattedFromDate} | To ${formattedToDate}`; + + const sheetName = 'Cashflow Statement'; + + return { + ...commonMeta, + sheetName, + formattedFromDate, + formattedToDate, + formattedDateRange, + }; + } +} diff --git a/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetService.ts b/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetService.ts index 20cf9a170..f3b24e7a6 100644 --- a/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetService.ts +++ b/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetService.ts @@ -6,11 +6,10 @@ import { } from '@/interfaces'; import ProfitLossSheet from './ProfitLossSheet'; import TenancyService from '@/services/Tenancy/TenancyService'; -import InventoryService from '@/services/Inventory/Inventory'; -import { parseBoolean } from 'utils'; import { Tenant } from '@/system/models'; import { mergeQueryWithDefaults } from './utils'; import { ProfitLossSheetRepository } from './ProfitLossSheetRepository'; +import { ProfitLossSheetMeta } from './ProfitLossSheetMeta'; // Profit/Loss sheet service. @Service() @@ -19,7 +18,7 @@ export default class ProfitLossSheetService { private tenancy: TenancyService; @Inject() - private inventoryService: InventoryService; + private profitLossSheetMeta: ProfitLossSheetMeta; /** * Retrieve profit/loss sheet statement. @@ -47,6 +46,7 @@ export default class ProfitLossSheetService { const profitLossRepo = new ProfitLossSheetRepository(models, filter); + // Loads the profit/loss sheet data. await profitLossRepo.asyncInitialize(); // Profit/Loss report instance. @@ -57,38 +57,15 @@ export default class ProfitLossSheetService { i18n ); // Profit/loss report data and collumns. - const profitLossData = profitLossInstance.reportData(); + const data = profitLossInstance.reportData(); + + // Retrieve the profit/loss sheet meta. + const meta = await this.profitLossSheetMeta.meta(tenantId, filter); return { - data: profitLossData, query: filter, - meta: this.reportMetadata(tenantId), + data, + meta, }; }; - - /** - * 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/ProfitLossTablePdfInjectable.ts b/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossTablePdfInjectable.ts new file mode 100644 index 000000000..4b0ba23de --- /dev/null +++ b/packages/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossTablePdfInjectable.ts @@ -0,0 +1,35 @@ +import { Inject, Service } from 'typedi'; +import { IProfitLossSheetQuery } from '@/interfaces'; +import { ProfitLossSheetTableInjectable } from './ProfitLossSheetTableInjectable'; +import { TableSheetPdf } from '../TableSheetPdf'; +import { HtmlTableCustomCss } from './constants'; + +@Service() +export class ProfitLossTablePdfInjectable { + @Inject() + private profitLossTable: ProfitLossSheetTableInjectable; + + @Inject() + private tableSheetPdf: TableSheetPdf; + + /** + * Retrieves the profit/loss sheet in pdf format. + * @param {number} tenantId + * @param {number} query + * @returns {Promise} + */ + public async pdf( + tenantId: number, + query: IProfitLossSheetQuery + ): Promise { + const table = await this.profitLossTable.table(tenantId, query); + + return this.tableSheetPdf.convertToPdf( + tenantId, + table.table, + table.meta.sheetName, + table.meta.formattedDateRange, + HtmlTableCustomCss + ); + } +} diff --git a/packages/server/src/services/FinancialStatements/ProfitLossSheet/constants.ts b/packages/server/src/services/FinancialStatements/ProfitLossSheet/constants.ts index 56f4a14ba..1ca50c5ed 100644 --- a/packages/server/src/services/FinancialStatements/ProfitLossSheet/constants.ts +++ b/packages/server/src/services/FinancialStatements/ProfitLossSheet/constants.ts @@ -18,4 +18,52 @@ export const TOTAL_NODE_TYPES = [ ProfitLossNodeType.ACCOUNTS, ProfitLossNodeType.AGGREGATE, ProfitLossNodeType.EQUATION -]; \ No newline at end of file +]; + +export const HtmlTableCustomCss =` +table tr.row-type--total td { + font-weight: 600; + border-top: 1px solid #bbb; + color: #000; +} +table tr.row-id--net-income td{ + border-bottom: 3px double #000; +} +table .column--name, +table .cell--name { + width: 400px; +} + +table .column--total { + width: 25%; +} +table td.cell--total, +table td.cell--previous_year, +table td.cell--previous_year_change, +table td.cell--previous_year_percentage, + +table td.cell--previous_period, +table td.cell--previous_period_change, +table td.cell--previous_period_percentage, + +table td.cell--percentage_of_row, +table td.cell--percentage_of_column, +table td[class*="cell--date-range"] { + text-align: right; +} + +table .column--total, +table .column--previous_year, +table .column--previous_year_change, +table .column--previous_year_percentage, + +table .column--previous_period, +table .column--previous_period_change, +table .column--previous_period_percentage, + +table .column--percentage_of_row, +table .column--percentage_of_column, +table [class*="column--date-range"] { + text-align: right; +} +`; \ No newline at end of file diff --git a/packages/server/src/services/FinancialStatements/PurchasesByItems/PurchasesByItemsApplication.ts b/packages/server/src/services/FinancialStatements/PurchasesByItems/PurchasesByItemsApplication.ts index c9a94bdbc..eeecaff38 100644 --- a/packages/server/src/services/FinancialStatements/PurchasesByItems/PurchasesByItemsApplication.ts +++ b/packages/server/src/services/FinancialStatements/PurchasesByItems/PurchasesByItemsApplication.ts @@ -7,6 +7,7 @@ import { } from '@/interfaces/PurchasesByItemsSheet'; import { PurchasesByItemsTableInjectable } from './PurchasesByItemsTableInjectable'; import { PurchasesByItemsService } from './PurchasesByItemsService'; +import { PurchasesByItemsPdf } from './PurchasesByItemsPdf'; @Service() export class PurcahsesByItemsApplication { @@ -19,6 +20,9 @@ export class PurcahsesByItemsApplication { @Inject() private purchasesByItemsExport: PurchasesByItemsExport; + @Inject() + private purchasesByItemsPdf: PurchasesByItemsPdf; + /** * Retrieves the purchases by items in json format. * @param {number} tenantId @@ -70,4 +74,17 @@ export class PurcahsesByItemsApplication { ): Promise { return this.purchasesByItemsExport.xlsx(tenantId, query); } + + /** + * Retrieves the purchases by items in pdf format. + * @param {number} tenantId + * @param {IPurchasesByItemsReportQuery} filter + * @returns {Promise} + */ + public pdf( + tenantId: number, + filter: IPurchasesByItemsReportQuery + ): Promise { + return this.purchasesByItemsPdf.pdf(tenantId, filter); + } } diff --git a/packages/server/src/services/FinancialStatements/PurchasesByItems/PurchasesByItemsMeta.ts b/packages/server/src/services/FinancialStatements/PurchasesByItems/PurchasesByItemsMeta.ts new file mode 100644 index 000000000..4bb22c583 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/PurchasesByItems/PurchasesByItemsMeta.ts @@ -0,0 +1,36 @@ +import moment from 'moment'; +import { Inject, Service } from 'typedi'; +import { FinancialSheetMeta } from '../FinancialSheetMeta'; +import { + IPurchasesByItemsReportQuery, + IPurchasesByItemsSheetMeta, +} from '@/interfaces/PurchasesByItemsSheet'; + +@Service() +export class PurchasesByItemsMeta { + @Inject() + private financialSheetMeta: FinancialSheetMeta; + + /** + * Retrieve the purchases by items meta. + * @param {number} tenantId - + * @returns {IBalanceSheetMeta} + */ + public async meta( + tenantId: number, + query: IPurchasesByItemsReportQuery + ): Promise { + const commonMeta = await this.financialSheetMeta.meta(tenantId); + const formattedToDate = moment(query.toDate).format('YYYY/MM/DD'); + const formattedFromDate = moment(query.fromDate).format('YYYY/MM/DD'); + const formattedDateRange = `From ${formattedFromDate} | To ${formattedToDate}`; + + return { + ...commonMeta, + sheetName: 'Purchases By Items', + formattedFromDate, + formattedToDate, + formattedDateRange, + }; + } +} diff --git a/packages/server/src/services/FinancialStatements/PurchasesByItems/PurchasesByItemsPdf.ts b/packages/server/src/services/FinancialStatements/PurchasesByItems/PurchasesByItemsPdf.ts new file mode 100644 index 000000000..67e3e7a24 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/PurchasesByItems/PurchasesByItemsPdf.ts @@ -0,0 +1,35 @@ +import { Inject, Service } from 'typedi'; +import { TableSheetPdf } from '../TableSheetPdf'; +import { PurchasesByItemsTableInjectable } from './PurchasesByItemsTableInjectable'; +import { IPurchasesByItemsReportQuery } from '@/interfaces/PurchasesByItemsSheet'; +import { HtmlTableCustomCss } from './_types'; + +@Service() +export class PurchasesByItemsPdf { + @Inject() + private purchasesByItemsTable: PurchasesByItemsTableInjectable; + + @Inject() + private tableSheetPdf: TableSheetPdf; + + /** + * Converts the given journal sheet table to pdf. + * @param {number} tenantId - Tenant ID. + * @param {IBalanceSheetQuery} query - Balance sheet query. + * @returns {Promise} + */ + public async pdf( + tenantId: number, + query: IPurchasesByItemsReportQuery + ): Promise { + const table = await this.purchasesByItemsTable.table(tenantId, query); + + return this.tableSheetPdf.convertToPdf( + tenantId, + table.table, + table.meta.sheetName, + table.meta.formattedDateRange, + HtmlTableCustomCss + ); + } +} diff --git a/packages/server/src/services/FinancialStatements/PurchasesByItems/PurchasesByItemsService.ts b/packages/server/src/services/FinancialStatements/PurchasesByItems/PurchasesByItemsService.ts index b9455be39..a2d6240cb 100644 --- a/packages/server/src/services/FinancialStatements/PurchasesByItems/PurchasesByItemsService.ts +++ b/packages/server/src/services/FinancialStatements/PurchasesByItems/PurchasesByItemsService.ts @@ -6,19 +6,22 @@ import { Tenant } from '@/system/models'; import { IPurchasesByItemsReportQuery, IPurchasesByItemsSheet, - IPurchasesByItemsSheetMeta, } from '@/interfaces/PurchasesByItemsSheet'; +import { PurchasesByItemsMeta } from './PurchasesByItemsMeta'; @Service() export class PurchasesByItemsService { @Inject() private tenancy: TenancyService; + @Inject() + private purchasesByItemsMeta: PurchasesByItemsMeta; + /** * Defaults purchases by items filter query. * @return {IPurchasesByItemsReportQuery} */ - get defaultQuery(): IPurchasesByItemsReportQuery { + private get defaultQuery(): IPurchasesByItemsReportQuery { return { fromDate: moment().startOf('month').format('YYYY-MM-DD'), toDate: moment().format('YYYY-MM-DD'), @@ -35,29 +38,6 @@ export class PurchasesByItemsService { }; } - /** - * Retrieve the balance sheet meta. - * @param {number} tenantId - - * @returns {IBalanceSheetMeta} - */ - reportMetadata(tenantId: number): IPurchasesByItemsSheetMeta { - const settings = this.tenancy.settings(tenantId); - - const organizationName = settings.get({ - group: 'organization', - key: 'name', - }); - const baseCurrency = settings.get({ - group: 'organization', - key: 'base_currency', - }); - - return { - organizationName, - baseCurrency, - }; - } - /** * Retrieve balance sheet statement. * ------------- @@ -109,10 +89,13 @@ export class PurchasesByItemsService { ); const purchasesByItemsData = purchasesByItemsInstance.reportData(); + // Retrieve the purchases by items meta. + const meta = await this.purchasesByItemsMeta.meta(tenantId, query); + return { data: purchasesByItemsData, query: filter, - meta: this.reportMetadata(tenantId), + meta, }; } } diff --git a/packages/server/src/services/FinancialStatements/PurchasesByItems/_types.ts b/packages/server/src/services/FinancialStatements/PurchasesByItems/_types.ts index d9fbb7dc0..bb4927958 100644 --- a/packages/server/src/services/FinancialStatements/PurchasesByItems/_types.ts +++ b/packages/server/src/services/FinancialStatements/PurchasesByItems/_types.ts @@ -1,5 +1,23 @@ - export enum ROW_TYPE { TOTAL = 'TOTAL', - ITEM = 'ITEM' -} \ No newline at end of file + ITEM = 'ITEM', +} + +export const HtmlTableCustomCss = ` +table tr.row-type--total td { + border-top: 1px solid #bbb; + border-bottom: 3px double #000; + font-weight: 600; +} +table .column--item_name{ + width: 300px; +} +table .column--quantity_purchases, +table .column--purchase_amount, +table .column--average_cost, +table .cell--quantity_purchases, +table .cell--purchase_amount, +table .cell--average_cost{ + text-align: right; +} +`; diff --git a/packages/server/src/services/FinancialStatements/SalesByItems/SalesByItems.ts b/packages/server/src/services/FinancialStatements/SalesByItems/SalesByItems.ts index 8c7e11256..9d96febd5 100644 --- a/packages/server/src/services/FinancialStatements/SalesByItems/SalesByItems.ts +++ b/packages/server/src/services/FinancialStatements/SalesByItems/SalesByItems.ts @@ -1,4 +1,5 @@ import { get, sumBy } from 'lodash'; + import * as R from 'ramda'; import FinancialSheet from '../FinancialSheet'; import { allPassedConditionsPass, transformToMap } from 'utils'; diff --git a/packages/server/src/services/FinancialStatements/SalesByItems/SalesByItemsApplication.ts b/packages/server/src/services/FinancialStatements/SalesByItems/SalesByItemsApplication.ts index b3b51869f..3ca915e39 100644 --- a/packages/server/src/services/FinancialStatements/SalesByItems/SalesByItemsApplication.ts +++ b/packages/server/src/services/FinancialStatements/SalesByItems/SalesByItemsApplication.ts @@ -1,13 +1,14 @@ import { Inject, Service } from 'typedi'; + import { ISalesByItemsReportQuery, ISalesByItemsSheet, - ISalesByItemsSheetData, ISalesByItemsTable, } from '@/interfaces'; import { SalesByItemsReportService } from './SalesByItemsService'; import { SalesByItemsTableInjectable } from './SalesByItemsTableInjectable'; import { SalesByItemsExport } from './SalesByItemsExport'; +import { SalesByItemsPdfInjectable } from './SalesByItemsPdfInjectable'; @Service() export class SalesByItemsApplication { @@ -20,6 +21,9 @@ export class SalesByItemsApplication { @Inject() private salesByItemsExport: SalesByItemsExport; + @Inject() + private salesByItemsPdf: SalesByItemsPdfInjectable; + /** * Retrieves the sales by items report in json format. * @param {number} tenantId @@ -71,4 +75,17 @@ export class SalesByItemsApplication { ): Promise { return this.salesByItemsExport.xlsx(tenantId, filter); } + + /** + * Retrieves the sales by items in pdf format. + * @param {number} tenantId + * @param {ISalesByItemsReportQuery} query + * @returns {Promise} + */ + public pdf( + tenantId: number, + query: ISalesByItemsReportQuery + ): Promise { + return this.salesByItemsPdf.pdf(tenantId, query); + } } diff --git a/packages/server/src/services/FinancialStatements/SalesByItems/SalesByItemsMeta.ts b/packages/server/src/services/FinancialStatements/SalesByItems/SalesByItemsMeta.ts new file mode 100644 index 000000000..b47b45215 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/SalesByItems/SalesByItemsMeta.ts @@ -0,0 +1,35 @@ +import moment from 'moment'; +import { Inject, Service } from 'typedi'; +import { FinancialSheetMeta } from '../FinancialSheetMeta'; +import { ISalesByItemsReportQuery, ISalesByItemsSheetMeta } from '@/interfaces'; + +@Service() +export class SalesByItemsMeta { + @Inject() + private financialSheetMeta: FinancialSheetMeta; + + /** + * Retrieve the sales by items meta. + * @param {number} tenantId - + * @returns {IBalanceSheetMeta} + */ + public async meta( + tenantId: number, + query: ISalesByItemsReportQuery + ): Promise { + const commonMeta = await this.financialSheetMeta.meta(tenantId); + const formattedToDate = moment(query.toDate).format('YYYY/MM/DD'); + const formattedFromDate = moment(query.fromDate).format('YYYY/MM/DD'); + const formattedDateRange = `From ${formattedFromDate} | To ${formattedToDate}`; + + const sheetName = 'Sales By Items'; + + return { + ...commonMeta, + sheetName, + formattedFromDate, + formattedToDate, + formattedDateRange, + }; + } +} diff --git a/packages/server/src/services/FinancialStatements/SalesByItems/SalesByItemsPdfInjectable.ts b/packages/server/src/services/FinancialStatements/SalesByItems/SalesByItemsPdfInjectable.ts new file mode 100644 index 000000000..874154086 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/SalesByItems/SalesByItemsPdfInjectable.ts @@ -0,0 +1,35 @@ +import { Inject, Service } from 'typedi'; +import { ISalesByItemsReportQuery } from '@/interfaces'; +import { SalesByItemsTableInjectable } from './SalesByItemsTableInjectable'; +import { TableSheetPdf } from '../TableSheetPdf'; +import { HtmlTableCustomCss } from './constants'; + +@Service() +export class SalesByItemsPdfInjectable { + @Inject() + private salesByItemsTable: SalesByItemsTableInjectable; + + @Inject() + private tableSheetPdf: TableSheetPdf; + + /** + * Retrieves the sales by items sheet in pdf format. + * @param {number} tenantId + * @param {number} query + * @returns {Promise} + */ + public async pdf( + tenantId: number, + query: ISalesByItemsReportQuery + ): Promise { + const table = await this.salesByItemsTable.table(tenantId, query); + + return this.tableSheetPdf.convertToPdf( + tenantId, + table.table, + table.meta.sheetName, + table.meta.formattedDateRange, + HtmlTableCustomCss + ); + } +} diff --git a/packages/server/src/services/FinancialStatements/SalesByItems/SalesByItemsService.ts b/packages/server/src/services/FinancialStatements/SalesByItems/SalesByItemsService.ts index bad73e34b..1dc9b4f05 100644 --- a/packages/server/src/services/FinancialStatements/SalesByItems/SalesByItemsService.ts +++ b/packages/server/src/services/FinancialStatements/SalesByItems/SalesByItemsService.ts @@ -1,27 +1,24 @@ import { Service, Inject } from 'typedi'; import moment from 'moment'; -import { - ISalesByItemsReportQuery, - ISalesByItemsSheetMeta, - ISalesByItemsSheet, -} from '@/interfaces'; +import { ISalesByItemsReportQuery, ISalesByItemsSheet } from '@/interfaces'; import TenancyService from '@/services/Tenancy/TenancyService'; import SalesByItems from './SalesByItems'; import { Tenant } from '@/system/models'; +import { SalesByItemsMeta } from './SalesByItemsMeta'; @Service() export class SalesByItemsReportService { @Inject() - tenancy: TenancyService; + private tenancy: TenancyService; - @Inject('logger') - logger: any; + @Inject() + private salesByItemsMeta: SalesByItemsMeta; /** * Defaults balance sheet filter query. * @return {IBalanceSheetQuery} */ - get defaultQuery(): ISalesByItemsReportQuery { + private get defaultQuery(): ISalesByItemsReportQuery { return { fromDate: moment().startOf('month').format('YYYY-MM-DD'), toDate: moment().format('YYYY-MM-DD'), @@ -38,29 +35,6 @@ export class SalesByItemsReportService { }; } - /** - * Retrieve the balance sheet meta. - * @param {number} tenantId - - * @returns {IBalanceSheetMeta} - */ - reportMetadata(tenantId: number): ISalesByItemsSheetMeta { - const settings = this.tenancy.settings(tenantId); - - const organizationName = settings.get({ - group: 'organization', - key: 'name', - }); - const baseCurrency = settings.get({ - group: 'organization', - key: 'base_currency', - }); - - return { - organizationName, - baseCurrency, - }; - } - /** * Retrieve balance sheet statement. * @param {number} tenantId @@ -112,10 +86,13 @@ export class SalesByItemsReportService { ); const salesByItemsData = sheet.reportData(); + // Retrieve the sales by items meta. + const meta = await this.salesByItemsMeta.meta(tenantId, query); + return { data: salesByItemsData, query: filter, - meta: this.reportMetadata(tenantId), + meta, }; } } diff --git a/packages/server/src/services/FinancialStatements/SalesByItems/constants.ts b/packages/server/src/services/FinancialStatements/SalesByItems/constants.ts index 0eb1e2311..761e37ec5 100644 --- a/packages/server/src/services/FinancialStatements/SalesByItems/constants.ts +++ b/packages/server/src/services/FinancialStatements/SalesByItems/constants.ts @@ -1,6 +1,23 @@ - - export enum ROW_TYPE { ITEM = 'ITEM', TOTAL = 'TOTAL', -} \ No newline at end of file +} + +export const HtmlTableCustomCss = ` +table tr.row-type--total td { + border-top: 1px solid #bbb; + border-bottom: 3px double #000; + font-weight: 600; +} +table .column--item_name{ + width: 300px; +} +table .column--average_price, +table .column--sold_quantity, +table .column--sold_amount, +table .cell--average_price, +table .cell--sold_quantity, +table .cell--sold_amount{ + text-align: right; +} +`; diff --git a/packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryApplication.ts b/packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryApplication.ts index f0e5a5248..3b9f0d7b3 100644 --- a/packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryApplication.ts +++ b/packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryApplication.ts @@ -3,6 +3,7 @@ import { SalesTaxLiabilitySummaryQuery } from '@/interfaces/SalesTaxLiabilitySum import { SalesTaxLiabilitySummaryTableInjectable } from './SalesTaxLiabilitySummaryTableInjectable'; import { SalesTaxLiabilitySummaryExportInjectable } from './SalesTaxLiabilitySummaryExportInjectable'; import { SalesTaxLiabilitySummaryService } from './SalesTaxLiabilitySummaryService'; +import { SalesTaxLiabiltiySummaryPdf } from './SalesTaxLiabiltiySummaryPdf'; @Service() export class SalesTaxLiabilitySummaryApplication { @@ -15,6 +16,9 @@ export class SalesTaxLiabilitySummaryApplication { @Inject() private salesTaxLiabilityTable: SalesTaxLiabilitySummaryTableInjectable; + @Inject() + private salesTaxLiabiltiyPdf: SalesTaxLiabiltiySummaryPdf; + /** * Retrieves the sales tax liability summary in json format. * @param {number} tenantId @@ -60,4 +64,17 @@ export class SalesTaxLiabilitySummaryApplication { ): Promise { return this.salesTaxLiabilityExport.csv(tenantId, query); } + + /** + * Retrieves the sales tax liability summary in PDF format. + * @param {number} tenantId + * @param {SalesTaxLiabilitySummaryQuery} query + * @returns {Promise} + */ + public pdf( + tenantId: number, + query: SalesTaxLiabilitySummaryQuery + ): Promise { + return this.salesTaxLiabiltiyPdf.pdf(tenantId, query): + } } diff --git a/packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryMeta.ts b/packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryMeta.ts new file mode 100644 index 000000000..c18a8f55d --- /dev/null +++ b/packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryMeta.ts @@ -0,0 +1,32 @@ +import { Inject, Service } from 'typedi'; +import moment from 'moment'; +import { SalesTaxLiabilitySummaryQuery } from '@/interfaces/SalesTaxLiabilitySummary'; +import { FinancialSheetMeta } from '../FinancialSheetMeta'; + +@Service() +export class SalesTaxLiabilitySummaryMeta { + @Inject() + private financialSheetMeta: FinancialSheetMeta; + + /** + * Retrieves the report meta. + * @param {number} tenantId + * @param {SalesTaxLiabilitySummaryQuery} filter + */ + public async meta(tenantId: number, query: SalesTaxLiabilitySummaryQuery) { + const commonMeta = await this.financialSheetMeta.meta(tenantId); + const formattedToDate = moment(query.toDate).format('YYYY/MM/DD'); + const formattedFromDate = moment(query.fromDate).format('YYYY/MM/DD'); + const formattedDateRange = `From ${formattedFromDate} | To ${formattedToDate}`; + + const sheetName = 'Sales Tax Liability Summary'; + + return { + ...commonMeta, + sheetName, + formattedFromDate, + formattedToDate, + formattedDateRange, + }; + } +} diff --git a/packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryService.ts b/packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryService.ts index a1ec7a771..585e9e4d9 100644 --- a/packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryService.ts +++ b/packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabilitySummaryService.ts @@ -1,11 +1,8 @@ import { Inject, Service } from 'typedi'; import { SalesTaxLiabilitySummaryRepository } from './SalesTaxLiabilitySummaryRepository'; -import { - SalesTaxLiabilitySummaryMeta, - SalesTaxLiabilitySummaryQuery, -} from '@/interfaces/SalesTaxLiabilitySummary'; +import { SalesTaxLiabilitySummaryQuery } from '@/interfaces/SalesTaxLiabilitySummary'; import { SalesTaxLiabilitySummary } from './SalesTaxLiabilitySummary'; -import HasTenancyService from '@/services/Tenancy/TenancyService'; +import { SalesTaxLiabilitySummaryMeta } from './SalesTaxLiabilitySummaryMeta'; @Service() export class SalesTaxLiabilitySummaryService { @@ -13,7 +10,7 @@ export class SalesTaxLiabilitySummaryService { private repostiory: SalesTaxLiabilitySummaryRepository; @Inject() - private tenancy: HasTenancyService; + private salesTaxLiabilityMeta: SalesTaxLiabilitySummaryMeta; /** * Retrieve sales tax liability summary. @@ -39,33 +36,12 @@ export class SalesTaxLiabilitySummaryService { payableByRateId, salesByRateId ); + const meta = await this.salesTaxLiabilityMeta.meta(tenantId, query); + return { data: taxLiabilitySummary.reportData(), query, - meta: this.reportMetadata(tenantId), - }; - } - - /** - * Retrieve the report meta. - * @param {number} tenantId - - * @returns {IBalanceSheetMeta} - */ - private reportMetadata(tenantId: number): SalesTaxLiabilitySummaryMeta { - const settings = this.tenancy.settings(tenantId); - - const organizationName = settings.get({ - group: 'organization', - key: 'name', - }); - const baseCurrency = settings.get({ - group: 'organization', - key: 'base_currency', - }); - - return { - organizationName, - baseCurrency, + meta, }; } } diff --git a/packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabiltiySummaryPdf.ts b/packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabiltiySummaryPdf.ts new file mode 100644 index 000000000..742241842 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/SalesTaxLiabilitySummary/SalesTaxLiabiltiySummaryPdf.ts @@ -0,0 +1,36 @@ +import { Inject, Service } from 'typedi'; +import { TableSheetPdf } from '../TableSheetPdf'; +import { SalesTaxLiabilitySummaryTableInjectable } from './SalesTaxLiabilitySummaryTableInjectable'; +import { ISalesByItemsReportQuery } from '@/interfaces'; +import { SalesTaxLiabilitySummaryQuery } from '@/interfaces/SalesTaxLiabilitySummary'; + +@Service() +export class SalesTaxLiabiltiySummaryPdf { + @Inject() + private salesTaxLiabiltiySummaryTable: SalesTaxLiabilitySummaryTableInjectable; + + @Inject() + private tableSheetPdf: TableSheetPdf; + + /** + * Converts the given sales tax liability summary table to pdf. + * @param {number} tenantId - Tenant ID. + * @param {ISalesByItemsReportQuery} query - Balance sheet query. + * @returns {Promise} + */ + public async pdf( + tenantId: number, + query: SalesTaxLiabilitySummaryQuery + ): Promise { + const table = await this.salesTaxLiabiltiySummaryTable.table( + tenantId, + query + ); + return this.tableSheetPdf.convertToPdf( + tenantId, + table.table, + table.meta.sheetName, + table.meta.formattedDateRange + ); + } +} diff --git a/packages/server/src/services/FinancialStatements/TableSheetPdf.ts b/packages/server/src/services/FinancialStatements/TableSheetPdf.ts new file mode 100644 index 000000000..280adf187 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/TableSheetPdf.ts @@ -0,0 +1,79 @@ +import { Inject, Service } from 'typedi'; +import * as R from 'ramda'; +import { ITableColumn, ITableData, ITableRow } from '@/interfaces'; +import { ChromiumlyTenancy } from '@/services/ChromiumlyTenancy/ChromiumlyTenancy'; +import { TemplateInjectable } from '@/services/TemplateInjectable/TemplateInjectable'; +import { FinancialTableStructure } from './FinancialTableStructure'; +import { tableClassNames } from './utils'; + +@Service() +export class TableSheetPdf { + @Inject() + private templateInjectable: TemplateInjectable; + + @Inject() + private chromiumlyTenancy: ChromiumlyTenancy; + + /** + * Converts the table data into a PDF format. + * @param {number} tenantId - The unique identifier for the tenant. + * @param {ITableData} table - The table data to be converted. + * @param {string} sheetName - The name of the sheet. + * @param {string} sheetDate - The date of the sheet. + * @returns A promise that resolves with the PDF conversion result. + */ + public async convertToPdf( + tenantId: number, + table: ITableData, + sheetName: string, + sheetDate: string, + customCSS?: string + ): Promise { + // Prepare columns and rows for PDF conversion + const columns = this.tablePdfColumns(table.columns); + const rows = this.tablePdfRows(table.rows); + + const landscape = columns.length > 4; + + // Generate HTML content from the template + const htmlContent = await this.templateInjectable.render( + tenantId, + 'modules/financial-sheet', + { + table: { rows, columns }, + sheetName, + sheetDate, + customCSS, + } + ); + // Convert the HTML content to PDF + return this.chromiumlyTenancy.convertHtmlContent(tenantId, htmlContent, { + margins: { top: 0, bottom: 0, left: 0, right: 0 }, + landscape, + }); + } + + /** + * Converts the table columns to pdf columns. + * @param {ITableColumn[]} columns + * @returns {ITableColumn[]} + */ + private tablePdfColumns = (columns: ITableColumn[]): ITableColumn[] => { + return columns; + }; + + /** + * Converts the table rows to pdf rows. + * @param {ITableRow[]} rows - + * @returns {ITableRow[]} + */ + private tablePdfRows = (rows: ITableRow[]): ITableRow[] => { + const curriedFlatNestedTree = R.curry( + FinancialTableStructure.flatNestedTree + ); + const flatNestedTree = curriedFlatNestedTree(R.__, { + nestedPrefix: '', + }); + return R.compose(tableClassNames, flatNestedTree)(rows); + }; +} diff --git a/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersApplication.ts b/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersApplication.ts index b729c219a..c3e4feb7e 100644 --- a/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersApplication.ts +++ b/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersApplication.ts @@ -6,6 +6,7 @@ import { import { TransactionsByCustomersTableInjectable } from './TransactionsByCustomersTableInjectable'; import { TransactionsByCustomersExportInjectable } from './TransactionsByCustomersExportInjectable'; import { TransactionsByCustomersSheet } from './TransactionsByCustomersService'; +import { TransactionsByCustomersPdf } from './TransactionsByCustomersPdf'; @Service() export class TransactionsByCustomerApplication { @@ -18,6 +19,9 @@ export class TransactionsByCustomerApplication { @Inject() private transactionsByCustomersSheet: TransactionsByCustomersSheet; + @Inject() + private transactionsByCustomersPdf: TransactionsByCustomersPdf; + /** * Retrieves the transactions by customers sheet in json format. * @param {number} tenantId @@ -69,4 +73,17 @@ export class TransactionsByCustomerApplication { ): Promise { return this.transactionsByCustomersExport.xlsx(tenantId, query); } + + /** + * Retrieves the transactions by vendors sheet in PDF format. + * @param {number} tenantId + * @param {ITransactionsByCustomersFilter} query + * @returns {Promise} + */ + public pdf( + tenantId: number, + query: ITransactionsByCustomersFilter + ): Promise { + return this.transactionsByCustomersPdf.pdf(tenantId, query); + } } diff --git a/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersMeta.ts b/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersMeta.ts new file mode 100644 index 000000000..710bc0bc4 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersMeta.ts @@ -0,0 +1,36 @@ +import moment from 'moment'; +import { Inject, Service } from 'typedi'; +import { FinancialSheetMeta } from '../FinancialSheetMeta'; +import { + ITransactionsByCustomersFilter, + ITransactionsByCustomersMeta, +} from '@/interfaces'; + +@Service() +export class TransactionsByCustomersMeta { + @Inject() + private financialSheetMeta: FinancialSheetMeta; + + /** + * Retrieves the transactions by customers meta. + * @param {number} tenantId - + * @returns {IBalanceSheetMeta} + */ + public async meta( + tenantId: number, + query: ITransactionsByCustomersFilter + ): Promise { + const commonMeta = await this.financialSheetMeta.meta(tenantId); + const formattedToDate = moment(query.toDate).format('YYYY/MM/DD'); + const formattedFromDate = moment(query.fromDate).format('YYYY/MM/DD'); + const formattedDateRange = `From ${formattedFromDate} | To ${formattedToDate}`; + + return { + ...commonMeta, + sheetName: 'Transactions By Customers', + formattedFromDate, + formattedToDate, + formattedDateRange, + }; + } +} diff --git a/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersPdf.ts b/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersPdf.ts new file mode 100644 index 000000000..122cbbaf2 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersPdf.ts @@ -0,0 +1,34 @@ +import { ITransactionsByCustomersFilter } from '@/interfaces'; +import { Inject } from 'typedi'; +import { TableSheetPdf } from '../TableSheetPdf'; +import { TransactionsByCustomersTableInjectable } from './TransactionsByCustomersTableInjectable'; + +export class TransactionsByCustomersPdf { + @Inject() + private transactionsByCustomersTable: TransactionsByCustomersTableInjectable; + + @Inject() + private tableSheetPdf: TableSheetPdf; + + /** + * Retrieves the transactions by customers in PDF format. + * @param {number} tenantId - Tenant ID. + * @param {ITransactionsByCustomersFilter} query - Balance sheet query. + * @returns {Promise} + */ + public async pdf( + tenantId: number, + query: ITransactionsByCustomersFilter + ): Promise { + const table = await this.transactionsByCustomersTable.table( + tenantId, + query + ); + return this.tableSheetPdf.convertToPdf( + tenantId, + table.table, + table.meta.sheetName, + table.meta.formattedDateRange + ); + } +} diff --git a/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersService.ts b/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersService.ts index 3fbf8cf06..a97a13afe 100644 --- a/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersService.ts +++ b/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersService.ts @@ -12,6 +12,7 @@ import TransactionsByCustomers from './TransactionsByCustomers'; import Ledger from '@/services/Accounting/Ledger'; import TransactionsByCustomersRepository from './TransactionsByCustomersRepository'; import { Tenant } from '@/system/models'; +import { TransactionsByCustomersMeta } from './TransactionsByCustomersMeta'; export class TransactionsByCustomersSheet implements ITransactionsByCustomersService @@ -22,6 +23,9 @@ export class TransactionsByCustomersSheet @Inject() private reportRepository: TransactionsByCustomersRepository; + @Inject() + private transactionsByCustomersMeta: TransactionsByCustomersMeta; + /** * Defaults balance sheet filter query. * @return {ICustomerBalanceSummaryQuery} @@ -160,9 +164,12 @@ export class TransactionsByCustomersSheet i18n ); + const meta = await this.transactionsByCustomersMeta.meta(tenantId, filter); + return { data: reportInstance.reportData(), query: filter, + meta, }; } } diff --git a/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersTable.ts b/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersTable.ts index 7016cf853..2f38b9cde 100644 --- a/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersTable.ts +++ b/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersTable.ts @@ -1,6 +1,10 @@ import * as R from 'ramda'; import { tableRowMapper } from 'utils'; -import { ITransactionsByCustomersCustomer, ITableRow, ITableColumn } from '@/interfaces'; +import { + ITransactionsByCustomersCustomer, + ITableRow, + ITableColumn, +} from '@/interfaces'; import TransactionsByContactsTableRows from '../TransactionsByContact/TransactionsByContactTableRows'; enum ROW_TYPE { @@ -78,6 +82,14 @@ export class TransactionsByCustomersTable extends TransactionsByContactsTableRow * @returns {ITableColumn[]} */ public tableColumns = (): ITableColumn[] => { - return []; - } + return [ + { key: 'customer_name', label: 'Customer name' }, + { key: 'account_name', label: 'Account Name' }, + { key: 'ref_type', label: 'Reference Type' }, + { key: 'transaction_type', label: 'Transaction Type' }, + { key: 'credit', label: 'Credit' }, + { key: 'debit', label: 'Debit' }, + { key: 'running_balance', label: 'Running Balance' }, + ]; + }; } diff --git a/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersTableInjectable.ts b/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersTableInjectable.ts index fb1c61311..2f2aa0277 100644 --- a/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersTableInjectable.ts +++ b/packages/server/src/services/FinancialStatements/TransactionsByCustomer/TransactionsByCustomersTableInjectable.ts @@ -39,6 +39,7 @@ export class TransactionsByCustomersTableInjectable { columns: table.tableColumns(), }, query: customersTransactions.query, + meta: customersTransactions.meta }; } } diff --git a/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorApplication.ts b/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorApplication.ts index d8d424a30..54a4c7ed4 100644 --- a/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorApplication.ts +++ b/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorApplication.ts @@ -7,6 +7,7 @@ import { import { TransactionsByVendorExportInjectable } from './TransactionsByVendorExportInjectable'; import { TransactionsByVendorTableInjectable } from './TransactionsByVendorTableInjectable'; import { TransactionsByVendorsInjectable } from './TransactionsByVendorInjectable'; +import { TransactionsByVendorsPdf } from './TransactionsByVendorPdf'; @Service() export class TransactionsByVendorApplication { @@ -19,6 +20,9 @@ export class TransactionsByVendorApplication { @Inject() private transactionsByVendorSheet: TransactionsByVendorsInjectable; + @Inject() + private transactionsByVendorPdf: TransactionsByVendorsPdf; + /** * Retrieves the transactions by vendor in sheet format. * @param {number} tenantId @@ -65,6 +69,7 @@ export class TransactionsByVendorApplication { * Retrieves the transactions by vendor in XLSX format. * @param {number} tenantId * @param {ITransactionsByVendorsFilter} query + * @returns {Promise} */ public xlsx( tenantId: number, @@ -72,4 +77,14 @@ export class TransactionsByVendorApplication { ): Promise { return this.transactionsByVendorExport.xlsx(tenantId, query); } + + /** + * Retrieves the transactions by vendor in PDF format. + * @param {number} tenantId + * @param {ITransactionsByVendorsFilter} query + * @returns {Promise} + */ + public pdf(tenantId: number, query: ITransactionsByVendorsFilter) { + return this.transactionsByVendorPdf.pdf(tenantId, query); + } } diff --git a/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorInjectable.ts b/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorInjectable.ts index a24041929..69b424957 100644 --- a/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorInjectable.ts +++ b/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorInjectable.ts @@ -12,6 +12,7 @@ import TransactionsByVendor from './TransactionsByVendor'; import Ledger from '@/services/Accounting/Ledger'; import TransactionsByVendorRepository from './TransactionsByVendorRepository'; import { Tenant } from '@/system/models'; +import { TransactionsByVendorMeta } from './TransactionsByVendorMeta'; export class TransactionsByVendorsInjectable implements ITransactionsByVendorsService @@ -22,6 +23,9 @@ export class TransactionsByVendorsInjectable @Inject() private reportRepository: TransactionsByVendorRepository; + @Inject() + private transactionsByVendorMeta: TransactionsByVendorMeta; + /** * Defaults balance sheet filter query. * @return {IVendorBalanceSummaryQuery} @@ -165,9 +169,12 @@ export class TransactionsByVendorsInjectable tenant.metadata.baseCurrency, i18n ); + const meta = await this.transactionsByVendorMeta.meta(tenantId, filter); + return { data: reportInstance.reportData(), query: filter, + meta, }; } } diff --git a/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorMeta.ts b/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorMeta.ts new file mode 100644 index 000000000..ea31ac034 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorMeta.ts @@ -0,0 +1,36 @@ +import moment from 'moment'; +import { Inject, Service } from 'typedi'; +import { FinancialSheetMeta } from '../FinancialSheetMeta'; +import { + ITransactionsByVendorMeta, + ITransactionsByVendorsFilter, +} from '@/interfaces'; + +@Service() +export class TransactionsByVendorMeta { + @Inject() + private financialSheetMeta: FinancialSheetMeta; + + /** + * Retrieves the transactions by vendor meta. + * @param {number} tenantId - + * @returns {Promise} + */ + public async meta( + tenantId: number, + query: ITransactionsByVendorsFilter + ): Promise { + const commonMeta = await this.financialSheetMeta.meta(tenantId); + const formattedToDate = moment(query.toDate).format('YYYY/MM/DD'); + const formattedFromDate = moment(query.fromDate).format('YYYY/MM/DD'); + const formattedDateRange = `From ${formattedFromDate} | To ${formattedToDate}`; + + return { + ...commonMeta, + sheetName: 'Transactions By Vendor', + formattedFromDate, + formattedToDate, + formattedDateRange, + }; + } +} diff --git a/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorPdf.ts b/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorPdf.ts new file mode 100644 index 000000000..54ab1be40 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorPdf.ts @@ -0,0 +1,33 @@ +import { Inject, Service } from 'typedi'; +import { ITransactionsByVendorsFilter } from '@/interfaces'; +import { TableSheetPdf } from '../TableSheetPdf'; +import { TransactionsByVendorTableInjectable } from './TransactionsByVendorTableInjectable'; + +@Service() +export class TransactionsByVendorsPdf { + @Inject() + private transactionsByVendorTable: TransactionsByVendorTableInjectable; + + @Inject() + private tableSheetPdf: TableSheetPdf; + + /** + * Converts the given balance sheet table to pdf. + * @param {number} tenantId - Tenant ID. + * @param {IBalanceSheetQuery} query - Balance sheet query. + * @returns {Promise} + */ + public async pdf( + tenantId: number, + query: ITransactionsByVendorsFilter + ): Promise { + const table = await this.transactionsByVendorTable.table(tenantId, query); + + return this.tableSheetPdf.convertToPdf( + tenantId, + table.table, + table.meta.sheetName, + table.meta.formattedDateRange + ); + } +} diff --git a/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorTable.ts b/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorTable.ts index 14ad3c1b4..2f8bf2498 100644 --- a/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorTable.ts +++ b/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorTable.ts @@ -43,7 +43,6 @@ export class TransactionsByVendorsTable extends TransactionsByContactsTableRows accessor: 'closingBalance.formattedAmount', }, ]; - return { ...tableRowMapper(vendor, columns, { rowTypes: [ROW_TYPE.VENDOR] }), children: R.pipe( @@ -82,6 +81,14 @@ export class TransactionsByVendorsTable extends TransactionsByContactsTableRows * @returns {ITableColumn[]} */ public tableColumns = (): ITableColumn[] => { - return []; + return [ + { key: 'vendor_name', label: 'Vendor name' }, + { key: 'account_name', label: 'Account Name' }, + { key: 'ref_type', label: 'Reference Type' }, + { key: 'transaction_type', label: 'Transaction Type' }, + { key: 'credit', label: 'Credit' }, + { key: 'debit', label: 'Debit' }, + { key: 'running_balance', label: 'Running Balance' }, + ]; }; } diff --git a/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorTableInjectable.ts b/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorTableInjectable.ts index 5b42b88e7..5c5243059 100644 --- a/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorTableInjectable.ts +++ b/packages/server/src/services/FinancialStatements/TransactionsByVendor/TransactionsByVendorTableInjectable.ts @@ -39,6 +39,7 @@ export class TransactionsByVendorTableInjectable { columns: table.tableColumns(), }, query, + meta: sheet.meta, }; } } diff --git a/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceExportInjectable.ts b/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceExportInjectable.ts index a515f1beb..62b847f7c 100644 --- a/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceExportInjectable.ts +++ b/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceExportInjectable.ts @@ -1,13 +1,17 @@ +import { Inject, Service } from 'typedi'; import { TableSheet } from '@/lib/Xlsx/TableSheet'; import { ITrialBalanceSheetQuery } from '@/interfaces'; -import { Inject, Service } from 'typedi'; import { TrialBalanceSheetTableInjectable } from './TrialBalanceSheetTableInjectable'; +import { TrialBalanceSheetPdfInjectable } from './TrialBalanceSheetPdfInjectsable'; @Service() export class TrialBalanceExportInjectable { @Inject() private trialBalanceSheetTable: TrialBalanceSheetTableInjectable; + @Inject() + private trialBalanceSheetPdf: TrialBalanceSheetPdfInjectable; + /** * Retrieves the trial balance sheet in XLSX format. * @param {number} tenantId @@ -40,4 +44,17 @@ export class TrialBalanceExportInjectable { return tableCsv; } + + /** + * Retrieves the trial balance sheet in PDF format. + * @param {number} tenantId + * @param {ITrialBalanceSheetQuery} query + * @returns {Promise} + */ + public async pdf( + tenantId: number, + query: ITrialBalanceSheetQuery + ): Promise { + return this.trialBalanceSheetPdf.pdf(tenantId, query); + } } diff --git a/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetApplication.ts b/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetApplication.ts index a771c8f15..20c485ecc 100644 --- a/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetApplication.ts +++ b/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetApplication.ts @@ -57,4 +57,14 @@ export class TrialBalanceSheetApplication { public async xlsx(tenantId: number, query: ITrialBalanceSheetQuery) { return this.exportable.xlsx(tenantId, query); } + + /** + * Retrieve the trial balance sheet in pdf format. + * @param {number} tenantId + * @param {ITrialBalanceSheetQuery} query + * @returns {Promise} + */ + public async pdf(tenantId: number, query: ITrialBalanceSheetQuery) { + return this.exportable.pdf(tenantId, query); + } } diff --git a/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetInjectable.ts b/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetInjectable.ts index bc880ec99..df498241b 100644 --- a/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetInjectable.ts +++ b/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetInjectable.ts @@ -1,28 +1,20 @@ import { Service, Inject } from 'typedi'; import moment from 'moment'; import TenancyService from '@/services/Tenancy/TenancyService'; -import { - ITrialBalanceSheetMeta, - ITrialBalanceSheetQuery, - ITrialBalanceStatement, -} from '@/interfaces'; +import { ITrialBalanceSheetQuery, ITrialBalanceStatement } from '@/interfaces'; import TrialBalanceSheet from './TrialBalanceSheet'; import FinancialSheet from '../FinancialSheet'; -import InventoryService from '@/services/Inventory/Inventory'; -import { parseBoolean } from 'utils'; import { Tenant } from '@/system/models'; import { TrialBalanceSheetRepository } from './TrialBalanceSheetRepository'; +import { TrialBalanceSheetMeta } from './TrialBalanceSheetMeta'; @Service() export default class TrialBalanceSheetService extends FinancialSheet { @Inject() - tenancy: TenancyService; + private tenancy: TenancyService; @Inject() - inventoryService: InventoryService; - - @Inject('logger') - logger: any; + private trialBalanceSheetMetaService: TrialBalanceSheetMeta; /** * Defaults trial balance sheet filter query. @@ -47,32 +39,6 @@ export default class TrialBalanceSheetService extends FinancialSheet { }; } - /** - * Retrieve the trial balance sheet meta. - * @param {number} tenantId - Tenant id. - * @returns {ITrialBalanceSheetMeta} - */ - private reportMetadata(tenantId: number): ITrialBalanceSheetMeta { - 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, - }; - } - /** * Retrieve trial balance sheet statement. * @param {number} tenantId @@ -99,6 +65,7 @@ export default class TrialBalanceSheetService extends FinancialSheet { repos, filter ); + // Loads the resources. await trialBalanceSheetRepos.asyncInitialize(); // Trial balance report instance. @@ -111,10 +78,13 @@ export default class TrialBalanceSheetService extends FinancialSheet { // Trial balance sheet data. const trialBalanceSheetData = trialBalanceInstance.reportData(); + // Trial balance sheet meta. + const meta = await this.trialBalanceSheetMetaService.meta(tenantId, filter); + return { data: trialBalanceSheetData, query: filter, - meta: this.reportMetadata(tenantId), + meta, }; } } diff --git a/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetMeta.ts b/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetMeta.ts new file mode 100644 index 000000000..7561e2b66 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetMeta.ts @@ -0,0 +1,37 @@ +import { Inject, Service } from 'typedi'; +import moment from 'moment'; +import { ITrialBalanceSheetMeta, ITrialBalanceSheetQuery } from '@/interfaces'; +import { FinancialSheetMeta } from '../FinancialSheetMeta'; + +@Service() +export class TrialBalanceSheetMeta { + @Inject() + private financialSheetMeta: FinancialSheetMeta; + + /** + * Retrieves the trial balance sheet meta. + * @param {number} tenantId + * @param {ITrialBalanceSheetQuery} query + * @returns {Promise} + */ + public async meta( + tenantId: number, + query: ITrialBalanceSheetQuery + ): Promise { + const commonMeta = await this.financialSheetMeta.meta(tenantId); + + const formattedFromDate = moment(query.fromDate).format('YYYY/MM/DD'); + const formattedToDate = moment(query.toDate).format('YYYY/MM/DD'); + const formattedDateRange = `From ${formattedFromDate} to ${formattedToDate}`; + + const sheetName = 'Trial Balance Sheet'; + + return { + ...commonMeta, + sheetName, + formattedFromDate, + formattedToDate, + formattedDateRange, + }; + } +} diff --git a/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetPdfInjectsable.ts b/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetPdfInjectsable.ts new file mode 100644 index 000000000..b7b53d437 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetPdfInjectsable.ts @@ -0,0 +1,35 @@ +import { Inject, Service } from 'typedi'; +import { ITrialBalanceSheetQuery } from '@/interfaces'; +import { TableSheetPdf } from '../TableSheetPdf'; +import { TrialBalanceSheetTableInjectable } from './TrialBalanceSheetTableInjectable'; +import { HtmlTableCustomCss } from './_constants'; + +@Service() +export class TrialBalanceSheetPdfInjectable { + @Inject() + private trialBalanceSheetTable: TrialBalanceSheetTableInjectable; + + @Inject() + private tableSheetPdf: TableSheetPdf; + + /** + * Converts the given trial balance sheet table to pdf. + * @param {number} tenantId - Tenant ID. + * @param {ITrialBalanceSheetQuery} query - Trial balance sheet query. + * @returns {Promise} + */ + public async pdf( + tenantId: number, + query: ITrialBalanceSheetQuery + ): Promise { + const table = await this.trialBalanceSheetTable.table(tenantId, query); + + return this.tableSheetPdf.convertToPdf( + tenantId, + table.table, + table.meta.sheetName, + table.meta.formattedDateRange, + HtmlTableCustomCss + ); + } +} diff --git a/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetTable.ts b/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetTable.ts index 5de03eb71..0d4df537e 100644 --- a/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetTable.ts +++ b/packages/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetTable.ts @@ -2,7 +2,6 @@ import * as R from 'ramda'; import FinancialSheet from '../FinancialSheet'; import { FinancialTable } from '../FinancialTable'; import { - IBalanceSheetStatementData, ITableColumn, ITableColumnAccessor, ITableRow, @@ -20,12 +19,13 @@ export class TrialBalanceSheetTable extends R.compose( FinancialSheetStructure )(FinancialSheet) { /** + * Trial balance sheet data. * @param {ITrialBalanceSheetData} */ public data: ITrialBalanceSheetData; /** - * Balance sheet query. + * Trial balance sheet query. * @param {ITrialBalanceSheetQuery} */ public query: ITrialBalanceSheetQuery; @@ -136,7 +136,7 @@ export class TrialBalanceSheetTable extends R.compose( return R.compose( this.tableColumnsCellIndexing, R.concat([ - { key: 'account_name', label: 'Account' }, + { key: 'account', label: 'Account' }, { key: 'debit', label: 'Debit' }, { key: 'credit', label: 'Credit' }, { key: 'total', label: 'Total' }, diff --git a/packages/server/src/services/FinancialStatements/TrialBalanceSheet/_constants.ts b/packages/server/src/services/FinancialStatements/TrialBalanceSheet/_constants.ts index 91e8c595f..80951d81e 100644 --- a/packages/server/src/services/FinancialStatements/TrialBalanceSheet/_constants.ts +++ b/packages/server/src/services/FinancialStatements/TrialBalanceSheet/_constants.ts @@ -1,5 +1,25 @@ - export enum IROW_TYPE { ACCOUNT = 'ACCOUNT', TOTAL = 'TOTAL', -} \ No newline at end of file +} + +export const HtmlTableCustomCss = ` +table tr.row-type--total td{ + border-top: 1px solid #bbb; + font-weight: 500; + border-bottom: 3px double #000; +} + +table .column--account { + width: 400px; +} + +table .column--debit, +table .column--credit, +table .column--total, +table .cell--debit, +table .cell--credit, +table .cell--total{ + text-align: right; +} +`; diff --git a/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummary.ts b/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummary.ts index 2e5e09aa4..6d04461b6 100644 --- a/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummary.ts +++ b/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummary.ts @@ -41,7 +41,7 @@ export class VendorBalanceSummaryReport extends ContactBalanceSummaryReport { /** * Customer section mapper. - * @param {IVendor} vendor + * @param {IVendor} vendor * @returns {IVendorBalanceSummaryVendor} */ private vendorMapper = (vendor: IVendor): IVendorBalanceSummaryVendor => { @@ -58,7 +58,7 @@ export class VendorBalanceSummaryReport extends ContactBalanceSummaryReport { /** * Mappes the vendor model object to vendor balance summary section. - * @param {IVendor[]} vendors - Customers. + * @param {IVendor[]} vendors - Customers. * @returns {IVendorBalanceSummaryVendor[]} */ private vendorsMapper = ( @@ -77,7 +77,7 @@ export class VendorBalanceSummaryReport extends ContactBalanceSummaryReport { /** * Retrieve the vendors sections of the report. - * @param {IVendor} vendors + * @param {IVendor} vendors * @returns {IVendorBalanceSummaryVendor[]} */ private getVendorsSection(vendors: IVendor[]): IVendorBalanceSummaryVendor[] { diff --git a/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryApplication.ts b/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryApplication.ts index 5fe4bc74d..c02eac224 100644 --- a/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryApplication.ts +++ b/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryApplication.ts @@ -3,6 +3,7 @@ import { IVendorBalanceSummaryQuery } from '@/interfaces'; import { VendorBalanceSummaryTableInjectable } from './VendorBalanceSummaryTableInjectable'; import { VendorBalanceSummaryExportInjectable } from './VendorBalanceSummaryExportInjectable'; import { VendorBalanceSummaryService } from './VendorBalanceSummaryService'; +import { VendorBalanceSummaryPdf } from './VendorBalanceSummaryPdf'; @Service() export class VendorBalanceSummaryApplication { @@ -15,6 +16,9 @@ export class VendorBalanceSummaryApplication { @Inject() private vendorBalanceSummaryExport: VendorBalanceSummaryExportInjectable; + @Inject() + private vendorBalanceSummaryPdf: VendorBalanceSummaryPdf; + /** * Retrieves the vendor balance summary sheet in sheet format. * @param {number} tenantId @@ -59,4 +63,14 @@ export class VendorBalanceSummaryApplication { ): Promise { return this.vendorBalanceSummaryExport.csv(tenantId, query); } + + /** + * Retrieves the vendor balance summary sheet in pdf format. + * @param {number} tenantId + * @param {IVendorBalanceSummaryQuery} query + * @returns {Promise} + */ + public pdf(tenantId: number, query: IVendorBalanceSummaryQuery) { + return this.vendorBalanceSummaryPdf.pdf(tenantId, query); + } } diff --git a/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryMeta.ts b/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryMeta.ts new file mode 100644 index 000000000..80071f8ca --- /dev/null +++ b/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryMeta.ts @@ -0,0 +1,32 @@ +import moment from 'moment'; +import { Inject, Service } from 'typedi'; +import { FinancialSheetMeta } from '../FinancialSheetMeta'; +import { + IVendorBalanceSummaryMeta, + IVendorBalanceSummaryQuery, +} from '@/interfaces'; + +@Service() +export class VendorBalanceSummaryMeta { + @Inject() + private financialSheetMeta: FinancialSheetMeta; + + /** + * Retrieves the vendor balance summary meta. + * @param {number} tenantId - + * @returns {IBalanceSheetMeta} + */ + public async meta( + tenantId: number, + query: IVendorBalanceSummaryQuery + ): Promise { + const commonMeta = await this.financialSheetMeta.meta(tenantId); + const formattedAsDate = moment(query.asDate).format('YYYY/MM/DD'); + + return { + ...commonMeta, + sheetName: 'Vendor Balance Summary', + formattedAsDate, + }; + } +} diff --git a/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryPdf.ts b/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryPdf.ts new file mode 100644 index 000000000..f13ffc98c --- /dev/null +++ b/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryPdf.ts @@ -0,0 +1,35 @@ +import { Inject, Service } from 'typedi'; +import { IVendorBalanceSummaryQuery } from '@/interfaces'; +import { TableSheetPdf } from '../TableSheetPdf'; +import { VendorBalanceSummaryTableInjectable } from './VendorBalanceSummaryTableInjectable'; +import { HtmlTableCustomCss } from './constants'; + +@Service() +export class VendorBalanceSummaryPdf { + @Inject() + private vendorBalanceSummaryTable: VendorBalanceSummaryTableInjectable; + + @Inject() + private tableSheetPdf: TableSheetPdf; + + /** + * Retrieves the sales by items sheet in pdf format. + * @param {number} tenantId + * @param {number} query + * @returns {Promise} + */ + public async pdf( + tenantId: number, + query: IVendorBalanceSummaryQuery + ): Promise { + const table = await this.vendorBalanceSummaryTable.table(tenantId, query); + + return this.tableSheetPdf.convertToPdf( + tenantId, + table.table, + table.meta.sheetName, + table.meta.formattedAsDate, + HtmlTableCustomCss + ); + } +} diff --git a/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryService.ts b/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryService.ts index b1a361b87..c64496b7b 100644 --- a/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryService.ts +++ b/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryService.ts @@ -12,15 +12,21 @@ import { VendorBalanceSummaryReport } from './VendorBalanceSummary'; import Ledger from '@/services/Accounting/Ledger'; import VendorBalanceSummaryRepository from './VendorBalanceSummaryRepository'; import { Tenant } from '@/system/models'; +import { JournalSheetMeta } from '../JournalSheet/JournalSheetMeta'; + +import { VendorBalanceSummaryMeta } from './VendorBalanceSummaryMeta'; export class VendorBalanceSummaryService implements IVendorBalanceSummaryService { @Inject() - tenancy: TenancyService; + private tenancy: TenancyService; + + @Inject() + private reportRepo: VendorBalanceSummaryRepository; @Inject() - reportRepo: VendorBalanceSummaryRepository; + private vendorBalanceSummaryMeta: VendorBalanceSummaryMeta; /** * Defaults balance sheet filter query. @@ -43,6 +49,7 @@ export class VendorBalanceSummaryService } /** + * * Retrieve the vendors ledger entrjes. * @param {number} tenantId - * @param {Date|string} date - @@ -97,10 +104,13 @@ export class VendorBalanceSummaryService filter, tenant.metadata.baseCurrency ); + // Retrieve the vendor balance summary meta. + const meta = await this.vendorBalanceSummaryMeta.meta(tenantId, filter); return { data: reportInstance.reportData(), query: filter, + meta }; } } diff --git a/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryTableInjectable.ts b/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryTableInjectable.ts index aec97e6f1..c055b1151 100644 --- a/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryTableInjectable.ts +++ b/packages/server/src/services/FinancialStatements/VendorBalanceSummary/VendorBalanceSummaryTableInjectable.ts @@ -27,10 +27,12 @@ export class VendorBalanceSummaryTableInjectable { ): Promise { const i18n = this.tenancy.i18n(tenantId); - const { data } = await this.vendorBalanceSummarySheet.vendorBalanceSummary( - tenantId, - query - ); + const { data, meta } = + await this.vendorBalanceSummarySheet.vendorBalanceSummary( + + tenantId, + query + ); const table = new VendorBalanceSummaryTable(data, query, i18n); return { @@ -39,6 +41,7 @@ export class VendorBalanceSummaryTableInjectable { rows: table.tableRows(), }, query, + meta, }; } } diff --git a/packages/server/src/services/FinancialStatements/VendorBalanceSummary/constants.ts b/packages/server/src/services/FinancialStatements/VendorBalanceSummary/constants.ts new file mode 100644 index 000000000..50c3aac24 --- /dev/null +++ b/packages/server/src/services/FinancialStatements/VendorBalanceSummary/constants.ts @@ -0,0 +1,6 @@ +export const HtmlTableCustomCss = ` +table tr.row-type--total td { + font-weight: 600; + border-top: 1px solid #bbb; + border-bottom: 3px double #333; +}`; diff --git a/packages/server/src/services/FinancialStatements/utils.ts b/packages/server/src/services/FinancialStatements/utils.ts index 1114131b9..5d304ca6f 100644 --- a/packages/server/src/services/FinancialStatements/utils.ts +++ b/packages/server/src/services/FinancialStatements/utils.ts @@ -1,4 +1,5 @@ - +import { kebabCase } from 'lodash'; +import { ITableRow } from '@/interfaces'; export const formatNumber = (balance, { noCents, divideOn1000 }): string => { let formattedBalance: number = parseFloat(balance); @@ -10,4 +11,20 @@ export const formatNumber = (balance, { noCents, divideOn1000 }): string => { formattedBalance /= 1000; } return formattedBalance; -}; \ No newline at end of file +}; + +export const tableClassNames = (rows: ITableRow[]) => { + return rows.map((row) => { + const classNames = + row?.rowTypes?.map((rowType) => `row-type--${kebabCase(rowType)}`) || []; + + if (row.id) { + classNames.push(`row-id--${kebabCase(row.id)}`); + } + + return { + ...row, + classNames, + }; + }); +}; diff --git a/packages/server/src/system/models/TenantMetadata.ts b/packages/server/src/system/models/TenantMetadata.ts index 7040a6a68..98953dd43 100644 --- a/packages/server/src/system/models/TenantMetadata.ts +++ b/packages/server/src/system/models/TenantMetadata.ts @@ -2,6 +2,7 @@ import BaseModel from 'models/Model'; export default class TenantMetadata extends BaseModel { baseCurrency: string; + name: string; /** * Table name. diff --git a/packages/webapp/src/components/FormattedMessage/index.tsx b/packages/webapp/src/components/FormattedMessage/index.tsx index b23418325..6dd6ff98b 100644 --- a/packages/webapp/src/components/FormattedMessage/index.tsx +++ b/packages/webapp/src/components/FormattedMessage/index.tsx @@ -1,8 +1,13 @@ // @ts-nocheck import intl from 'react-intl-universal'; -export function FormattedMessage({ id, values }) { - return intl.get(id, values); +interface FormattedMessageProps { + id: string; + values?: Record; +} + +export function FormattedMessage({ id, values }: FormattedMessageProps) { + return <>{intl.get(id, values)}; } export function FormattedHTMLMessage({ ...args }) { diff --git a/packages/webapp/src/constants/dialogs.ts b/packages/webapp/src/constants/dialogs.ts index c9bb52a0e..ba06da095 100644 --- a/packages/webapp/src/constants/dialogs.ts +++ b/packages/webapp/src/constants/dialogs.ts @@ -53,4 +53,21 @@ export enum DialogsName { EstimateMail = 'estimate-mail', ReceiptMail = 'receipt-mail', PaymentMail = 'payment-mail', + BalanceSheetPdfPreview = 'BalanceSheetPdfPreview', + TrialBalanceSheetPdfPreview = 'TrialBalanceSheetPdfPreview', + CashflowSheetPdfPreview = 'CashflowSheetPdfPreview', + ProfitLossSheetPdfPreview = 'ProfitLossSheetPdfPreview', + InventoryValuationPdfPreview = 'InventoryValuationPdfPreview', + APAgingSummaryPdfPreview = 'APAgingSummaryPdfPreview', + ARAgingSummaryPdfPreview = 'ARAgingSummaryPdfPreview', + JournalPdfPreview = 'JournalPdfPreview', + SalesByItemsPdfPreview = 'SalesByItemsPdfPreview', + PurchasesByItemsPdfPreview = 'PurchasesByItemsPdfPreview', + VendorBalancePdfPreview = 'VendorBalancePdfPreview', + InventoryItemDetailsPdfPreview = 'InventoryItemDetailsPdfPreview', + CustomerBalanceSummaryPdfPreview = 'CustomerBalanceSummaryPdfPreview', + CustomerTransactionsPdfPreview = 'CustomerTransactionsPdfPreview', + VendorTransactionsPdfPreview = 'VendorTransactionsPdfPreview', + GeneralLedgerPdfPreview = 'GeneralLedgerPdfPreview', + SalesTaxLiabilitySummaryPdfPreview = 'SalesTaxLiabilitySummaryPdfPreview' } diff --git a/packages/webapp/src/containers/FinancialStatements/APAgingSummary/APAgingSummary.tsx b/packages/webapp/src/containers/FinancialStatements/APAgingSummary/APAgingSummary.tsx index 0e16bac3e..f3df7ef86 100644 --- a/packages/webapp/src/containers/FinancialStatements/APAgingSummary/APAgingSummary.tsx +++ b/packages/webapp/src/containers/FinancialStatements/APAgingSummary/APAgingSummary.tsx @@ -15,6 +15,8 @@ import { APAgingSummarySheetLoadingBar } from './components'; import withAPAgingSummaryActions from './withAPAgingSummaryActions'; import { compose } from '@/utils'; +import { APAgingSummaryPdfDialog } from './dialogs/APAgingSummaryPdfDialog'; +import { DialogsName } from '@/constants/dialogs'; /** * A/P aging summary report. @@ -68,6 +70,10 @@ function APAgingSummary({ + + ); } diff --git a/packages/webapp/src/containers/FinancialStatements/APAgingSummary/APAgingSummaryActionsBar.tsx b/packages/webapp/src/containers/FinancialStatements/APAgingSummary/APAgingSummaryActionsBar.tsx index f0473ab58..9035be7e6 100644 --- a/packages/webapp/src/containers/FinancialStatements/APAgingSummary/APAgingSummaryActionsBar.tsx +++ b/packages/webapp/src/containers/FinancialStatements/APAgingSummary/APAgingSummaryActionsBar.tsx @@ -21,6 +21,8 @@ import withAPAgingSummary from './withAPAgingSummary'; import withAPAgingSummaryActions from './withAPAgingSummaryActions'; import { saveInvoke, compose } from '@/utils'; +import { DialogsName } from '@/constants/dialogs'; +import withDialogActions from '@/containers/Dialog/withDialogActions'; /** * AP Aging summary sheet - Actions bar. @@ -32,6 +34,9 @@ function APAgingSummaryActionsBar({ // #withARAgingSummaryActions toggleAPAgingSummaryFilterDrawer: toggleFilterDrawerDisplay, + // #withDialogActions + openDialog, + //#ownProps numberFormat, onNumberFormatSubmit, @@ -52,6 +57,11 @@ function APAgingSummaryActionsBar({ saveInvoke(onNumberFormatSubmit, numberFormat); }; + // Handle the print button click. + const handlePrintBtnClick = () => { + openDialog(DialogsName.APAgingSummaryPdfPreview); + }; + return ( @@ -106,6 +116,7 @@ function APAgingSummaryActionsBar({ className={Classes.MINIMAL} icon={} text={} + onClick={handlePrintBtnClick} /> } @@ -129,4 +140,5 @@ export default compose( withAPAgingSummary(({ APAgingSummaryFilterDrawer }) => ({ isFilterDrawerOpen: APAgingSummaryFilterDrawer, })), + withDialogActions )(APAgingSummaryActionsBar); diff --git a/packages/webapp/src/containers/FinancialStatements/APAgingSummary/APAgingSummaryDialogs.tsx b/packages/webapp/src/containers/FinancialStatements/APAgingSummary/APAgingSummaryDialogs.tsx new file mode 100644 index 000000000..003c9d5f2 --- /dev/null +++ b/packages/webapp/src/containers/FinancialStatements/APAgingSummary/APAgingSummaryDialogs.tsx @@ -0,0 +1,12 @@ +import { DialogsName } from '@/constants/dialogs'; +import { APAgingSummaryPdfDialog } from './dialogs/APAgingSummaryPdfDialog'; + +export function APAgingSummaryDialogs() { + return ( + <> + + + ); +} diff --git a/packages/webapp/src/containers/FinancialStatements/APAgingSummary/APAgingSummaryProvider.tsx b/packages/webapp/src/containers/FinancialStatements/APAgingSummary/APAgingSummaryProvider.tsx index 28611a13d..844a2b904 100644 --- a/packages/webapp/src/containers/FinancialStatements/APAgingSummary/APAgingSummaryProvider.tsx +++ b/packages/webapp/src/containers/FinancialStatements/APAgingSummary/APAgingSummaryProvider.tsx @@ -1,5 +1,5 @@ // @ts-nocheck -import React, { useMemo, createContext, useContext } from 'react'; +import { useMemo, createContext, useContext } from 'react'; import FinancialReportPage from '../FinancialReportPage'; import { useAPAgingSummaryReport } from '@/hooks/query'; @@ -12,22 +12,22 @@ const APAgingSummaryContext = createContext(); */ function APAgingSummaryProvider({ filter, ...props }) { // Transformers the filter from to the Url query. - const query = useMemo(() => transformFilterFormToQuery(filter), [filter]); + const httpQuery = useMemo(() => transformFilterFormToQuery(filter), [filter]); const { data: APAgingSummary, isLoading: isAPAgingLoading, isFetching: isAPAgingFetching, refetch, - } = useAPAgingSummaryReport(query, { keepPreviousData: true }); + } = useAPAgingSummaryReport(httpQuery, { keepPreviousData: true }); const provider = { APAgingSummary, - isAPAgingLoading, isAPAgingFetching, refetch, - query, + query: httpQuery, + httpQuery, }; return ( diff --git a/packages/webapp/src/containers/FinancialStatements/APAgingSummary/components.tsx b/packages/webapp/src/containers/FinancialStatements/APAgingSummary/components.tsx index b313bab50..408057c22 100644 --- a/packages/webapp/src/containers/FinancialStatements/APAgingSummary/components.tsx +++ b/packages/webapp/src/containers/FinancialStatements/APAgingSummary/components.tsx @@ -49,11 +49,8 @@ export function APAgingSummarySheetLoadingBar() { */ export function APAgingSummaryExportMenu() { const toastKey = useRef(null); - const commonToastConfig = { - isCloseButtonShown: true, - timeout: 2000, - }; - const { query } = useAPAgingSummaryContext(); + const commonToastConfig = { isCloseButtonShown: true, timeout: 2000 }; + const { httpQuery } = useAPAgingSummaryContext(); const openProgressToast = (amount: number) => { return ( @@ -70,7 +67,7 @@ export function APAgingSummaryExportMenu() { ); }; // Export the report to xlsx. - const { mutateAsync: xlsxExport } = useAPAgingSheetXlsxExport(query, { + const { mutateAsync: xlsxExport } = useAPAgingSheetXlsxExport(httpQuery, { onDownloadProgress: (xlsxExportProgress: number) => { if (!toastKey.current) { toastKey.current = AppToaster.show({ @@ -89,7 +86,7 @@ export function APAgingSummaryExportMenu() { }, }); // Export the report to csv. - const { mutateAsync: csvExport } = useAPAgingSheetCsvExport(query, { + const { mutateAsync: csvExport } = useAPAgingSheetCsvExport(httpQuery, { onDownloadProgress: (xlsxExportProgress: number) => { if (!toastKey.current) { toastKey.current = AppToaster.show({ diff --git a/packages/webapp/src/containers/FinancialStatements/APAgingSummary/dialogs/APAgingSummaryPdfDialog/APAgingSummaryPdfDialog.tsx b/packages/webapp/src/containers/FinancialStatements/APAgingSummary/dialogs/APAgingSummaryPdfDialog/APAgingSummaryPdfDialog.tsx new file mode 100644 index 000000000..e497798b8 --- /dev/null +++ b/packages/webapp/src/containers/FinancialStatements/APAgingSummary/dialogs/APAgingSummaryPdfDialog/APAgingSummaryPdfDialog.tsx @@ -0,0 +1,39 @@ +// @ts-nocheck +import React, { lazy } from 'react'; +import classNames from 'classnames'; + +import { Dialog, DialogSuspense } from '@/components'; +import withDialogRedux from '@/components/DialogReduxConnect'; +import { CLASSES } from '@/constants/classes'; +import { compose } from '@/utils'; + +// Lazy loading the content. +const APAgingSummaryPdfDialogContent = lazy( + () => import('./APAgingSummaryPdfDialogContent'), +); + +/** + * A/P aging summary pdf preview dialog. + * @returns {React.ReactNode} + */ +function APAgingSummaryPdfDialogRoot({ dialogName, payload, isOpen }) { + return ( + + + + + + ); +} + +export const APAgingSummaryPdfDialog = compose(withDialogRedux())( + APAgingSummaryPdfDialogRoot, +); diff --git a/packages/webapp/src/containers/FinancialStatements/APAgingSummary/dialogs/APAgingSummaryPdfDialog/APAgingSummaryPdfDialogContent.tsx b/packages/webapp/src/containers/FinancialStatements/APAgingSummary/dialogs/APAgingSummaryPdfDialog/APAgingSummaryPdfDialogContent.tsx new file mode 100644 index 000000000..de94494bd --- /dev/null +++ b/packages/webapp/src/containers/FinancialStatements/APAgingSummary/dialogs/APAgingSummaryPdfDialog/APAgingSummaryPdfDialogContent.tsx @@ -0,0 +1,45 @@ +// @ts-nocheck +import { + DialogContent, + PdfDocumentPreview, + FormattedMessage as T, +} from '@/components'; +import { useAPAgingSummaryPdf } from '@/hooks/query'; +import { AnchorButton } from '@blueprintjs/core'; +import { useAPAgingSummaryContext } from '../../APAgingSummaryProvider'; + +export default function APAgingSummaryPdfDialogContent() { + const { httpQuery } = useAPAgingSummaryContext(); + const { isLoading, pdfUrl } = useAPAgingSummaryPdf(httpQuery); + + return ( + +
+ + + + + + + +
+ + +
+ ); +} diff --git a/packages/webapp/src/containers/FinancialStatements/APAgingSummary/dialogs/APAgingSummaryPdfDialog/index.ts b/packages/webapp/src/containers/FinancialStatements/APAgingSummary/dialogs/APAgingSummaryPdfDialog/index.ts new file mode 100644 index 000000000..4d3fd7ed7 --- /dev/null +++ b/packages/webapp/src/containers/FinancialStatements/APAgingSummary/dialogs/APAgingSummaryPdfDialog/index.ts @@ -0,0 +1 @@ +export * from './APAgingSummaryPdfDialog'; \ No newline at end of file diff --git a/packages/webapp/src/containers/FinancialStatements/ARAgingSummary/ARAgingSummary.tsx b/packages/webapp/src/containers/FinancialStatements/ARAgingSummary/ARAgingSummary.tsx index 2ff0550bb..f56ba5a00 100644 --- a/packages/webapp/src/containers/FinancialStatements/ARAgingSummary/ARAgingSummary.tsx +++ b/packages/webapp/src/containers/FinancialStatements/ARAgingSummary/ARAgingSummary.tsx @@ -1,5 +1,5 @@ // @ts-nocheck -import React, { useState, useCallback, useEffect } from 'react'; +import { useCallback, useEffect } from 'react'; import moment from 'moment'; import ARAgingSummaryHeader from './ARAgingSummaryHeader'; @@ -13,6 +13,8 @@ import { ARAgingSummaryBody } from './ARAgingSummaryBody'; import withARAgingSummaryActions from './withARAgingSummaryActions'; import { useARAgingSummaryQuery } from './common'; +import { ARAgingSummaryPdfDialog } from './dialogs/ARAgingSummaryPdfDialog'; +import { DialogsName } from '@/constants/dialogs'; import { compose } from '@/utils'; /** @@ -25,13 +27,16 @@ function ReceivableAgingSummarySheet({ const { query, setLocationQuery } = useARAgingSummaryQuery(); // Handle filter submit. - const handleFilterSubmit = useCallback((filter) => { - const _filter = { - ...filter, - asDate: moment(filter.asDate).format('YYYY-MM-DD'), - }; - setLocationQuery(_filter); - }, [setLocationQuery]); + const handleFilterSubmit = useCallback( + (filter) => { + const _filter = { + ...filter, + asDate: moment(filter.asDate).format('YYYY-MM-DD'), + }; + setLocationQuery(_filter); + }, + [setLocationQuery], + ); // Handle number format submit. const handleNumberFormatSubmit = (numberFormat) => { @@ -60,6 +65,10 @@ function ReceivableAgingSummarySheet({ + + ); } diff --git a/packages/webapp/src/containers/FinancialStatements/ARAgingSummary/ARAgingSummaryActionsBar.tsx b/packages/webapp/src/containers/FinancialStatements/ARAgingSummary/ARAgingSummaryActionsBar.tsx index 4b34f94aa..e0a0ab51c 100644 --- a/packages/webapp/src/containers/FinancialStatements/ARAgingSummary/ARAgingSummaryActionsBar.tsx +++ b/packages/webapp/src/containers/FinancialStatements/ARAgingSummary/ARAgingSummaryActionsBar.tsx @@ -17,9 +17,11 @@ import NumberFormatDropdown from '@/components/NumberFormatDropdown'; import { useARAgingSummaryContext } from './ARAgingSummaryProvider'; import withARAgingSummaryActions from './withARAgingSummaryActions'; import withARAgingSummary from './withARAgingSummary'; +import withDialogActions from '@/containers/Dialog/withDialogActions'; import { compose, safeInvoke } from '@/utils'; import { ARAgingSummaryExportMenu } from './components'; +import { DialogsName } from '@/constants/dialogs'; /** * A/R Aging summary sheet - Actions bar. @@ -31,6 +33,9 @@ function ARAgingSummaryActionsBar({ // #withReceivableAgingActions toggleARAgingSummaryFilterDrawer: toggleDisplayFilterDrawer, + // #withDialogActions + openDialog, + // #ownProps numberFormat, onNumberFormatSubmit, @@ -51,6 +56,11 @@ function ARAgingSummaryActionsBar({ safeInvoke(onNumberFormatSubmit, numberFormat); }; + // Handles the print button click. + const handlePrintBtnClick = () => { + openDialog(DialogsName.ARAgingSummaryPdfPreview) + }; + return ( @@ -107,6 +117,7 @@ function ARAgingSummaryActionsBar({ className={Classes.MINIMAL} icon={} text={} + onClick={handlePrintBtnClick} /> } @@ -130,4 +141,5 @@ export default compose( withARAgingSummary(({ ARAgingSummaryFilterDrawer }) => ({ isFilterDrawerOpen: ARAgingSummaryFilterDrawer, })), + withDialogActions, )(ARAgingSummaryActionsBar); diff --git a/packages/webapp/src/containers/FinancialStatements/ARAgingSummary/ARAgingSummaryProvider.tsx b/packages/webapp/src/containers/FinancialStatements/ARAgingSummary/ARAgingSummaryProvider.tsx index 1b9577900..1698870a5 100644 --- a/packages/webapp/src/containers/FinancialStatements/ARAgingSummary/ARAgingSummaryProvider.tsx +++ b/packages/webapp/src/containers/FinancialStatements/ARAgingSummary/ARAgingSummaryProvider.tsx @@ -1,5 +1,5 @@ // @ts-nocheck -import React, { useMemo, createContext, useContext } from 'react'; +import { useMemo, createContext, useContext } from 'react'; import FinancialReportPage from '../FinancialReportPage'; import { useARAgingSummaryReport } from '@/hooks/query'; import { transformFilterFormToQuery } from '../common'; @@ -11,10 +11,7 @@ const ARAgingSummaryContext = createContext(); */ function ARAgingSummaryProvider({ filter, ...props }) { // Transformes the filter from to the url query. - const requestQuery = useMemo( - () => transformFilterFormToQuery(filter), - [filter], - ); + const httpQuery = useMemo(() => transformFilterFormToQuery(filter), [filter]); // A/R aging summary sheet context. const { @@ -22,13 +19,14 @@ function ARAgingSummaryProvider({ filter, ...props }) { isLoading: isARAgingLoading, isFetching: isARAgingFetching, refetch, - } = useARAgingSummaryReport(requestQuery, { keepPreviousData: true }); + } = useARAgingSummaryReport(httpQuery, { keepPreviousData: true }); const provider = { ARAgingSummary, isARAgingLoading, isARAgingFetching, refetch, + httpQuery, }; return ( diff --git a/packages/webapp/src/containers/FinancialStatements/ARAgingSummary/components.tsx b/packages/webapp/src/containers/FinancialStatements/ARAgingSummary/components.tsx index 19166c101..6039fbfc5 100644 --- a/packages/webapp/src/containers/FinancialStatements/ARAgingSummary/components.tsx +++ b/packages/webapp/src/containers/FinancialStatements/ARAgingSummary/components.tsx @@ -53,7 +53,7 @@ export function ARAgingSummaryExportMenu() { isCloseButtonShown: true, timeout: 2000, }; - const { query } = useARAgingSummaryContext(); + const { httpQuery } = useARAgingSummaryContext(); const openProgressToast = (amount: number) => { return ( @@ -71,7 +71,7 @@ export function ARAgingSummaryExportMenu() { }; // Export the report to xlsx. - const { mutateAsync: xlsxExport } = useARAgingSheetXlsxExport(query, { + const { mutateAsync: xlsxExport } = useARAgingSheetXlsxExport(httpQuery, { onDownloadProgress: (xlsxExportProgress: number) => { if (!toastKey.current) { toastKey.current = AppToaster.show({ @@ -90,7 +90,7 @@ export function ARAgingSummaryExportMenu() { }, }); // Export the report to csv. - const { mutateAsync: csvExport } = useARAgingSheetCsvExport(query, { + const { mutateAsync: csvExport } = useARAgingSheetCsvExport(httpQuery, { onDownloadProgress: (xlsxExportProgress: number) => { if (!toastKey.current) { toastKey.current = AppToaster.show({ diff --git a/packages/webapp/src/containers/FinancialStatements/ARAgingSummary/dialogs/ARAgingSummaryPdfDialog/ARAgingSummaryPdfDialog.tsx b/packages/webapp/src/containers/FinancialStatements/ARAgingSummary/dialogs/ARAgingSummaryPdfDialog/ARAgingSummaryPdfDialog.tsx new file mode 100644 index 000000000..5ae8d9998 --- /dev/null +++ b/packages/webapp/src/containers/FinancialStatements/ARAgingSummary/dialogs/ARAgingSummaryPdfDialog/ARAgingSummaryPdfDialog.tsx @@ -0,0 +1,39 @@ +// @ts-nocheck +import React, { lazy } from 'react'; +import classNames from 'classnames'; + +import { Dialog, DialogSuspense } from '@/components'; +import withDialogRedux from '@/components/DialogReduxConnect'; +import { CLASSES } from '@/constants/classes'; +import { compose } from '@/utils'; + +// Lazy loading the content. +const ARAgingSummaryPdfDialogContent = lazy( + () => import('./ARAgingSummaryPdfDialogContent'), +); + +/** + * Balance sheet pdf preview dialog. + * @returns {React.ReactNode} + */ +function ARAgingSummaryPdfDialogRoot({ dialogName, payload, isOpen }) { + return ( + + + + + + ); +} + +export const ARAgingSummaryPdfDialog = compose(withDialogRedux())( + ARAgingSummaryPdfDialogRoot, +); diff --git a/packages/webapp/src/containers/FinancialStatements/ARAgingSummary/dialogs/ARAgingSummaryPdfDialog/ARAgingSummaryPdfDialogContent.tsx b/packages/webapp/src/containers/FinancialStatements/ARAgingSummary/dialogs/ARAgingSummaryPdfDialog/ARAgingSummaryPdfDialogContent.tsx new file mode 100644 index 000000000..add15f432 --- /dev/null +++ b/packages/webapp/src/containers/FinancialStatements/ARAgingSummary/dialogs/ARAgingSummaryPdfDialog/ARAgingSummaryPdfDialogContent.tsx @@ -0,0 +1,45 @@ +// @ts-nocheck +import { + DialogContent, + PdfDocumentPreview, + FormattedMessage as T, +} from '@/components'; +import { useARAgingSummaryPdf } from '@/hooks/query'; +import { AnchorButton } from '@blueprintjs/core'; +import { useARAgingSummaryContext } from '../../ARAgingSummaryProvider'; + +export default function ARAgingSummaryPdfDialogContent() { + const { httpQuery } = useARAgingSummaryContext(); + const { isLoading, pdfUrl } = useARAgingSummaryPdf(httpQuery); + + return ( + +
+ + + + + + + +
+ + +
+ ); +} diff --git a/packages/webapp/src/containers/FinancialStatements/ARAgingSummary/dialogs/ARAgingSummaryPdfDialog/index.ts b/packages/webapp/src/containers/FinancialStatements/ARAgingSummary/dialogs/ARAgingSummaryPdfDialog/index.ts new file mode 100644 index 000000000..6a739c257 --- /dev/null +++ b/packages/webapp/src/containers/FinancialStatements/ARAgingSummary/dialogs/ARAgingSummaryPdfDialog/index.ts @@ -0,0 +1 @@ +export * from './ARAgingSummaryPdfDialog'; \ No newline at end of file diff --git a/packages/webapp/src/containers/FinancialStatements/BalanceSheet/BalanceSheet.tsx b/packages/webapp/src/containers/FinancialStatements/BalanceSheet/BalanceSheet.tsx index 787c7f14e..11928622f 100644 --- a/packages/webapp/src/containers/FinancialStatements/BalanceSheet/BalanceSheet.tsx +++ b/packages/webapp/src/containers/FinancialStatements/BalanceSheet/BalanceSheet.tsx @@ -13,6 +13,7 @@ import { useBalanceSheetQuery } from './utils'; import { compose } from '@/utils'; import withBalanceSheetActions from './withBalanceSheetActions'; +import { BalanceSheetDialogs } from './BalanceSheetDialogs'; /** * Balance sheet. @@ -67,6 +68,8 @@ function BalanceSheet({ + + ); } diff --git a/packages/webapp/src/containers/FinancialStatements/BalanceSheet/BalanceSheetActionsBar.tsx b/packages/webapp/src/containers/FinancialStatements/BalanceSheet/BalanceSheetActionsBar.tsx index 0421ea2ae..75d1a3236 100644 --- a/packages/webapp/src/containers/FinancialStatements/BalanceSheet/BalanceSheetActionsBar.tsx +++ b/packages/webapp/src/containers/FinancialStatements/BalanceSheet/BalanceSheetActionsBar.tsx @@ -17,7 +17,9 @@ import { BalanceSheetExportMenu } from './components'; import { useBalanceSheetContext } from './BalanceSheetProvider'; import withBalanceSheet from './withBalanceSheet'; import withBalanceSheetActions from './withBalanceSheetActions'; +import withDialogActions from '@/containers/Dialog/withDialogActions'; import { compose, saveInvoke } from '@/utils'; +import { DialogsName } from '@/constants/dialogs'; /** * Balance sheet - actions bar. @@ -29,6 +31,9 @@ function BalanceSheetActionsBar({ // #withBalanceSheetActions toggleBalanceSheetFilterDrawer: toggleFilterDrawer, + // #withDialogsActions + openDialog, + // #ownProps numberFormat, onNumberFormatSubmit, @@ -50,6 +55,11 @@ function BalanceSheetActionsBar({ saveInvoke(onNumberFormatSubmit, values); }; + // Handles the pdf print button click. + const handlePdfPrintBtnSubmit = () => { + openDialog(DialogsName.BalanceSheetPdfPreview) + } + return ( @@ -75,7 +85,6 @@ function BalanceSheetActionsBar({ active={balanceSheetDrawerFilter} /> - -