feat: add adjustment total in estimates, invoices, and receipts pdf templates

This commit is contained in:
Ahmed Bouhuolia
2024-12-03 23:37:55 +02:00
parent 3a19518440
commit fabc88c81a
12 changed files with 91 additions and 33 deletions

View File

@@ -1,14 +1,12 @@
import { Inject, Service } from 'typedi';
import { ChromiumlyTenancy } from '@/services/ChromiumlyTenancy/ChromiumlyTenancy';
import { TemplateInjectable } from '@/services/TemplateInjectable/TemplateInjectable';
import { GetSaleEstimate } from './GetSaleEstimate';
import HasTenancyService from '@/services/Tenancy/TenancyService';
import { SaleEstimatePdfTemplate } from '../Invoices/SaleEstimatePdfTemplate';
import { transformEstimateToPdfTemplate } from './utils';
import { EstimatePdfBrandingAttributes } from './constants';
import events from '@/subscribers/events';
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
import { renderEstimatePaperTemplateHtml } from '@bigcapital/pdf-templates';
import { renderEstimatePaperTemplateHtml, EstimatePaperTemplateProps } from '@bigcapital/pdf-templates';
@Service()
export class SaleEstimatesPdf {
@@ -97,7 +95,7 @@ export class SaleEstimatesPdf {
async getEstimateBrandingAttributes(
tenantId: number,
estimateId: number
): Promise<EstimatePdfBrandingAttributes> {
): Promise<EstimatePaperTemplateProps> {
const { PdfTemplate } = this.tenancy.models(tenantId);
const saleEstimate = await this.getSaleEstimate.getEstimate(
tenantId,

View File

@@ -1,9 +1,9 @@
import { EstimatePaperTemplateProps } from '@bigcapital/pdf-templates';
import { contactAddressTextFormat } from '@/utils/address-text-format';
import { EstimatePdfBrandingAttributes } from './constants';
export const transformEstimateToPdfTemplate = (
estimate
): Partial<EstimatePdfBrandingAttributes> => {
): Partial<EstimatePaperTemplateProps> => {
return {
expirationDate: estimate.formattedExpirationDate,
estimateNumebr: estimate.estimateNumber,
@@ -17,6 +17,7 @@ export const transformEstimateToPdfTemplate = (
})),
total: estimate.formattedSubtotal,
subtotal: estimate.formattedSubtotal,
adjustment: estimate.adjustmentFormatted,
customerNote: estimate.note,
termsConditions: estimate.termsConditions,
customerAddress: contactAddressTextFormat(estimate.customer),

View File

@@ -1,10 +1,12 @@
import { Inject, Service } from 'typedi';
import { renderInvoicePaperTemplateHtml } from '@bigcapital/pdf-templates';
import {
renderInvoicePaperTemplateHtml,
InvoicePaperTemplateProps,
} from '@bigcapital/pdf-templates';
import { ChromiumlyTenancy } from '@/services/ChromiumlyTenancy/ChromiumlyTenancy';
import { GetSaleInvoice } from './GetSaleInvoice';
import HasTenancyService from '@/services/Tenancy/TenancyService';
import { transformInvoiceToPdfTemplate } from './utils';
import { InvoicePdfTemplateAttributes } from '@/interfaces';
import { SaleInvoicePdfTemplate } from './SaleInvoicePdfTemplate';
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
import events from '@/subscribers/events';
@@ -100,7 +102,7 @@ export class SaleInvoicePdf {
async getInvoiceBrandingAttributes(
tenantId: number,
invoiceId: number
): Promise<InvoicePdfTemplateAttributes> {
): Promise<InvoicePaperTemplateProps> {
const { PdfTemplate } = this.tenancy.models(tenantId);
const invoice = await this.getInvoiceService.getSaleInvoice(

View File

@@ -1,6 +1,7 @@
import { pickBy } from 'lodash';
import { InvoicePdfTemplateAttributes, ISaleInvoice } from '@/interfaces';
import { ISaleInvoice } from '@/interfaces';
import { contactAddressTextFormat } from '@/utils/address-text-format';
import { InvoicePaperTemplateProps } from '@bigcapital/pdf-templates';
export const mergePdfTemplateWithDefaultAttributes = (
brandingTemplate?: Record<string, any>,
@@ -18,7 +19,7 @@ export const mergePdfTemplateWithDefaultAttributes = (
export const transformInvoiceToPdfTemplate = (
invoice: ISaleInvoice
): Partial<InvoicePdfTemplateAttributes> => {
): Partial<InvoicePaperTemplateProps> => {
return {
dueDate: invoice.dueDateFormatted,
dateIssue: invoice.invoiceDateFormatted,
@@ -29,6 +30,7 @@ export const transformInvoiceToPdfTemplate = (
paymentMade: invoice.paymentAmountFormatted,
dueAmount: invoice.dueAmountFormatted,
discount: invoice.discountAmountFormatted,
adjustment: invoice.adjustmentFormatted,
discountLabel: invoice.discountPercentageFormatted
? `Discount [${invoice.discountPercentageFormatted}]`
: 'Discount',

View File

@@ -1,13 +1,15 @@
import { Inject, Service } from 'typedi';
import { ChromiumlyTenancy } from '@/services/ChromiumlyTenancy/ChromiumlyTenancy';
import {
renderReceiptPaperTemplateHtml,
ReceiptPaperTemplateProps,
} from '@bigcapital/pdf-templates';
import { GetSaleReceipt } from './GetSaleReceipt';
import HasTenancyService from '@/services/Tenancy/TenancyService';
import { SaleReceiptBrandingTemplate } from './SaleReceiptBrandingTemplate';
import { transformReceiptToBrandingTemplateAttributes } from './utils';
import { ISaleReceiptBrandingTemplateAttributes } from '@/interfaces';
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
import events from '@/subscribers/events';
import { renderReceiptPaperTemplateHtml } from '@bigcapital/pdf-templates';
@Service()
export class SaleReceiptsPdf {
@@ -90,12 +92,12 @@ export class SaleReceiptsPdf {
* Retrieves receipt branding attributes.
* @param {number} tenantId
* @param {number} receiptId
* @returns {Promise<ISaleReceiptBrandingTemplateAttributes>}
* @returns {Promise<ReceiptPaperTemplateProps>}
*/
public async getReceiptBrandingAttributes(
tenantId: number,
receiptId: number
): Promise<ISaleReceiptBrandingTemplateAttributes> {
): Promise<ReceiptPaperTemplateProps> {
const { PdfTemplate } = this.tenancy.models(tenantId);
const saleReceipt = await this.getSaleReceiptService.getSaleReceipt(

View File

@@ -1,12 +1,10 @@
import {
ISaleReceipt,
ISaleReceiptBrandingTemplateAttributes,
} from '@/interfaces';
import { ISaleReceipt } from '@/interfaces';
import { contactAddressTextFormat } from '@/utils/address-text-format';
import { ReceiptPaperTemplateProps } from '@bigcapital/pdf-templates';
export const transformReceiptToBrandingTemplateAttributes = (
saleReceipt: ISaleReceipt
): Partial<ISaleReceiptBrandingTemplateAttributes> => {
): Partial<ReceiptPaperTemplateProps> => {
return {
total: saleReceipt.totalFormatted,
subtotal: saleReceipt.subtotalFormatted,
@@ -23,6 +21,7 @@ export const transformReceiptToBrandingTemplateAttributes = (
discountLabel: saleReceipt.discountPercentageFormatted
? `Discount [${saleReceipt.discountPercentageFormatted}]`
: 'Discount',
adjustment: saleReceipt.adjustmentFormatted,
customerAddress: contactAddressTextFormat(saleReceipt.customer),
};
};

View File

@@ -239,6 +239,7 @@ export const useJournalTotals = () => {
const totalDebit = safeSumBy(entries, 'debit');
const total = Math.max(totalCredit, totalDebit);
// Retrieves the formatted total money.
const formattedTotal = React.useMemo(
() => formattedAmount(total, currencyCode),

View File

@@ -9,7 +9,7 @@
},
"main": "./dist/components.umd.js",
"module": "./dist/components.es.js",
"types": "./dist/src/index.d.ts",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/src/index.d.ts",

View File

@@ -43,7 +43,7 @@ export interface EstimatePaperTemplateProps extends PaperTemplateProps {
companyAddress?: string;
billedToLabel?: string;
// Totals
// Total
total?: string;
showTotal?: boolean;
totalLabel?: string;
@@ -53,6 +53,11 @@ export interface EstimatePaperTemplateProps extends PaperTemplateProps {
showDiscount?: boolean;
discountLabel?: string;
// # Adjustment
adjustment?: string;
showAdjustment?: boolean;
adjustmentLabel?: string;
// # Subtotal
subtotal?: string;
showSubtotal?: boolean;
@@ -117,6 +122,11 @@ export function EstimatePaperTemplate({
subtotalLabel = 'Subtotal',
showSubtotal = true,
// # Adjustment
adjustment = '',
showAdjustment = true,
adjustmentLabel = 'Adjustment',
// # Customer Note
showCustomerNote = true,
customerNote = DefaultPdfTemplateStatement,
@@ -240,6 +250,12 @@ export function EstimatePaperTemplate({
amount={discount}
/>
)}
{showAdjustment && adjustment && (
<PaperTemplate.TotalLine
label={adjustmentLabel}
amount={adjustment}
/>
)}
{showTotal && (
<PaperTemplate.TotalLine label={totalLabel} amount={total} />
)}

View File

@@ -1,3 +1,4 @@
import { isEmpty } from 'lodash';
import {
PaperTemplate,
PaperTemplateProps,
@@ -33,17 +34,21 @@ export interface InvoicePaperTemplateProps extends PaperTemplateProps {
primaryColor?: string;
secondaryColor?: string;
// Company
showCompanyLogo?: boolean;
companyLogoUri?: string;
// Invoice number
showInvoiceNumber?: boolean;
invoiceNumber?: string;
invoiceNumberLabel?: string;
// Date of issue
showDateIssue?: boolean;
dateIssue?: string;
dateIssueLabel?: string;
// Due date
showDueDate?: boolean;
dueDate?: string;
dueDateLabel?: string;
@@ -66,7 +71,7 @@ export interface InvoicePaperTemplateProps extends PaperTemplateProps {
lineRateLabel?: string;
lineTotalLabel?: string;
// Totals
// Total
showTotal?: boolean;
totalLabel?: string;
total?: string;
@@ -76,11 +81,17 @@ export interface InvoicePaperTemplateProps extends PaperTemplateProps {
discountLabel?: string;
discount?: string;
// Adjustment
showAdjustment?: boolean;
adjustmentLabel?: string;
adjustment?: string;
// Subtotal
showSubtotal?: boolean;
subtotalLabel?: string;
subtotal?: string;
// Payment made
showPaymentMade?: boolean;
paymentMadeLabel?: string;
paymentMade?: string;
@@ -97,6 +108,7 @@ export interface InvoicePaperTemplateProps extends PaperTemplateProps {
showTermsConditions?: boolean;
termsConditions?: string;
// Statement
statementLabel?: string;
showStatement?: boolean;
statement?: string;
@@ -145,20 +157,24 @@ export function InvoicePaperTemplate({
totalLabel = 'Total',
subtotalLabel = 'Subtotal',
discountLabel = 'Discount',
adjustmentLabel = 'Adjustment',
paymentMadeLabel = 'Payment Made',
dueAmountLabel = 'Balance Due',
// Totals
showTotal = true,
total = '$662.75',
showSubtotal = true,
showDiscount = true,
showTaxes = true,
showPaymentMade = true,
showDueAmount = true,
showAdjustment = true,
total = '$662.75',
subtotal = '630.00',
discount = '0.00',
adjustment = '',
paymentMade = '100.00',
dueAmount = '$562.75',
@@ -243,17 +259,18 @@ export function InvoicePaperTemplate({
accessor: (data) => (
<Stack spacing={2}>
<Text>{data.item}</Text>
<Text
color={'#5f6b7c'}
fontSize={12}
>
<Text color={'#5f6b7c'} fontSize={12}>
{data.description}
</Text>
</Stack>
),
thStyle: { width: '60%' },
},
{ label: lineQuantityLabel, accessor: 'quantity', align: 'right' },
{
label: lineQuantityLabel,
accessor: 'quantity',
align: 'right',
},
{ label: lineRateLabel, accessor: 'rate', align: 'right' },
{ label: lineTotalLabel, accessor: 'total', align: 'right' },
]}
@@ -267,12 +284,18 @@ export function InvoicePaperTemplate({
border={PaperTemplateTotalBorder.Gray}
/>
)}
{showDiscount && (
{showDiscount && !isEmpty(discount) && (
<PaperTemplate.TotalLine
label={discountLabel}
amount={discount}
/>
)}
{showAdjustment && !isEmpty(adjustment) && (
<PaperTemplate.TotalLine
label={adjustmentLabel}
amount={adjustment}
/>
)}
{showTaxes && (
<>
{taxes.map((tax, index) => (

View File

@@ -39,6 +39,11 @@ export interface ReceiptPaperTemplateProps extends PaperTemplateProps {
showDiscount?: boolean;
discountLabel?: string;
// # Adjustment
adjustment?: string;
showAdjustment?: boolean;
adjustmentLabel?: string;
// Total
total?: string;
showTotal?: boolean;
@@ -111,6 +116,11 @@ export function ReceiptPaperTemplate({
discountLabel = 'Discount',
showDiscount = true,
// # Adjustment
adjustment = '',
adjustmentLabel = 'Adjustment',
showAdjustment = true,
// # Subtotal
subtotal = '1000/00',
subtotalLabel = 'Subtotal',
@@ -228,6 +238,12 @@ export function ReceiptPaperTemplate({
amount={discount}
/>
)}
{showAdjustment && adjustment && (
<PaperTemplate.TotalLine
label={adjustmentLabel}
amount={adjustment}
/>
)}
{showTotal && (
<PaperTemplate.TotalLine label={totalLabel} amount={total} />
)}

View File

@@ -8,8 +8,6 @@ export const renderInvoicePaperTemplateHtml = (
props: InvoicePaperTemplateProps
) => {
return renderSSR(
<InvoicePaperTemplate
{...props}
/>
<InvoicePaperTemplate {...props} />
);
};