mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-23 00:00:31 +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('entries.item')
|
||||||
.withGraphFetched('customer')
|
.withGraphFetched('customer')
|
||||||
.withGraphFetched('taxes.taxRate')
|
.withGraphFetched('taxes.taxRate')
|
||||||
|
.withGraphFetched('paymentMethods.paymentIntegration')
|
||||||
.throwIfNotFound();
|
.throwIfNotFound();
|
||||||
|
|
||||||
return this.transformer.transform(
|
return this.transformer.transform(
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ export class GetInvoicePaymentLinkMetaTransformer extends SaleInvoiceTransformer
|
|||||||
'entries',
|
'entries',
|
||||||
'taxes',
|
'taxes',
|
||||||
'organization',
|
'organization',
|
||||||
|
'isReceivable',
|
||||||
|
'hasStripePaymentMethod',
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -50,7 +52,7 @@ export class GetInvoicePaymentLinkMetaTransformer extends SaleInvoiceTransformer
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the organization metadata for the payment link.
|
* Retrieves the organization metadata for the payment link.
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
public organization(invoice) {
|
public organization(invoice) {
|
||||||
return this.item(
|
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 {
|
class GetPaymentLinkOrganizationMetaTransformer extends Transformer {
|
||||||
@@ -97,12 +109,26 @@ class GetPaymentLinkOrganizationMetaTransformer extends Transformer {
|
|||||||
* @returns {Array}
|
* @returns {Array}
|
||||||
*/
|
*/
|
||||||
public includeAttributes = (): string[] => {
|
public includeAttributes = (): string[] => {
|
||||||
return ['primaryColor', 'name', 'address', 'logoUri'];
|
return [
|
||||||
|
'primaryColor',
|
||||||
|
'name',
|
||||||
|
'address',
|
||||||
|
'logoUri',
|
||||||
|
'addressTextFormatted',
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
public excludeAttributes = (): string[] => {
|
public excludeAttributes = (): string[] => {
|
||||||
return ['*'];
|
return ['*'];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the formatted text of organization address.
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
public addressTextFormatted() {
|
||||||
|
return this.context.organization.addressTextFormatted;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class GetInvoicePaymentLinkEntryMetaTransformer extends ItemEntryTransformer {
|
class GetInvoicePaymentLinkEntryMetaTransformer extends ItemEntryTransformer {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { addressTextFormat } from '@/utils/address-text-format';
|
||||||
import BaseModel from 'models/Model';
|
import BaseModel from 'models/Model';
|
||||||
|
|
||||||
export default class TenantMetadata extends BaseModel {
|
export default class TenantMetadata extends BaseModel {
|
||||||
@@ -12,8 +13,11 @@ export default class TenantMetadata extends BaseModel {
|
|||||||
fiscalYear!: string;
|
fiscalYear!: string;
|
||||||
primaryColor!: string;
|
primaryColor!: string;
|
||||||
logoKey!: string;
|
logoKey!: string;
|
||||||
address!: object;
|
address!: Record<string, any>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Json schema.
|
||||||
|
*/
|
||||||
static get jsonSchema() {
|
static get jsonSchema() {
|
||||||
return {
|
return {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
@@ -50,9 +54,35 @@ export default class TenantMetadata extends BaseModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Organization logo url.
|
||||||
|
* @returns {string | null}
|
||||||
*/
|
*/
|
||||||
public get logoUri() {
|
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>
|
<Text>{tax?.taxRateAmountFormatted}</Text>
|
||||||
</Group>
|
</Group>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
<Group
|
<Group
|
||||||
position={'apart'}
|
position={'apart'}
|
||||||
className={clsx(styles.totalItem, styles.borderBottomGray)}
|
className={clsx(styles.totalItem, styles.borderBottomGray)}
|
||||||
@@ -132,14 +131,17 @@ export function PaymentPortal() {
|
|||||||
View Invoice
|
View Invoice
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button
|
{sharableLinkMeta?.isReceivable &&
|
||||||
intent={Intent.PRIMARY}
|
sharableLinkMeta?.hasStripePaymentMethod && (
|
||||||
className={clsx(styles.footerButton, styles.buyButton)}
|
<Button
|
||||||
loading={isStripeCheckoutLoading}
|
intent={Intent.PRIMARY}
|
||||||
onClick={handlePayButtonClick}
|
className={clsx(styles.footerButton, styles.buyButton)}
|
||||||
>
|
loading={isStripeCheckoutLoading}
|
||||||
Pay {sharableLinkMeta?.totalFormatted}
|
onClick={handlePayButtonClick}
|
||||||
</Button>
|
>
|
||||||
|
Pay {sharableLinkMeta?.totalFormatted}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
<Text className={clsx(Classes.TEXT_MUTED, styles.buyNote)}>
|
<Text className={clsx(Classes.TEXT_MUTED, styles.buyNote)}>
|
||||||
@@ -150,15 +152,11 @@ export function PaymentPortal() {
|
|||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
<Stack spacing={18} className={styles.footer}>
|
<Stack spacing={18} className={styles.footer}>
|
||||||
<Stack spacing={0}>
|
<Box
|
||||||
<Box>
|
dangerouslySetInnerHTML={{
|
||||||
<strong>Bigcapital Technology, Inc.</strong>
|
__html: sharableLinkMeta?.organization?.addressTextFormatted || '',
|
||||||
</Box>
|
}}
|
||||||
<Box>131 Continental Dr Suite 305 Newark,</Box>
|
></Box>
|
||||||
<Box>Delaware 19713</Box>
|
|
||||||
<Box>United States</Box>
|
|
||||||
<Box>ahmed@bigcapital.app</Box>
|
|
||||||
</Stack>
|
|
||||||
|
|
||||||
<Stack spacing={0} className={styles.footerText}>
|
<Stack spacing={0} className={styles.footerText}>
|
||||||
© 2024 Bigcapital Technology, Inc.
|
© 2024 Bigcapital Technology, Inc.
|
||||||
|
|||||||
@@ -104,8 +104,11 @@ export interface GetInvoicePaymentLinkResponse {
|
|||||||
name: string;
|
name: string;
|
||||||
primaryColor: string;
|
primaryColor: string;
|
||||||
logoUri: string;
|
logoUri: string;
|
||||||
|
addressTextFormatted: string;
|
||||||
}
|
}
|
||||||
>;
|
>;
|
||||||
|
hasStripePaymentMethod: boolean;
|
||||||
|
isReceivable: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user