feat: Hook up customer/company address to pdf templates

This commit is contained in:
Ahmed Bouhuolia
2024-09-29 22:59:14 +02:00
parent 776b69475c
commit 863c7ad99f
29 changed files with 242 additions and 152 deletions

View File

@@ -150,17 +150,14 @@ block content
div(class=`${prefix}-terms-item__value`) #{creditNoteDate}
div(class=`${prefix}-address-section`)
if showBilledFromAddress
div(class=`${prefix}-address`)
strong #{companyName}
each address in billedFromAddress
div #{address}
if showCompanyAddress
div(class=`${prefix}-address-from`)
div !{companyAddress}
if showBilledToAddress
div(class=`${prefix}-address`)
if showCustomerAddress
div(class=`${prefix}-address-to`)
strong #{billedToLabel}
each address in billedToAddress
div #{address}
div !{customerAddress}
table(class=`${prefix}-table`)
thead

View File

@@ -156,17 +156,14 @@ block content
//- Addresses (Group section)
div(class=`${prefix}-addresses`)
if showBilledFromAddress
div(class=`${prefix}-address`)
strong #{companyName}
each item in billedFromAddress
div(class=`${prefix}-address__item`) #{item}
if showCompanyAddress
div(class=`${prefix}-address-from`)
div !{companyAddress}
if showBilledToAddress
div(class=`${prefix}-address`)
if showCustomerAddress
div(class=`${prefix}-address-to`)
strong #{billedToLabel}
each item in billedToAddress
div(class=`${prefix}-address__item`) #{item}
div !{customerAddress}
//- Table section (Line items)
table(class=`${prefix}-table`)

View File

@@ -173,6 +173,7 @@ block content
if showCustomerAddress
div(class=`${prefix}-address-to`)
strong #{billedToLabel}
div !{customerAddress}
//- Invoice table

View File

@@ -140,17 +140,14 @@ block content
div(class=`${prefix}-terms-item__value`) #{paymentReceivedDate}
div(class=`${prefix}-addresses`)
if showBilledFromAddress
div(class=`${prefix}-address`)
strong(class=`${prefix}-address__item`) #{companyName}
each addressLine in billedFromAddress
div(class=`${prefix}-address__item`) #{addressLine}
if showCompanyAddress
div(class=`${prefix}-address-from`)
div !{companyAddress}
if showBillingToAddress
div(class=`${prefix}-address`)
strong(class=`${prefix}-address__item`) #{billedToLabel}
each addressLine in billedToAddress
div(class=`${prefix}-address__item`) #{addressLine}
if showCustomerAddress
div(class=`${prefix}-address-to`)
strong #{billedToLabel}
div !{customerAddress}
table(class=`${prefix}-table`)
thead

View File

@@ -146,17 +146,14 @@ block content
//- Address Section
div(class=`${prefix}-address-section`)
if showBilledFromAddress
div(class=`${prefix}-address`)
strong= companyName
each addressLine in billedFromAddress
div= addressLine
if showCompanyAddress
div(class=`${prefix}-address-from`)
div !{companyAddress}
if showBilledToAddress
div(class=`${prefix}-address`)
strong= billedToLabel
each addressLine in billedToAddress
div= addressLine
if showCustomerAddress
div(class=`${prefix}-address-to`)
strong #{billedToLabel}
div !{customerAddress}
//- Table Section
table(class=`${prefix}-table`)

View File

