mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-18 22:00:31 +00:00
feat: rendering pdf templates on the server-side
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
import { GetPdfTemplate } from '@/services/PdfTemplate/GetPdfTemplate';
|
||||
import { Inject, Service } from 'typedi';
|
||||
import { defaultSaleReceiptBrandingAttributes } from './constants';
|
||||
import { mergePdfTemplateWithDefaultAttributes } from '../Invoices/utils';
|
||||
|
||||
@Service()
|
||||
export class SaleReceiptBrandingTemplate {
|
||||
@Inject()
|
||||
private getPdfTemplateService: GetPdfTemplate;
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves the sale receipt branding template.
|
||||
* @param {number} tenantId - The ID of the tenant.
|
||||
* @param {number} templateId - The ID of the PDF template.
|
||||
* @returns {Promise<Object>} The sale receipt branding template with merged attributes.
|
||||
*/
|
||||
public async getSaleReceiptBrandingTemplate(
|
||||
tenantId: number,
|
||||
templateId: number
|
||||
) {
|
||||
const template = await this.getPdfTemplateService.getPdfTemplate(
|
||||
tenantId,
|
||||
templateId
|
||||
);
|
||||
const attributes = mergePdfTemplateWithDefaultAttributes(
|
||||
template.attributes,
|
||||
defaultSaleReceiptBrandingAttributes
|
||||
);
|
||||
return {
|
||||
...template,
|
||||
attributes,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import { formatDateFields } from '@/utils';
|
||||
import { SaleReceiptIncrement } from './SaleReceiptIncrement';
|
||||
import { ItemEntry } from '@/models';
|
||||
import { assocItemEntriesDefaultIndex } from '@/services/Items/utils';
|
||||
import { BrandingTemplateDTOTransformer } from '@/services/PdfTemplate/BrandingTemplateDTOTransformer';
|
||||
|
||||
@Service()
|
||||
export class SaleReceiptDTOTransformer {
|
||||
@@ -30,6 +31,9 @@ export class SaleReceiptDTOTransformer {
|
||||
@Inject()
|
||||
private receiptIncrement: SaleReceiptIncrement;
|
||||
|
||||
@Inject()
|
||||
private brandingTemplatesTransformer: BrandingTemplateDTOTransformer;
|
||||
|
||||
/**
|
||||
* Transform create DTO object to model object.
|
||||
* @param {ISaleReceiptDTO} saleReceiptDTO -
|
||||
@@ -88,9 +92,17 @@ export class SaleReceiptDTOTransformer {
|
||||
}),
|
||||
entries,
|
||||
};
|
||||
const initialAsyncDTO = await composeAsync(
|
||||
// Assigns the default branding template id to the invoice DTO.
|
||||
this.brandingTemplatesTransformer.assocDefaultBrandingTemplate(
|
||||
tenantId,
|
||||
'SaleReceipt'
|
||||
)
|
||||
)(initialDTO);
|
||||
|
||||
return R.compose(
|
||||
this.branchDTOTransform.transformDTO<ISaleReceipt>(tenantId),
|
||||
this.warehouseDTOTransform.transformDTO<ISaleReceipt>(tenantId)
|
||||
)(initialDTO);
|
||||
)(initialAsyncDTO);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,15 @@ import { Inject, Service } from 'typedi';
|
||||
import { TemplateInjectable } from '@/services/TemplateInjectable/TemplateInjectable';
|
||||
import { ChromiumlyTenancy } from '@/services/ChromiumlyTenancy/ChromiumlyTenancy';
|
||||
import { GetSaleReceipt } from './GetSaleReceipt';
|
||||
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
||||
import { SaleReceiptBrandingTemplate } from './SaleReceiptBrandingTemplate';
|
||||
import { transformReceiptToBrandingTemplateAttributes } from './utils';
|
||||
|
||||
@Service()
|
||||
export class SaleReceiptsPdf {
|
||||
@Inject()
|
||||
private tenancy: HasTenancyService;
|
||||
|
||||
@Inject()
|
||||
private chromiumlyTenancy: ChromiumlyTenancy;
|
||||
|
||||
@@ -14,26 +20,64 @@ export class SaleReceiptsPdf {
|
||||
@Inject()
|
||||
private getSaleReceiptService: GetSaleReceipt;
|
||||
|
||||
@Inject()
|
||||
private saleReceiptBrandingTemplate: SaleReceiptBrandingTemplate;
|
||||
|
||||
/**
|
||||
* Retrieves sale invoice pdf content.
|
||||
* @param {number} tenantId -
|
||||
* @param {number} tenantId -
|
||||
* @param {number} saleInvoiceId -
|
||||
* @returns {Promise<Buffer>}
|
||||
*/
|
||||
public async saleReceiptPdf(tenantId: number, saleReceiptId: number) {
|
||||
const saleReceipt = await this.getSaleReceiptService.getSaleReceipt(
|
||||
const brandingAttributes = await this.getReceiptBrandingAttributes(
|
||||
tenantId,
|
||||
saleReceiptId
|
||||
);
|
||||
console.log(brandingAttributes, 'attributes');
|
||||
|
||||
const htmlContent = await this.templateInjectable.render(
|
||||
tenantId,
|
||||
'modules/receipt-regular',
|
||||
{
|
||||
saleReceipt,
|
||||
}
|
||||
brandingAttributes
|
||||
);
|
||||
return this.chromiumlyTenancy.convertHtmlContent(tenantId, htmlContent, {
|
||||
margins: { top: 0, bottom: 0, left: 0, right: 0 },
|
||||
});
|
||||
return this.chromiumlyTenancy.convertHtmlContent(tenantId, htmlContent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves receipt branding attributes.
|
||||
* @param {number} tenantId
|
||||
* @param {number] receiptId
|
||||
* @returns
|
||||
*/
|
||||
public async getReceiptBrandingAttributes(
|
||||
tenantId: number,
|
||||
receiptId: number
|
||||
) {
|
||||
const { PdfTemplate } = this.tenancy.models(tenantId);
|
||||
|
||||
const saleReceipt = await this.getSaleReceiptService.getSaleReceipt(
|
||||
tenantId,
|
||||
receiptId
|
||||
);
|
||||
// Retrieve the invoice template id of not found get the default template id.
|
||||
const templateId =
|
||||
saleReceipt.pdfTemplateId ??
|
||||
(
|
||||
await PdfTemplate.query().findOne({
|
||||
resource: 'SaleReceipt',
|
||||
default: true,
|
||||
})
|
||||
)?.id;
|
||||
// Retrieves the receipt branding template.
|
||||
const brandingTemplate =
|
||||
await this.saleReceiptBrandingTemplate.getSaleReceiptBrandingTemplate(
|
||||
tenantId,
|
||||
templateId
|
||||
);
|
||||
return {
|
||||
...brandingTemplate.attributes,
|
||||
...transformReceiptToBrandingTemplateAttributes(saleReceipt),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ export const ERRORS = {
|
||||
SALE_RECEIPT_IS_ALREADY_CLOSED: 'SALE_RECEIPT_IS_ALREADY_CLOSED',
|
||||
SALE_RECEIPT_NO_IS_REQUIRED: 'SALE_RECEIPT_NO_IS_REQUIRED',
|
||||
CUSTOMER_HAS_SALES_INVOICES: 'CUSTOMER_HAS_SALES_INVOICES',
|
||||
NO_INVOICE_CUSTOMER_EMAIL_ADDR: 'NO_INVOICE_CUSTOMER_EMAIL_ADDR'
|
||||
NO_INVOICE_CUSTOMER_EMAIL_ADDR: 'NO_INVOICE_CUSTOMER_EMAIL_ADDR',
|
||||
};
|
||||
|
||||
export const DEFAULT_VIEW_COLUMNS = [];
|
||||
@@ -47,22 +47,84 @@ export const DEFAULT_VIEWS = [
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
export const SaleReceiptsSampleData = [
|
||||
{
|
||||
"Receipt Date": "2023-01-01",
|
||||
"Customer": "Randall Kohler",
|
||||
"Deposit Account": "Petty Cash",
|
||||
"Exchange Rate": "",
|
||||
"Receipt Number": "REC-00001",
|
||||
"Reference No.": "REF-0001",
|
||||
"Statement": "Delectus unde aut soluta et accusamus placeat.",
|
||||
"Receipt Message": "Vitae asperiores dicta.",
|
||||
"Closed": "T",
|
||||
"Item": "Schmitt Group",
|
||||
"Quantity": 100,
|
||||
"Rate": 200,
|
||||
"Line Description": "Distinctio distinctio sit veritatis consequatur iste quod veritatis."
|
||||
}
|
||||
|
||||
]
|
||||
'Receipt Date': '2023-01-01',
|
||||
Customer: 'Randall Kohler',
|
||||
'Deposit Account': 'Petty Cash',
|
||||
'Exchange Rate': '',
|
||||
'Receipt Number': 'REC-00001',
|
||||
'Reference No.': 'REF-0001',
|
||||
Statement: 'Delectus unde aut soluta et accusamus placeat.',
|
||||
'Receipt Message': 'Vitae asperiores dicta.',
|
||||
Closed: 'T',
|
||||
Item: 'Schmitt Group',
|
||||
Quantity: 100,
|
||||
Rate: 200,
|
||||
'Line Description':
|
||||
'Distinctio distinctio sit veritatis consequatur iste quod veritatis.',
|
||||
},
|
||||
];
|
||||
|
||||
export const defaultSaleReceiptBrandingAttributes = {
|
||||
primaryColor: '',
|
||||
secondaryColor: '',
|
||||
showCompanyLogo: true,
|
||||
companyLogo: '',
|
||||
companyName: 'Bigcapital Technology, Inc.',
|
||||
|
||||
// # Address
|
||||
billedToAddress: [
|
||||
'Bigcapital Technology, Inc.',
|
||||
'131 Continental Dr Suite 305 Newark,',
|
||||
'Delaware 19713',
|
||||
'United States',
|
||||
'+1 762-339-5634',
|
||||
'ahmed@bigcapital.app',
|
||||
],
|
||||
billedFromAddress: [
|
||||
'131 Continental Dr Suite 305 Newark,',
|
||||
'Delaware 19713',
|
||||
'United States',
|
||||
'+1 762-339-5634',
|
||||
'ahmed@bigcapital.app',
|
||||
],
|
||||
showBilledFromAddress: true,
|
||||
showBilledToAddress: true,
|
||||
billedToLabel: 'Billed To',
|
||||
|
||||
total: '$1000.00',
|
||||
totalLabel: 'Total',
|
||||
showTotal: true,
|
||||
|
||||
subtotal: '1000/00',
|
||||
subtotalLabel: 'Subtotal',
|
||||
showSubtotal: true,
|
||||
|
||||
showCustomerNote: true,
|
||||
customerNote:
|
||||
'It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout.',
|
||||
customerNoteLabel: 'Customer Note',
|
||||
|
||||
showTermsConditions: true,
|
||||
termsConditions:
|
||||
'It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout.',
|
||||
termsConditionsLabel: 'Terms & Conditions',
|
||||
|
||||
lines: [
|
||||
{
|
||||
item: 'Simply dummy text',
|
||||
description: 'Simply dummy text of the printing and typesetting',
|
||||
rate: '1',
|
||||
quantity: '1000',
|
||||
total: '$1000.00',
|
||||
},
|
||||
],
|
||||
showReceiptNumber: true,
|
||||
receiptNumberLabel: 'Receipt Number',
|
||||
receiptNumebr: '346D3D40-0001',
|
||||
|
||||
receiptDate: 'September 3, 2024',
|
||||
showReceiptDate: true,
|
||||
receiptDateLabel: 'Receipt Date',
|
||||
};
|
||||
|
||||
6
packages/server/src/services/Sales/Receipts/utils.ts
Normal file
6
packages/server/src/services/Sales/Receipts/utils.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
|
||||
|
||||
export const transformReceiptToBrandingTemplateAttributes = () => {
|
||||
return {};
|
||||
}
|
||||
Reference in New Issue
Block a user