mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-16 04:40:32 +00:00
Merge pull request #870 from bigcapitalhq/report-pdf-template
fix: reports pdf template
This commit is contained in:
@@ -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);
|
||||
};
|
||||
|
||||
@@ -21,6 +21,7 @@ export class APAgingSummaryPdfInjectable {
|
||||
|
||||
return this.tableSheetPdf.convertToPdf(
|
||||
table.table,
|
||||
table.meta.organizationName,
|
||||
table.meta.sheetName,
|
||||
table.meta.formattedAsDate,
|
||||
HtmlTableCss,
|
||||
|
||||
@@ -21,6 +21,7 @@ export class ARAgingSummaryPdfInjectable {
|
||||
|
||||
return this.tableSheetPdf.convertToPdf(
|
||||
table.table,
|
||||
table.meta.organizationName,
|
||||
table.meta.sheetName,
|
||||
table.meta.formattedDateRange,
|
||||
HtmlTableCss,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -22,6 +22,7 @@ export class CashflowTablePdfInjectable {
|
||||
|
||||
return this.tableSheetPdf.convertToPdf(
|
||||
table.table,
|
||||
table.meta.organizationName,
|
||||
table.meta.sheetName,
|
||||
table.meta.formattedDateRange,
|
||||
HtmlTableCustomCss,
|
||||
|
||||
@@ -21,6 +21,7 @@ export class CustomerBalanceSummaryPdf {
|
||||
|
||||
return this.tableSheetPdf.convertToPdf(
|
||||
table.table,
|
||||
table.meta.organizationName,
|
||||
table.meta.sheetName,
|
||||
table.meta.formattedDateRange,
|
||||
HtmlTableCustomCss,
|
||||
|
||||
@@ -21,6 +21,7 @@ export class GeneralLedgerPdf {
|
||||
|
||||
return this.tableSheetPdf.convertToPdf(
|
||||
table.table,
|
||||
table.meta.organizationName,
|
||||
table.meta.sheetName,
|
||||
table.meta.formattedDateRange,
|
||||
HtmlTableCustomCss,
|
||||
|
||||
@@ -26,6 +26,7 @@ export class InventoryDetailsTablePdf {
|
||||
|
||||
return this.tableSheetPdf.convertToPdf(
|
||||
table.table,
|
||||
table.meta.organizationName,
|
||||
table.meta.sheetName,
|
||||
table.meta.formattedDateRange,
|
||||
HtmlTableCustomCss,
|
||||
|
||||
@@ -22,6 +22,7 @@ export class InventoryValuationSheetPdf {
|
||||
|
||||
return this.tableSheetPdf.convertToPdf(
|
||||
table.table,
|
||||
table.meta.organizationName,
|
||||
table.meta.sheetName,
|
||||
table.meta.formattedDateRange,
|
||||
HtmlTableCustomCss,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -21,6 +21,7 @@ export class ProfitLossTablePdfInjectable {
|
||||
|
||||
return this.tableSheetPdf.convertToPdf(
|
||||
table.table,
|
||||
table.meta.organizationName,
|
||||
table.meta.sheetName,
|
||||
table.meta.formattedDateRange,
|
||||
HtmlTableCustomCss,
|
||||
|
||||
@@ -23,6 +23,7 @@ export class PurchasesByItemsPdf {
|
||||
|
||||
return this.tableSheetPdf.convertToPdf(
|
||||
table.table,
|
||||
table.meta.organizationName,
|
||||
table.meta.sheetName,
|
||||
table.meta.formattedDateRange,
|
||||
HtmlTableCustomCss,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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';
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import {
|
||||
FinancialSheetTemplate,
|
||||
FinancialSheetTemplateProps,
|
||||
} from '../components/FinancialSheetTemplate';
|
||||
import { renderSSR } from './render-ssr';
|
||||
|
||||
export const renderFinancialSheetTemplateHtml = (
|
||||
props: FinancialSheetTemplateProps
|
||||
) => {
|
||||
return renderSSR(
|
||||
<FinancialSheetTemplate {...props} />
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user