mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-20 23:00:34 +00:00
feat: Hook up company address to payment page
This commit is contained in:
@@ -45,6 +45,7 @@ export class GetInvoicePaymentLinkMetadata {
|
||||
.withGraphFetched('entries.item')
|
||||
.withGraphFetched('customer')
|
||||
.withGraphFetched('taxes.taxRate')
|
||||
.withGraphFetched('paymentMethods.paymentIntegration')
|
||||
.throwIfNotFound();
|
||||
|
||||
return this.transformer.transform(
|
||||
|
||||
@@ -41,6 +41,8 @@ export class GetInvoicePaymentLinkMetaTransformer extends SaleInvoiceTransformer
|
||||
'entries',
|
||||
'taxes',
|
||||
'organization',
|
||||
'isReceivable',
|
||||
'hasStripePaymentMethod',
|
||||
];
|
||||
};
|
||||
|
||||
@@ -50,7 +52,7 @@ export class GetInvoicePaymentLinkMetaTransformer extends SaleInvoiceTransformer
|
||||
|
||||
/**
|
||||
* Retrieves the organization metadata for the payment link.
|
||||
* @returns
|
||||
* @returns
|
||||
*/
|
||||
public organization(invoice) {
|
||||
return this.item(
|
||||
@@ -89,6 +91,16 @@ export class GetInvoicePaymentLinkMetaTransformer extends SaleInvoiceTransformer
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
protected isReceivable(invoice) {
|
||||
return invoice.dueAmount > 0;
|
||||
}
|
||||
|
||||
protected hasStripePaymentMethod(invoice) {
|
||||
return invoice.paymentMethods.some(
|
||||
(paymentMethod) => paymentMethod.paymentIntegration.service === 'Stripe'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class GetPaymentLinkOrganizationMetaTransformer extends Transformer {
|
||||
@@ -97,12 +109,26 @@ class GetPaymentLinkOrganizationMetaTransformer extends Transformer {
|
||||
* @returns {Array}
|
||||
*/
|
||||
public includeAttributes = (): string[] => {
|
||||
return ['primaryColor', 'name', 'address', 'logoUri'];
|
||||
return [
|
||||
'primaryColor',
|
||||
'name',
|
||||
'address',
|
||||
'logoUri',
|
||||
'addressTextFormatted',
|
||||
];
|
||||
};
|
||||
|
||||
public excludeAttributes = (): string[] => {
|
||||
return ['*'];
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the formatted text of organization address.
|
||||
* @returns {string}
|
||||
*/
|
||||
public addressTextFormatted() {
|
||||
return this.context.organization.addressTextFormatted;
|
||||
}
|
||||
}
|
||||
|
||||
class GetInvoicePaymentLinkEntryMetaTransformer extends ItemEntryTransformer {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { addressTextFormat } from '@/utils/address-text-format';
|
||||
import BaseModel from 'models/Model';
|
||||
|
||||
export default class TenantMetadata extends BaseModel {
|
||||
@@ -12,8 +13,11 @@ export default class TenantMetadata extends BaseModel {
|
||||
fiscalYear!: string;
|
||||
primaryColor!: string;
|
||||
logoKey!: string;
|
||||
address!: object;
|
||||
address!: Record<string, any>;
|
||||
|
||||
/**
|
||||
* Json schema.
|
||||
*/
|
||||
static get jsonSchema() {
|
||||
return {
|
||||
type: 'object',
|
||||
@@ -50,9 +54,35 @@ export default class TenantMetadata extends BaseModel {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Organization logo url.
|
||||
* @returns {string | null}
|
||||
*/
|
||||
public get logoUri() {
|
||||
return this.logoKey ? `https://bigcapital.sfo3.digitaloceanspaces.com/${this.logoKey}` : null;
|
||||
return this.logoKey
|
||||
? `https://bigcapital.sfo3.digitaloceanspaces.com/${this.logoKey}`
|
||||
: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the organization address formatted text.
|
||||
* @returns {string}
|
||||
*/
|
||||
public get addressTextFormatted() {
|
||||
const defaultMessage = `<strong>{ORGANIZATION_NAME}</strong>
|
||||
{ADDRESS_1},
|
||||
{ADDRESS_2},
|
||||
{CITY} {STATE},
|
||||
{POSTAL_CODE},
|
||||
{COUNTRY}
|
||||
`;
|
||||
return addressTextFormat(defaultMessage, {
|
||||
organizationName: this.name,
|
||||
address1: this.address?.address1,
|
||||
address2: this.address?.address2,
|
||||
state: this.address?.stateProvince,
|
||||
city: this.address?.city,
|
||||
postalCode: this.address?.postalCode,
|
||||
country: 'United State',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
42
packages/server/src/utils/address-text-format.ts
Normal file
42
packages/server/src/utils/address-text-format.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
interface OrganizationAddressFormatArgs {
|
||||
organizationName?: string;
|
||||
address1?: string;
|
||||
address2?: string;
|
||||
state?: string;
|
||||
city?: string;
|
||||
country?: string;
|
||||
postalCode?: string;
|
||||
}
|
||||
|
||||
const defaultMessage = `
|
||||
<strong>{ORGANIZATION_NAME}</strong>
|
||||
{ADDRESS_1},
|
||||
{ADDRESS_2},
|
||||
{CITY} {STATE},
|
||||
{POSTAL_CODE},
|
||||
{COUNTRY}
|
||||
`;
|
||||
|
||||
export const addressTextFormat = (
|
||||
message: string,
|
||||
args: OrganizationAddressFormatArgs
|
||||
) => {
|
||||
const replacements: Record<string, string> = {
|
||||
ORGANIZATION_NAME: args.organizationName || '',
|
||||
ADDRESS_1: args.address1 || '',
|
||||
ADDRESS_2: args.address2 || '',
|
||||
CITY: args.city || '',
|
||||
STATE: args.state || '',
|
||||
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();
|
||||
};
|
||||
@@ -96,7 +96,6 @@ export function PaymentPortal() {
|
||||
<Text>{tax?.taxRateAmountFormatted}</Text>
|
||||
</Group>
|
||||
))}
|
||||
|
||||
<Group
|
||||
position={'apart'}
|
||||
className={clsx(styles.totalItem, styles.borderBottomGray)}
|
||||
@@ -132,14 +131,17 @@ export function PaymentPortal() {
|
||||
View Invoice
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
intent={Intent.PRIMARY}
|
||||
className={clsx(styles.footerButton, styles.buyButton)}
|
||||
loading={isStripeCheckoutLoading}
|
||||
onClick={handlePayButtonClick}
|
||||
>
|
||||
Pay {sharableLinkMeta?.totalFormatted}
|
||||
</Button>
|
||||
{sharableLinkMeta?.isReceivable &&
|
||||
sharableLinkMeta?.hasStripePaymentMethod && (
|
||||
<Button
|
||||
intent={Intent.PRIMARY}
|
||||
className={clsx(styles.footerButton, styles.buyButton)}
|
||||
loading={isStripeCheckoutLoading}
|
||||
onClick={handlePayButtonClick}
|
||||
>
|
||||
Pay {sharableLinkMeta?.totalFormatted}
|
||||
</Button>
|
||||
)}
|
||||
</Stack>
|
||||
|
||||
<Text className={clsx(Classes.TEXT_MUTED, styles.buyNote)}>
|
||||
@@ -150,15 +152,11 @@ export function PaymentPortal() {
|
||||
</Stack>
|
||||
|
||||
<Stack spacing={18} className={styles.footer}>
|
||||
<Stack spacing={0}>
|
||||
<Box>
|
||||
<strong>Bigcapital Technology, Inc.</strong>
|
||||
</Box>
|
||||
<Box>131 Continental Dr Suite 305 Newark,</Box>
|
||||
<Box>Delaware 19713</Box>
|
||||
<Box>United States</Box>
|
||||
<Box>ahmed@bigcapital.app</Box>
|
||||
</Stack>
|
||||
<Box
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: sharableLinkMeta?.organization?.addressTextFormatted || '',
|
||||
}}
|
||||
></Box>
|
||||
|
||||
<Stack spacing={0} className={styles.footerText}>
|
||||
© 2024 Bigcapital Technology, Inc.
|
||||
|
||||
@@ -104,8 +104,11 @@ export interface GetInvoicePaymentLinkResponse {
|
||||
name: string;
|
||||
primaryColor: string;
|
||||
logoUri: string;
|
||||
addressTextFormatted: string;
|
||||
}
|
||||
>;
|
||||
hasStripePaymentMethod: boolean;
|
||||
isReceivable: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user