fix: reports pdf template

This commit is contained in:
Ahmed Bouhuolia
2025-12-12 23:38:48 +02:00
parent 736f2c4109
commit 3cfb5cdde8
23 changed files with 173 additions and 42 deletions

View File

@@ -3,29 +3,30 @@ import { ITableColumn, ITableData, ITableRow } from '../types/Table.types';
import { FinancialTableStructure } from './FinancialTableStructure';
import { tableClassNames } from '../utils';
import { Injectable } from '@nestjs/common';
import { TemplateInjectable } from '../../TemplateInjectable/TemplateInjectable.service';
import { ChromiumlyTenancy } from '../../ChromiumlyTenancy/ChromiumlyTenancy.service';
import { renderFinancialSheetTemplateHtml } from '@bigcapital/pdf-templates';
@Injectable()
export class TableSheetPdf {
/**
* @param {TemplateInjectable} templateInjectable - The template injectable service.
* @param {ChromiumlyTenancy} chromiumlyTenancy - The chromiumly tenancy service.
*/
constructor(
private readonly templateInjectable: TemplateInjectable,
private readonly chromiumlyTenancy: ChromiumlyTenancy,
) {}
) { }
/**
* Converts the table data into a PDF format.
* @param {ITableData} table - The table data to be converted.
* @param {string} organizationName - The organization name.
* @param {string} sheetName - The name of the sheet.
* @param {string} sheetDate - The date of the sheet.
* @param {string} customCSS - Optional custom CSS to inject.
* @returns A promise that resolves with the PDF conversion result.
*/
public async convertToPdf(
table: ITableData,
organizationName: string,
sheetName: string,
sheetDate: string,
customCSS?: string,
@@ -33,19 +34,26 @@ export class TableSheetPdf {
// 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(
'financial-sheet',
{
table: { rows, columns },
sheetName,
sheetDate,
customCSS,
// Generate HTML content from the React template
const htmlContent = renderFinancialSheetTemplateHtml({
organizationName,
sheetName,
sheetDate,
table: {
columns: columns.map((col) => ({
key: col.key,
label: col.label,
style: (col as any).style, // style may be added during transformation
})),
rows: rows.map((row) => ({
cells: row.cells,
classNames: (row as any).classNames,
})),
},
);
customCSS,
});
// Convert the HTML content to PDF
return this.chromiumlyTenancy.convertHtmlContent(htmlContent, {
margins: { top: 0, bottom: 0, left: 0, right: 0 },
@@ -74,7 +82,6 @@ export class TableSheetPdf {
const flatNestedTree = curriedFlatNestedTree(R.__, {
nestedPrefix: '<span style="padding-left: 15px;"></span>',
});
// @ts-ignore
return R.compose(tableClassNames, flatNestedTree)(rows);
};

View File

@@ -21,6 +21,7 @@ export class APAgingSummaryPdfInjectable {
return this.tableSheetPdf.convertToPdf(
table.table,
table.meta.organizationName,
table.meta.sheetName,
table.meta.formattedAsDate,
HtmlTableCss,

View File

@@ -21,6 +21,7 @@ export class ARAgingSummaryPdfInjectable {
return this.tableSheetPdf.convertToPdf(
table.table,
table.meta.organizationName,
table.meta.sheetName,
table.meta.formattedDateRange,
HtmlTableCss,

View File

@@ -9,7 +9,7 @@ export class BalanceSheetPdfInjectable {
constructor(
private readonly balanceSheetTable: BalanceSheetTableInjectable,
private readonly tableSheetPdf: TableSheetPdf,
) {}
) { }
/**
* Converts the given balance sheet table to pdf.
@@ -21,6 +21,7 @@ export class BalanceSheetPdfInjectable {
return this.tableSheetPdf.convertToPdf(
table.table,
table.meta.organizationName,
table.meta.sheetName,
table.meta.formattedDateRange,
HtmlTableCustomCss,

View File

@@ -22,6 +22,7 @@ export class CashflowTablePdfInjectable {
return this.tableSheetPdf.convertToPdf(
table.table,
table.meta.organizationName,
table.meta.sheetName,
table.meta.formattedDateRange,
HtmlTableCustomCss,

View File

@@ -21,6 +21,7 @@ export class CustomerBalanceSummaryPdf {
return this.tableSheetPdf.convertToPdf(
table.table,
table.meta.organizationName,
table.meta.sheetName,
table.meta.formattedDateRange,
HtmlTableCustomCss,

View File

@@ -21,6 +21,7 @@ export class GeneralLedgerPdf {
return this.tableSheetPdf.convertToPdf(
table.table,
table.meta.organizationName,
table.meta.sheetName,
table.meta.formattedDateRange,
HtmlTableCustomCss,

View File

@@ -26,6 +26,7 @@ export class InventoryDetailsTablePdf {
return this.tableSheetPdf.convertToPdf(
table.table,
table.meta.organizationName,
table.meta.sheetName,
table.meta.formattedDateRange,
HtmlTableCustomCss,

View File

@@ -22,6 +22,7 @@ export class InventoryValuationSheetPdf {
return this.tableSheetPdf.convertToPdf(
table.table,
table.meta.organizationName,
table.meta.sheetName,
table.meta.formattedDateRange,
HtmlTableCustomCss,

View File

@@ -9,7 +9,7 @@ export class JournalSheetPdfInjectable {
constructor(
private readonly journalSheetTable: JournalSheetTableInjectable,
private readonly tableSheetPdf: TableSheetPdf,
) {}
) { }
/**
* Converts the given journal sheet table to pdf.
@@ -22,6 +22,7 @@ export class JournalSheetPdfInjectable {
return this.tableSheetPdf.convertToPdf(
table.table,
table.meta.organizationName,
table.meta.sheetName,
table.meta.formattedDateRange,
HtmlTableCustomCss,

View File

@@ -21,6 +21,7 @@ export class ProfitLossTablePdfInjectable {
return this.tableSheetPdf.convertToPdf(
table.table,
table.meta.organizationName,
table.meta.sheetName,
table.meta.formattedDateRange,
HtmlTableCustomCss,

View File

@@ -23,6 +23,7 @@ export class PurchasesByItemsPdf {
return this.tableSheetPdf.convertToPdf(
table.table,
table.meta.organizationName,
table.meta.sheetName,
table.meta.formattedDateRange,
HtmlTableCustomCss,

View File

@@ -9,7 +9,7 @@ export class SalesByItemsPdfInjectable {
constructor(
private readonly salesByItemsTable: SalesByItemsTableInjectable,
private readonly tableSheetPdf: TableSheetPdf,
) {}
) { }
/**
* Retrieves the sales by items sheet in pdf format.
@@ -23,6 +23,7 @@ export class SalesByItemsPdfInjectable {
return this.tableSheetPdf.convertToPdf(
table.table,
table.meta.organizationName,
table.meta.sheetName,
table.meta.formattedDateRange,
HtmlTableCustomCss,

View File

@@ -8,7 +8,7 @@ export class SalesTaxLiabiltiySummaryPdf {
constructor(
private readonly salesTaxLiabiltiySummaryTable: SalesTaxLiabilitySummaryTableInjectable,
private readonly tableSheetPdf: TableSheetPdf,
) {}
) { }
/**
* Converts the given sales tax liability summary table to pdf.
@@ -21,6 +21,7 @@ export class SalesTaxLiabiltiySummaryPdf {
);
return this.tableSheetPdf.convertToPdf(
table.table,
table.meta.organizationName,
table.meta.sheetName,
table.meta.formattedDateRange,
);

View File

@@ -6,7 +6,7 @@ export class TransactionsByCustomersPdf {
constructor(
private readonly transactionsByCustomersTable: TransactionsByCustomersTableInjectable,
private readonly tableSheetPdf: TableSheetPdf,
) {}
) { }
/**
* Retrieves the transactions by customers in PDF format.
@@ -18,6 +18,7 @@ export class TransactionsByCustomersPdf {
return this.tableSheetPdf.convertToPdf(
table.table,
table.meta.organizationName,
table.meta.sheetName,
table.meta.formattedDateRange,
);

View File

@@ -9,7 +9,7 @@ export class TransactionsByVendorsPdf {
constructor(
private readonly transactionsByVendorTable: TransactionsByVendorTableInjectable,
private readonly tableSheetPdf: TableSheetPdf,
) {}
) { }
/**
* Converts the given balance sheet table to pdf.
@@ -21,6 +21,7 @@ export class TransactionsByVendorsPdf {
return this.tableSheetPdf.convertToPdf(
table.table,
table.meta.organizationName,
table.meta.sheetName,
table.meta.formattedDateRange,
HtmlTableCustomCss,

View File

@@ -9,7 +9,7 @@ export class TrialBalanceSheetPdfInjectable {
constructor(
private readonly trialBalanceSheetTable: TrialBalanceSheetTableInjectable,
private readonly tableSheetPdf: TableSheetPdf,
) {}
) { }
/**
* Converts the given trial balance sheet table to pdf.
@@ -21,6 +21,7 @@ export class TrialBalanceSheetPdfInjectable {
return this.tableSheetPdf.convertToPdf(
table.table,
table.meta.organizationName,
table.meta.sheetName,
table.meta.formattedDateRange,
HtmlTableCustomCss,

View File

@@ -9,7 +9,7 @@ export class VendorBalanceSummaryPdf {
constructor(
private readonly vendorBalanceSummaryTable: VendorBalanceSummaryTableInjectable,
private readonly tableSheetPdf: TableSheetPdf,
) {}
) { }
/**
* Retrieves the sales by items sheet in pdf format.
@@ -23,6 +23,7 @@ export class VendorBalanceSummaryPdf {
return this.tableSheetPdf.convertToPdf(
table.table,
table.meta.organizationName,
table.meta.sheetName,
table.meta.formattedAsDate,
HtmlTableCustomCss,

View File

@@ -10,7 +10,7 @@ import { useBalanceSheetContext } from '../../BalanceSheetProvider';
export default function BalanceSheetPdfDialogContent() {
const { httpQuery } = useBalanceSheetContext();
const { isLoading, pdfUrl } = useBalanceSheetPdf({ ...httpQuery });
const { isLoading, isLoaded, pdfUrl } = useBalanceSheetPdf({ ...httpQuery });
return (
<DialogContent>
@@ -18,8 +18,10 @@ export default function BalanceSheetPdfDialogContent() {
<AnchorButton
href={pdfUrl}
target={'__blank'}
minimal={true}
outlined={true}
disabled={!isLoaded}
small
minimal
outlined
>
<T id={'pdf_preview.preview.button'} />
</AnchorButton>
@@ -27,8 +29,11 @@ export default function BalanceSheetPdfDialogContent() {
<AnchorButton
href={pdfUrl}
download={'invoice.pdf'}
minimal={true}
outlined={true}
disabled={!isLoaded}
small
minimal
outlined
>
<T id={'pdf_preview.download.button'} />
</AnchorButton>

View File

@@ -234,22 +234,12 @@ html[lang^='ar'] {
.dialog__header-actions {
position: absolute;
right: 50px;
right: 44px;
top: 0;
z-index: 9999999;
margin: 6px;
.bp4-button {
border-color: rgba(0, 0, 0, 0.25);
color: rgb(25, 32, 37);
min-height: 30px;
padding-left: 14px;
padding-right: 14px;
&+.bp4-button {
margin-left: 8px;
}
}
margin: 9px 6px 6px;
display: flex;
gap: 10px;
}
.bp4-dialog {

View File

@@ -0,0 +1,96 @@
import { x } from '@xstyled/emotion';
import { Box } from '../lib/layout/Box';
export interface TableColumn {
key: string;
label: string;
style?: string;
}
export interface TableCell {
key: string;
value: string;
}
export interface TableRow {
cells: TableCell[];
classNames?: string;
}
export interface FinancialSheetTemplateProps {
organizationName: string;
sheetName?: string;
sheetDate?: string;
table: {
columns: TableColumn[];
rows: TableRow[];
};
customCSS?: string;
}
export function FinancialSheetTemplate({
organizationName,
sheetName,
sheetDate,
table,
customCSS,
}: FinancialSheetTemplateProps) {
return (
<Box fontSize="14px">
<Box p="20px">
<Box textAlign="center" mb="1rem">
<Box m={0} fontSize="1.4rem">
{organizationName}
</Box>
{sheetName && <Box m={0}>{sheetName}</Box>}
{sheetDate && <Box mt="0.35rem">{sheetDate}</Box>}
</Box>
<x.table
borderTop="1px solid #000"
textAlign="left"
fontSize="inherit"
w="100%"
tableLayout="auto"
borderCollapse="collapse"
>
<x.thead>
<x.tr>
{table.columns.map((column) => (
<x.th
key={column.key}
color="#000"
borderBottom="1px solid #000000"
p="0.5rem"
className={`column--${column.key}`}
>
{column.label}
</x.th>
))}
</x.tr>
</x.thead>
<x.tbody>
{table.rows.map((row, rowIndex) => (
<x.tr key={rowIndex} className={row.classNames}>
{row.cells.map((cell) => (
<x.td
key={cell.key}
pt="0.28rem"
pb="0.28rem"
pl="0.5rem"
pr="0.5rem"
color="#252A31"
borderBottom="1px solid transparent"
className={`cell--${cell.key}`}
>
<span dangerouslySetInnerHTML={{ __html: cell.value }} />
</x.td>
))}
</x.tr>
))}
</x.tbody>
</x.table>
</Box>
</Box>
);
}

View File

@@ -3,8 +3,10 @@ export * from './components/InvoicePaperTemplate';
export * from './components/EstimatePaperTemplate';
export * from './components/ReceiptPaperTemplate';
export * from './components/PaymentReceivedPaperTemplate';
export * from './components/FinancialSheetTemplate';
export * from './renders/render-invoice-paper-template';
export * from './renders/render-estimate-paper-template';
export * from './renders/render-receipt-paper-template';
export * from './renders/render-payment-received-paper-template';
export * from './renders/render-financial-sheet-template';

View File

@@ -0,0 +1,14 @@
import {
FinancialSheetTemplate,
FinancialSheetTemplateProps,
} from '../components/FinancialSheetTemplate';
import { renderSSR } from './render-ssr';
export const renderFinancialSheetTemplateHtml = (
props: FinancialSheetTemplateProps
) => {
return renderSSR(
<FinancialSheetTemplate {...props} />
);
};