@@ -262,16 +262,24 @@ export type ICreditNoteGLCommonEntry = Pick<
>;
export interface CreditNotePdfTemplateAttributes {
// # Primary color
primaryColor: string;
secondaryColor: string;
// # Company logo
showCompanyLogo: boolean;
companyLogo: string;
// # Company name
companyName: string;
billedToAddress: string[];
billedFromAddress: string[];
showBilledToAddress: boolean;
showBilledFromAddress: boolean;
// # Customer Address
showCustomerAddress: boolean;
customerAddress: string;
// # Company address
showCompanyAddress: boolean;
companyAddress: string;
billedToLabel: string;
total: string;

View File

@@ -207,10 +207,13 @@ export interface PaymentReceivedPdfTemplateAttributes {
companyLogo: string;
companyName: string;
billedToAddress: string[];
billedFromAddress: string[];
showBilledFromAddress: boolean;
showBillingToAddress: boolean;
// Customer Address
showCustomerAddress: boolean;
customerAddress: string;
// Company address
showCompanyAddress: boolean;
companyAddress: string;
billedToLabel: string;
total: string;

View File

@@ -294,8 +294,13 @@ export interface InvoicePdfTemplateAttributes {
invoiceNumber: string;
showInvoiceNumber: boolean;
showBillingToAddress: boolean;
showBilledFromAddress: boolean;
// Customer Address
showCustomerAddress: boolean;
customerAddress: string;
// Company address
showCompanyAddress: boolean;
companyAddress: string;
billedToLabel: string;
lineItemLabel: string;
@@ -333,7 +338,4 @@ export interface InvoicePdfTemplateAttributes {
statementLabel: string;
showStatement: boolean;
statement: string;
billedToAddress: string[];
billedFromAddres: string[];
}

View File

@@ -163,11 +163,13 @@ export interface ISaleReceiptBrandingTemplateAttributes {
companyLogo: string;
companyName: string;
// Address
billedToAddress: string[];
billedFromAddress: string[];
showBilledFromAddress: boolean;
showBilledToAddress: boolean;
// Customer Address
showCustomerAddress: boolean;
customerAddress: string;
// Company address
showCompanyAddress: boolean;
companyAddress: string;
billedToLabel: string;
// Total

View File

@@ -1,26 +1,44 @@
import { Inject } from "typedi";
import { GetPdfTemplate } from "../PdfTemplate/GetPdfTemplate";
import { defaultCreditNoteBrandingAttributes } from "./constants";
import { mergePdfTemplateWithDefaultAttributes } from "../Sales/Invoices/utils";
import { Inject } from 'typedi';
import { GetPdfTemplate } from '../PdfTemplate/GetPdfTemplate';
import { defaultCreditNoteBrandingAttributes } from './constants';
import { mergePdfTemplateWithDefaultAttributes } from '../Sales/Invoices/utils';
import { GetOrganizationBrandingAttributes } from '../PdfTemplate/GetOrganizationBrandingAttributes';
export class CreditNoteBrandingTemplate {
@Inject()
private getPdfTemplateService: GetPdfTemplate;
@Inject()
private getOrgBrandingAttributes: GetOrganizationBrandingAttributes;
/**
* Retrieves the credit note branding template.
* @param {number} tenantId
* @param {number} templateId
* @param {number} tenantId
* @param {number} templateId
* @returns {}
*/
public async getCreditNoteBrandingTemplate(tenantId: number, templateId: number) {
public async getCreditNoteBrandingTemplate(
tenantId: number,
templateId: number
) {
const template = await this.getPdfTemplateService.getPdfTemplate(
tenantId,
templateId
);
// Retrieves the organization branding attributes.
const commonOrgBrandingAttrs =
await this.getOrgBrandingAttributes.getOrganizationBrandingAttributes(
tenantId
);
// Merges the default branding attributes with common organization branding attrs.
const organizationBrandingAttrs = {
...defaultCreditNoteBrandingAttributes,
...commonOrgBrandingAttrs,
};
const attributes = mergePdfTemplateWithDefaultAttributes(
template.attributes,
defaultCreditNoteBrandingAttributes
organizationBrandingAttrs
);
return {
...template,

View File

@@ -34,8 +34,6 @@ export default class GetCreditNotePdf {
tenantId,
creditNoteId
);
console.log(brandingAttributes, 'brandingAttributes');
const htmlContent = await this.templateInjectable.render(
tenantId,
'modules/credit-note-standard',

View File

@@ -80,24 +80,13 @@ export const defaultCreditNoteBrandingAttributes = {
// # Company name
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',
],
showBilledToAddress: true,
showBilledFromAddress: true,
// # Customer address
showCustomerAddress: true,
customerAddress: '',
// # Company address
showCompanyAddress: true,
companyAddress: '',
billedToLabel: 'Billed To',
// Total

View File

@@ -1,4 +1,5 @@
import { CreditNotePdfTemplateAttributes, ICreditNote } from '@/interfaces';
import { contactAddressTextFormat } from '@/utils/address-text-format';
export const transformCreditNoteToPdfTemplate = (
creditNote: ICreditNote
@@ -19,5 +20,6 @@ export const transformCreditNoteToPdfTemplate = (
})),
customerNote: creditNote.note,
termsConditions: creditNote.termsConditions,
customerAddress: contactAddressTextFormat(creditNote.customer),
};
};

View File

@@ -231,7 +231,6 @@ export const defaultEstimatePdfBrandingAttributes = {
expirationDate: 'September 3, 2024',
};
interface EstimatePdfBrandingLineItem {
item: string;
description: string;
@@ -247,10 +246,13 @@ export interface EstimatePdfBrandingAttributes {
companyLogo: string;
companyName: string;
billedToAddress: string[];
billedFromAddress: string[];
showBilledFromAddress: boolean;
showBilledToAddress: boolean;
// Customer Address
showCustomerAddress: boolean;
customerAddress: string;
// Company Address
showCompanyAddress: boolean;
companyAddress: string;
billedToLabel: string;
total: string;
@@ -282,4 +284,4 @@ export interface EstimatePdfBrandingAttributes {
expirationDateLabel: string;
showExpirationDate: boolean;
expirationDate: string;
}
}

View File

@@ -1,3 +1,4 @@
import { contactAddressTextFormat } from '@/utils/address-text-format';
import { EstimatePdfBrandingAttributes } from './constants';
export const transformEstimateToPdfTemplate = (
@@ -18,5 +19,6 @@ export const transformEstimateToPdfTemplate = (
subtotal: estimate.formattedSubtotal,
customerNote: estimate.customerNote,
termsConditions: estimate.termsConditions,
customerAddress: contactAddressTextFormat(estimate.customer),
};
};

View File

@@ -28,7 +28,7 @@ export class SaleEstimatePdfTemplate {
await this.getOrgBrandingAttrs.getOrganizationBrandingAttributes(
tenantId
);
// Merge the default branding attributes with organization attrs.
const orgainizationBrandingAttrs = {
...defaultEstimatePdfBrandingAttributes,
...commonOrgBrandingAttrs,

View File

@@ -1,5 +1,6 @@
import { pickBy } from 'lodash';
import { InvoicePdfTemplateAttributes, ISaleInvoice } from '@/interfaces';
import { contactAddressTextFormat } from '@/utils/address-text-format';
export const mergePdfTemplateWithDefaultAttributes = (
brandingTemplate?: Record<string, any>,
@@ -42,5 +43,7 @@ export const transformInvoiceToPdfTemplate = (
label: tax.name,
amount: tax.taxRateAmountFormatted,
})),
customerAddress: contactAddressTextFormat(invoice.customer),
};
};

View File

@@ -3,12 +3,18 @@ import { Inject, Service } from 'typedi';
import { mergePdfTemplateWithDefaultAttributes } from '../Invoices/utils';
import { defaultPaymentReceivedPdfTemplateAttributes } from './constants';
import { PdfTemplate } from '@/models/PdfTemplate';
import { GetOrganizationBrandingAttributes } from '@/services/PdfTemplate/GetOrganizationBrandingAttributes';
@Service()
export class PaymentReceivedBrandingTemplate {
@Inject()
private getPdfTemplateService: GetPdfTemplate;
@Inject()
private getOrgBrandingAttributes: GetOrganizationBrandingAttributes;
/**
* Retrieves the payment received pdf template.
* @param {number} tenantId
@@ -23,9 +29,16 @@ export class PaymentReceivedBrandingTemplate {
tenantId,
paymentTemplateId
);
// Retrieves the organization branding attributes.
const commonOrgBrandingAttrs = this.getOrgBrandingAttributes.getOrganizationBrandingAttributes(tenantId);
const organizationBrandingAttrs = {
...defaultPaymentReceivedPdfTemplateAttributes,
...commonOrgBrandingAttrs,
};
const attributes = mergePdfTemplateWithDefaultAttributes(
template.attributes,
defaultPaymentReceivedPdfTemplateAttributes
organizationBrandingAttrs
);
return {
...template,

View File

@@ -58,24 +58,13 @@ export const defaultPaymentReceivedPdfTemplateAttributes = {
// # Company name
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,
showBillingToAddress: true,
// # Customer address
showCustomerAddress: true,
customerAddress: '',
// # Company address
showCompanyAddress: true,
companyAddress: '',
billedToLabel: 'Billed To',
// Total

View File

@@ -2,6 +2,7 @@ import {
IPaymentReceived,
PaymentReceivedPdfTemplateAttributes,
} from '@/interfaces';
import { contactAddressTextFormat } from '@/utils/address-text-format';
export const transformPaymentReceivedToPdfTemplate = (
payment: IPaymentReceived
@@ -17,5 +18,6 @@ export const transformPaymentReceivedToPdfTemplate = (
invoiceAmount: entry.invoice.totalFormatted,
paidAmount: entry.paymentAmountFormatted,
})),
customerAddress: contactAddressTextFormat(payment.customer),
};
};

View File

@@ -2,12 +2,15 @@ import { GetPdfTemplate } from '@/services/PdfTemplate/GetPdfTemplate';
import { Inject, Service } from 'typedi';
import { defaultSaleReceiptBrandingAttributes } from './constants';
import { mergePdfTemplateWithDefaultAttributes } from '../Invoices/utils';
import { GetOrganizationBrandingAttributes } from '@/services/PdfTemplate/GetOrganizationBrandingAttributes';
@Service()
export class SaleReceiptBrandingTemplate {
@Inject()
private getPdfTemplateService: GetPdfTemplate;
@Inject()
private getOrgBrandingAttributes: GetOrganizationBrandingAttributes;
/**
* Retrieves the sale receipt branding template.
@@ -23,9 +26,20 @@ export class SaleReceiptBrandingTemplate {
tenantId,
templateId
);
// Retrieves the organization branding attributes.
const commonOrgBrandingAttrs =
await this.getOrgBrandingAttributes.getOrganizationBrandingAttributes(
tenantId
);
// Merges the default branding attributes with organization common branding attrs.
const organizationBrandingAttrs = {
...defaultSaleReceiptBrandingAttributes,
...commonOrgBrandingAttrs,
};
const attributes = mergePdfTemplateWithDefaultAttributes(
template.attributes,
defaultSaleReceiptBrandingAttributes
organizationBrandingAttrs
);
return {
...template,

View File

@@ -76,26 +76,16 @@ export const defaultSaleReceiptBrandingAttributes = {
companyLogoUri: '',
companyLogoKey: '',
// # 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,
// # Customer address
showCustomerAddress: true,
customerAddress: '',
// # Company address
showCompanyAddress: true,
companyAddress: '',
billedToLabel: 'Billed To',
// # Total
total: '$1000.00',
totalLabel: 'Total',
showTotal: true,

View File

@@ -1,4 +1,5 @@
import { ISaleReceipt, ISaleReceiptBrandingTemplateAttributes } from "@/interfaces";
import { contactAddressTextFormat } from "@/utils/address-text-format";
@@ -13,8 +14,8 @@ export const transformReceiptToBrandingTemplateAttributes = (saleReceipt: ISaleR
quantity: entry.quantityFormatted,
total: entry.totalFormatted,
})),
receiptNumber: saleReceipt.receiptNumber,
receiptDate: saleReceipt.formattedReceiptDate,
customerAddress: contactAddressTextFormat(saleReceipt.customer),
};
}

View File

@@ -1,4 +1,4 @@
import { addressTextFormat } from '@/utils/address-text-format';
import { organizationAddressTextFormat } from '@/utils/address-text-format';
import BaseModel from 'models/Model';
import { getUploadedObjectUri } from '../../services/Attachments/utils';
@@ -74,7 +74,7 @@ export default class TenantMetadata extends BaseModel {
{POSTAL_CODE},
{COUNTRY}
`;
return addressTextFormat(defaultMessage, {
return organizationAddressTextFormat(defaultMessage, {
organizationName: this.name,
address1: this.address?.address1,
address2: this.address?.address2,

View File

@@ -1,3 +1,5 @@
import { IContact } from '@/interfaces';
interface OrganizationAddressFormatArgs {
organizationName?: string;
address1?: string;
@@ -17,7 +19,19 @@ const defaultMessage = `
{COUNTRY}
`;
export const addressTextFormat = (
const formatText = (message: string, replacements: Record<string, string>) => {
let formattedMessage = Object.entries(replacements).reduce(
(msg, [key, value]) => {
return msg.split(`{${key}}`).join(value || '');
},
message
);
formattedMessage = formattedMessage.replace(/\n/g, '<br />');
return formattedMessage.trim();
};
export const organizationAddressTextFormat = (
message: string,
args: OrganizationAddressFormatArgs
) => {
@@ -30,13 +44,53 @@ export const addressTextFormat = (
POSTAL_CODE: args.postalCode || '',
COUNTRY: args.country || '',
};
let formattedMessage = Object.entries(replacements).reduce(
(msg, [key, value]) => {
return value ? msg.split(`{${key}}`).join(value) : msg;
},
message
);
formattedMessage = formattedMessage.replace(/\n/g, '<br />');
return formattedMessage.trim();
return formatText(message, replacements);
};
interface ContactAddressTextFormatArgs {
displayName?: string;
state?: string;
postalCode?: string;
email?: string;
country?: string;
city?: string;
address2?: string;
address1?: string;
}
const contactFormatMessage = `{CONTACT_NAME}
{ADDRESS_1}
{ADDRESS_2}
{CITY} {STATE}
{POSTAL_CODE}
{COUNTRY}
{EMAIL}
`;
export const contactAddressTextFormat = (
contact: IContact,
message: string = contactFormatMessage
) => {
const args = {
displayName: contact.displayName,
address1: contact.billingAddress1,
address2: contact.billingAddress2,
state: contact.billingAddressState,
country: contact.billingAddressCountry,
postalCode: contact?.billingAddressPostcode,
city: contact?.billingAddressCity,
email: contact?.email,
} as ContactAddressTextFormatArgs;
const replacements: Record<string, string> = {
CONTACT_NAME: args.displayName || '',
ADDRESS_1: args.address1 || '',
ADDRESS_2: args.address2 || '',
CITY: args.city || '',
STATE: args.state || '',
POSTAL_CODE: args.postalCode || '',
COUNTRY: args.country || '',
EMAIL: args?.email || '',
};
return formatText(message, replacements);
};

View File

@@ -17,10 +17,9 @@ United States, <br />
ahmed@bigcapital.app
`;
export const DefaultPdfTemplateAddressBilledFrom = `131 Continental Dr Suite 305 Newark, <br />
Delaware 19713,<br />
United States, <br />
+1 762-339-5634, <br />
ahmed@bigcapital.app
`;
`;

View File

@@ -71,23 +71,27 @@ export function EstimatePaperTemplate({
primaryColor,
secondaryColor,
// # Company logo
showCompanyLogo = true,
companyLogoUri = '',
companyName,
// # Address
customerAddress = DefaultPdfTemplateAddressBilledTo,
// # Company address
companyAddress = DefaultPdfTemplateAddressBilledFrom,
showCompanyAddress = true,
// # Customer address
customerAddress = DefaultPdfTemplateAddressBilledTo,
showCustomerAddress = true,
billedToLabel = 'Billed To',
// #Total
// # Total
total = '$1000.00',
totalLabel = 'Total',
showTotal = true,
// # Subtotal
subtotal = '1000/00',
subtotalLabel = 'Subtotal',
showSubtotal = true,
@@ -111,14 +115,18 @@ export function EstimatePaperTemplate({
total: '$1000.00',
},
],
// Estimate number
showEstimateNumber = true,
estimateNumberLabel = 'Estimate Number',
estimateNumebr = '346D3D40-0001',
// Estimate date
estimateDate = 'September 3, 2024',
showEstimateDate = true,
estimateDateLabel = 'Estimate Date',
// Expiration date
expirationDateLabel = 'Expiration Date',
showExpirationDate = true,
expirationDate = 'September 3, 2024',

View File

@@ -23,10 +23,11 @@ export const initialValues = {
// Company name
companyName: 'Bigcapital Technology, Inc.',
// Addresses
// Customer address
showCustomerAddress: true,
// Company address
showCompanyAddress: true,
customerAddress: '',
companyAddress: '',
billedToLabel: 'Billed To',

View File

@@ -21,11 +21,12 @@ export const initialValues = {
// Company name
companyName: 'Bigcapital Technology, Inc.',
// Addresses
showCompanyAddress: true,
// Customer address
showCustomerAddress: true,
// Company address
companyAddress: '',
customerAddress: '',
showCompanyAddress: true,
billedToLabel: 'Billed To',
// Entries