feat: rendering pdf templates on the server-side

This commit is contained in:
Ahmed Bouhuolia
2024-09-17 13:53:57 +02:00
parent 4f59b27d70
commit 2c790427fa
44 changed files with 1833 additions and 363 deletions

View File

@@ -2,9 +2,16 @@ import { Inject, Service } from 'typedi';
import { ChromiumlyTenancy } from '@/services/ChromiumlyTenancy/ChromiumlyTenancy';
import { TemplateInjectable } from '@/services/TemplateInjectable/TemplateInjectable';
import { GetPaymentReceived } from './GetPaymentReceived';
import HasTenancyService from '@/services/Tenancy/TenancyService';
import { PaymentReceivedBrandingTemplate } from './PaymentReceivedBrandingTemplate';
import { transformPaymentReceivedToPdfTemplate } from './utils';
import { PaymentReceivedPdfTemplateAttributes } from '@/interfaces';
@Service()
export default class GetPaymentReceivedPdf {
@Inject()
private tenancy: HasTenancyService;
@Inject()
private chromiumlyTenancy: ChromiumlyTenancy;
@@ -14,6 +21,9 @@ export default class GetPaymentReceivedPdf {
@Inject()
private getPaymentService: GetPaymentReceived;
@Inject()
private paymentBrandingTemplateService: PaymentReceivedBrandingTemplate;
/**
* Retrieve sale invoice pdf content.
* @param {number} tenantId -
@@ -24,19 +34,52 @@ export default class GetPaymentReceivedPdf {
tenantId: number,
paymentReceiveId: number
): Promise<Buffer> {
const paymentReceive = await this.getPaymentService.getPaymentReceive(
const brandingAttributes = await this.getPaymentBrandingAttributes(
tenantId,
paymentReceiveId
);
const htmlContent = await this.templateInjectable.render(
tenantId,
'modules/payment-receive-standard',
{
paymentReceive,
}
brandingAttributes
);
return this.chromiumlyTenancy.convertHtmlContent(tenantId, htmlContent, {
margins: { top: 0, bottom: 0, left: 0, right: 0 },
});
// Converts the given html content to pdf document.
return this.chromiumlyTenancy.convertHtmlContent(tenantId, htmlContent);
}
/**
* Retrieves the given payment received branding attributes.
* @param {number} tenantId
* @param {number} paymentReceivedId
* @returns {Promise<PaymentReceivedPdfTemplateAttributes>}
*/
async getPaymentBrandingAttributes(
tenantId: number,
paymentReceivedId: number
): Promise<PaymentReceivedPdfTemplateAttributes> {
const { PdfTemplate } = this.tenancy.models(tenantId);
const paymentReceived = await this.getPaymentService.getPaymentReceive(
tenantId,
paymentReceivedId
);
const templateId =
paymentReceived?.pdfTemplateId ??
(
await PdfTemplate.query().findOne({
resource: 'PaymentReceive',
default: true,
})
)?.id;
const brandingTemplate =
await this.paymentBrandingTemplateService.getPaymentReceivedPdfTemplate(
tenantId,
templateId
);
return {
...brandingTemplate.attributes,
...transformPaymentReceivedToPdfTemplate(paymentReceived),
};
}
}

View File

@@ -0,0 +1,35 @@
import { GetPdfTemplate } from '@/services/PdfTemplate/GetPdfTemplate';
import { Inject, Service } from 'typedi';
import { mergePdfTemplateWithDefaultAttributes } from '../Invoices/utils';
import { defaultPaymentReceivedPdfTemplateAttributes } from './constants';
import { PdfTemplate } from '@/models/PdfTemplate';
@Service()
export class PaymentReceivedBrandingTemplate {
@Inject()
private getPdfTemplateService: GetPdfTemplate;
/**
* Retrieves the payment received pdf template.
* @param {number} tenantId
* @param {number} paymentTemplateId
* @returns
*/
public async getPaymentReceivedPdfTemplate(
tenantId: number,
paymentTemplateId: number
): Promise<PdfTemplate> {
const template = await this.getPdfTemplateService.getPdfTemplate(
tenantId,
paymentTemplateId
);
const attributes = mergePdfTemplateWithDefaultAttributes(
template.attributes,
defaultPaymentReceivedPdfTemplateAttributes
);
return {
...template,
attributes,
};
}
}

View File

@@ -1,6 +1,7 @@
import * as R from 'ramda';
import { Inject, Service } from 'typedi';
import { omit, sumBy } from 'lodash';
import composeAsync from 'async/compose';
import {
ICustomer,
IPaymentReceived,
@@ -12,6 +13,7 @@ import { PaymentReceivedIncrement } from './PaymentReceivedIncrement';
import { BranchTransactionDTOTransform } from '@/services/Branches/Integrations/BranchTransactionDTOTransform';
import { formatDateFields } from '@/utils';
import { assocItemEntriesDefaultIndex } from '@/services/Items/utils';
import { BrandingTemplateDTOTransformer } from '@/services/PdfTemplate/BrandingTemplateDTOTransformer';
@Service()
export class PaymentReceiveDTOTransformer {
@@ -24,6 +26,9 @@ export class PaymentReceiveDTOTransformer {
@Inject()
private branchDTOTransform: BranchTransactionDTOTransform;
@Inject()
private brandingTemplatesTransformer: BrandingTemplateDTOTransformer;
/**
* Transformes the create payment receive DTO to model object.
* @param {number} tenantId
@@ -68,8 +73,16 @@ export class PaymentReceiveDTOTransformer {
exchangeRate: paymentReceiveDTO.exchangeRate || 1,
entries,
};
const initialAsyncDTO = await composeAsync(
// Assigns the default branding template id to the invoice DTO.
this.brandingTemplatesTransformer.assocDefaultBrandingTemplate(
tenantId,
'SaleInvoice'
)
)(initialDTO);
return R.compose(
this.branchDTOTransform.transformDTO<IPaymentReceived>(tenantId)
)(initialDTO);
)(initialAsyncDTO);
}
}

View File

@@ -45,3 +45,53 @@ export const PaymentsReceiveSampleData = [
'Payment Amount': 850,
},
];
export const defaultPaymentReceivedPdfTemplateAttributes = {
primaryColor: '#000',
secondaryColor: '#000',
showCompanyLogo: true,
companyLogo: '',
companyName: 'Bigcapital Technology, Inc.',
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,
showBillingToAddress: true,
billedToLabel: 'Billed To',
total: '$1000.00',
totalLabel: 'Total',
showTotal: true,
subtotal: '1000/00',
subtotalLabel: 'Subtotal',
showSubtotal: true,
lines: [
{
invoiceNumber: 'INV-00001',
invoiceAmount: '$1000.00',
paidAmount: '$1000.00',
},
],
showPaymentReceivedNumber: true,
paymentReceivedNumberLabel: 'Payment Number',
paymentReceivedNumebr: '346D3D40-0001',
paymentReceivedDate: 'September 3, 2024',
showPaymentReceivedDate: true,
paymentReceivedDateLabel: 'Payment Date',
};

View File

@@ -0,0 +1,12 @@
import {
IPaymentReceived,
PaymentReceivedPdfTemplateAttributes,
} from '@/interfaces';
export const transformPaymentReceivedToPdfTemplate = (
payment: IPaymentReceived
): Partial<PaymentReceivedPdfTemplateAttributes> => {
return {
// ...payment
};
};