Merge pull request #760 from bigcapitalhq/fix-formatted-hooks

fix: update financial forms to use new formatted amount utilities and…
This commit is contained in:
Ahmed Bouhuolia
2024-12-04 13:24:23 +02:00
committed by GitHub
47 changed files with 333 additions and 225 deletions

View File

@@ -153,7 +153,7 @@ export default class BillsController extends BaseController {
check('discount_type') check('discount_type')
.default(DiscountType.Amount) .default(DiscountType.Amount)
.isIn([DiscountType.Amount, DiscountType.Percentage]), .isIn([DiscountType.Amount, DiscountType.Percentage]),
check('discount').optional().isDecimal().toFloat(), check('discount').optional({ nullable: true }).isDecimal().toFloat(),
// # Adjustment // # Adjustment
check('adjustment').optional({ nullable: true }).isNumeric().toFloat(), check('adjustment').optional({ nullable: true }).isNumeric().toFloat(),
@@ -204,7 +204,7 @@ export default class BillsController extends BaseController {
check('discount_type') check('discount_type')
.default(DiscountType.Amount) .default(DiscountType.Amount)
.isIn([DiscountType.Amount, DiscountType.Percentage]), .isIn([DiscountType.Amount, DiscountType.Percentage]),
check('discount').optional().isDecimal().toFloat(), check('discount').optional({ nullable: true }).isDecimal().toFloat(),
// # Adjustment // # Adjustment
check('adjustment').optional({ nullable: true }).isNumeric().toFloat(), check('adjustment').optional({ nullable: true }).isNumeric().toFloat(),

View File

@@ -204,13 +204,13 @@ export default class SalesEstimatesController extends BaseController {
check('pdf_template_id').optional({ nullable: true }).isNumeric().toInt(), check('pdf_template_id').optional({ nullable: true }).isNumeric().toInt(),
// # Discount // # Discount
check('discount').optional().isNumeric().toFloat(), check('discount').optional({ nullable: true }).isNumeric().toFloat(),
check('discount_type') check('discount_type')
.default(DiscountType.Amount) .default(DiscountType.Amount)
.isIn([DiscountType.Amount, DiscountType.Percentage]), .isIn([DiscountType.Amount, DiscountType.Percentage]),
// # Adjustment // # Adjustment
check('adjustment').optional().isNumeric().toFloat(), check('adjustment').optional({ nullable: true }).isNumeric().toFloat(),
]; ];
} }

View File

@@ -96,6 +96,7 @@ export class CreditNoteTransformer extends Transformer {
protected discountAmountFormatted = (credit): string => { protected discountAmountFormatted = (credit): string => {
return formatNumber(credit.discountAmount, { return formatNumber(credit.discountAmount, {
currencyCode: credit.currencyCode, currencyCode: credit.currencyCode,
excerptZero: true,
}); });
}; };
@@ -118,6 +119,7 @@ export class CreditNoteTransformer extends Transformer {
protected adjustmentFormatted = (credit): string => { protected adjustmentFormatted = (credit): string => {
return this.formatMoney(credit.adjustment, { return this.formatMoney(credit.adjustment, {
currencyCode: credit.currencyCode, currencyCode: credit.currencyCode,
excerptZero: true,
}); });
}; };

View File

@@ -171,6 +171,7 @@ export class PurchaseInvoiceTransformer extends Transformer {
protected discountAmountFormatted = (bill): string => { protected discountAmountFormatted = (bill): string => {
return formatNumber(bill.discountAmount, { return formatNumber(bill.discountAmount, {
currencyCode: bill.currencyCode, currencyCode: bill.currencyCode,
excerptZero: true,
}); });
}; };
@@ -193,6 +194,7 @@ export class PurchaseInvoiceTransformer extends Transformer {
protected adjustmentFormatted = (bill): string => { protected adjustmentFormatted = (bill): string => {
return formatNumber(bill.adjustment, { return formatNumber(bill.adjustment, {
currencyCode: bill.currencyCode, currencyCode: bill.currencyCode,
excerptZero: true,
}); });
}; };

View File

@@ -82,6 +82,7 @@ export class VendorCreditTransformer extends Transformer {
protected discountAmountFormatted = (credit): string => { protected discountAmountFormatted = (credit): string => {
return formatNumber(credit.discountAmount, { return formatNumber(credit.discountAmount, {
currencyCode: credit.currencyCode, currencyCode: credit.currencyCode,
excerptZero: true,
}); });
}; };
@@ -102,6 +103,7 @@ export class VendorCreditTransformer extends Transformer {
protected adjustmentFormatted = (credit): string => { protected adjustmentFormatted = (credit): string => {
return formatNumber(credit.adjustment, { return formatNumber(credit.adjustment, {
currencyCode: credit.currencyCode, currencyCode: credit.currencyCode,
excerptZero: true,
}); });
}; };

View File

@@ -111,6 +111,7 @@ export class SaleEstimateTransfromer extends Transformer {
protected discountAmountFormatted = (estimate: ISaleEstimate): string => { protected discountAmountFormatted = (estimate: ISaleEstimate): string => {
return formatNumber(estimate.discountAmount, { return formatNumber(estimate.discountAmount, {
currencyCode: estimate.currencyCode, currencyCode: estimate.currencyCode,
excerptZero: true,
}); });
}; };
@@ -133,6 +134,7 @@ export class SaleEstimateTransfromer extends Transformer {
protected adjustmentFormatted = (estimate: ISaleEstimate): string => { protected adjustmentFormatted = (estimate: ISaleEstimate): string => {
return this.formatMoney(estimate.adjustment, { return this.formatMoney(estimate.adjustment, {
currencyCode: estimate.currencyCode, currencyCode: estimate.currencyCode,
excerptZero: true,
}); });
}; };

View File

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

View File

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

View File

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

View File

@@ -170,6 +170,7 @@ export class SaleInvoiceTransformer extends Transformer {
protected discountAmountFormatted = (invoice): string => { protected discountAmountFormatted = (invoice): string => {
return formatNumber(invoice.discountAmount, { return formatNumber(invoice.discountAmount, {
currencyCode: invoice.currencyCode, currencyCode: invoice.currencyCode,
excerptZero: true,
}); });
}; };
@@ -192,8 +193,9 @@ export class SaleInvoiceTransformer extends Transformer {
protected adjustmentFormatted = (invoice): string => { protected adjustmentFormatted = (invoice): string => {
return this.formatMoney(invoice.adjustment, { return this.formatMoney(invoice.adjustment, {
currencyCode: invoice.currencyCode, currencyCode: invoice.currencyCode,
}) excerptZero: true,
} });
};
/** /**
* Retrieves formatted total in foreign currency. * Retrieves formatted total in foreign currency.

View File

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

View File

@@ -113,6 +113,7 @@ export class SaleReceiptTransformer extends Transformer {
protected discountAmountFormatted = (receipt: ISaleReceipt): string => { protected discountAmountFormatted = (receipt: ISaleReceipt): string => {
return formatNumber(receipt.discountAmount, { return formatNumber(receipt.discountAmount, {
currencyCode: receipt.currencyCode, currencyCode: receipt.currencyCode,
excerptZero: true,
}); });
}; };
@@ -135,6 +136,7 @@ export class SaleReceiptTransformer extends Transformer {
protected adjustmentFormatted = (receipt: ISaleReceipt): string => { protected adjustmentFormatted = (receipt: ISaleReceipt): string => {
return this.formatMoney(receipt.adjustment, { return this.formatMoney(receipt.adjustment, {
currencyCode: receipt.currencyCode, currencyCode: receipt.currencyCode,
excerptZero: true,
}); });
}; };

View File

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

View File

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

View File

@@ -2,18 +2,22 @@
import React from 'react'; import React from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { CLASSES } from '@/constants/classes'; import { CLASSES } from '@/constants/classes';
import { Money } from '@/components';
import '@/style/components/BigAmount.scss'; import '@/style/components/BigAmount.scss';
export function PageFormBigNumber({ label, amount, currencyCode }) { interface PageFormBigNumberProps {
label: string;
amount: string | number;
}
export function PageFormBigNumber({
label,
amount,
}: PageFormBigNumberProps) {
return ( return (
<div className={classNames(CLASSES.PAGE_FORM_HEADER_BIG_NUMBERS)}> <div className={classNames(CLASSES.PAGE_FORM_HEADER_BIG_NUMBERS)}>
<div class="big-amount"> <div class="big-amount">
<span class="big-amount__label">{label}</span> <span class="big-amount__label">{label}</span>
<h1 class="big-amount__number"> <h1 class="big-amount__number">{amount}</h1>
<Money amount={amount} currency={currencyCode} />
</h1>
</div> </div>
</div> </div>
); );

View File

@@ -1,11 +1,10 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { useFormikContext } from 'formik';
import { CLASSES } from '@/constants/classes'; import { CLASSES } from '@/constants/classes';
import { safeSumBy } from '@/utils';
import { PageFormBigNumber, FormattedMessage as T } from '@/components'; import { PageFormBigNumber, FormattedMessage as T } from '@/components';
import MakeJournalEntriesHeaderFields from './MakeJournalEntriesHeaderFields'; import MakeJournalEntriesHeaderFields from './MakeJournalEntriesHeaderFields';
import { useManualJournalTotalFormatted } from './utils';
export default function MakeJournalEntriesHeader() { export default function MakeJournalEntriesHeader() {
return ( return (
@@ -21,19 +20,9 @@ export default function MakeJournalEntriesHeader() {
* @returns {React.ReactNode} * @returns {React.ReactNode}
*/ */
function MakeJournalHeaderBigNumber() { function MakeJournalHeaderBigNumber() {
const { const totalFormatted = useManualJournalTotalFormatted();
values: { entries, currency_code },
} = useFormikContext();
const totalCredit = safeSumBy(entries, 'credit');
const totalDebit = safeSumBy(entries, 'debit');
const total = Math.max(totalCredit, totalDebit);
return ( return (
<PageFormBigNumber <PageFormBigNumber label={<T id={'amount'} />} amount={totalFormatted} />
label={<T id={'amount'} />}
amount={total}
currencyCode={currency_code}
/>
); );
} }

View File

@@ -8,10 +8,14 @@ import {
TotalLineBorderStyle, TotalLineBorderStyle,
TotalLineTextStyle, TotalLineTextStyle,
} from '@/components'; } from '@/components';
import { useJournalTotals } from './utils'; import {
useManualJournalSubtotalFormatted,
useManualJournalTotalFormatted,
} from './utils';
export function MakeJournalFormFooterRight() { export function MakeJournalFormFooterRight() {
const { formattedSubtotal, formattedTotal } = useJournalTotals(); const formattedSubtotal = useManualJournalSubtotalFormatted();
const formattedTotal = useManualJournalTotalFormatted();
return ( return (
<MakeJouranlTotalLines> <MakeJouranlTotalLines>

View File

@@ -226,34 +226,73 @@ export const useSetPrimaryBranchToForm = () => {
}, [isBranchesSuccess, setFieldValue, branches]); }, [isBranchesSuccess, setFieldValue, branches]);
}; };
/** export const useManualJournalCreditTotal = () => {
* Retreives the Journal totals. const { values } = useFormikContext();
*/ const totalCredit = safeSumBy(values.entries, 'credit');
export const useJournalTotals = () => {
const {
values: { entries, currency_code: currencyCode },
} = useFormikContext();
// Retrieves the invoice entries total. return totalCredit;
const totalCredit = safeSumBy(entries, 'credit');
const totalDebit = safeSumBy(entries, 'debit');
const total = Math.max(totalCredit, totalDebit);
// Retrieves the formatted total money.
const formattedTotal = React.useMemo(
() => formattedAmount(total, currencyCode),
[total, currencyCode],
);
// Retrieves the formatted subtotal.
const formattedSubtotal = React.useMemo(
() => formattedAmount(total, currencyCode, { money: false }),
[total, currencyCode],
);
return {
formattedTotal,
formattedSubtotal,
}; };
export const useManualJournalCreditTotalFormatted = () => {
const totalCredit = useManualJournalCreditTotal();
const { values } = useFormikContext();
return formattedAmount(totalCredit, values.currency_code);
};
export const useManualJournalDebitTotal = () => {
const { values } = useFormikContext();
const totalDebit = safeSumBy(values.entries, 'debit');
return totalDebit;
};
export const useManualJournalDebitTotalFormatted = () => {
const totalDebit = useManualJournalDebitTotal();
const { values } = useFormikContext();
return formattedAmount(totalDebit, values.currency_code);
};
export const useManualJournalSubtotal = () => {
const totalCredit = useManualJournalCreditTotal();
const totalDebit = useManualJournalDebitTotal();
return Math.max(totalCredit, totalDebit);
};
export const useManualJournalSubtotalFormatted = () => {
const subtotal = useManualJournalSubtotal();
const { values } = useFormikContext();
return formattedAmount(subtotal, values.currency_code);
};
export const useManualJournalTotalDifference = () => {
const totalCredit = useManualJournalCreditTotal();
const totalDebit = useManualJournalDebitTotal();
return Math.abs(totalCredit - totalDebit);
};
export const useManualJournalTotalDifferenceFormatted = () => {
const difference = useManualJournalTotalDifference();
const { values } = useFormikContext();
return formattedAmount(difference, values.currency_code);
};
export const useManualJournalTotal = () => {
const total = useManualJournalSubtotal();
return total;
};
export const useManualJournalTotalFormatted = () => {
const total = useManualJournalTotal();
const { values } = useFormikContext();
return formattedAmount(total, values.currency_code);
}; };
/** /**

View File

@@ -42,6 +42,12 @@ export function BillDetailTableFooter() {
textStyle={TotalLineTextStyle.Regular} textStyle={TotalLineTextStyle.Regular}
/> />
)} )}
{bill.adjustment > 0 && (
<TotalLine
title={'Adjustment'}
value={bill.adjustment_formatted}
/>
)}
<TotalLine <TotalLine
title={<T id={'bill.details.total'} />} title={<T id={'bill.details.total'} />}
value={bill.total_formatted} value={bill.total_formatted}

View File

@@ -30,7 +30,7 @@ export default function CreditNoteDetailHeader() {
<CommercialDocTopHeader> <CommercialDocTopHeader>
<DetailsMenu> <DetailsMenu>
<AmountItem label={intl.get('amount')}> <AmountItem label={intl.get('amount')}>
<span class="big-number">{creditNote.formatted_amount}</span> <span class="big-number">{creditNote.total_formatted}</span>
</AmountItem> </AmountItem>
<StatusItem> <StatusItem>

View File

@@ -21,6 +21,7 @@ export default function CreditNoteDetailTableFooter() {
<TotalLine <TotalLine
title={<T id={'credit_note.drawer.label_subtotal'} />} title={<T id={'credit_note.drawer.label_subtotal'} />}
value={creditNote.formatted_subtotal} value={creditNote.formatted_subtotal}
borderStyle={TotalLineBorderStyle.SingleDark}
/> />
{creditNote.discount_amount > 0 && ( {creditNote.discount_amount > 0 && (
<TotalLine <TotalLine
@@ -30,7 +31,12 @@ export default function CreditNoteDetailTableFooter() {
: 'Discount' : 'Discount'
} }
value={creditNote.discount_amount_formatted} value={creditNote.discount_amount_formatted}
borderStyle={TotalLineBorderStyle.Dark} />
)}
{creditNote.adjustment > 0 && (
<TotalLine
title={'Adjustment'}
value={creditNote.adjustment_formatted}
/> />
)} )}
<TotalLine <TotalLine

View File

@@ -30,7 +30,7 @@ export default function EstimateDetailHeader() {
<CommercialDocTopHeader> <CommercialDocTopHeader>
<DetailsMenu> <DetailsMenu>
<AmountEstimateDetail label={intl.get('amount')}> <AmountEstimateDetail label={intl.get('amount')}>
<span class="big-number">{estimate.formatted_amount}</span> <span class="big-number">{estimate.total_formatted}</span>
</AmountEstimateDetail> </AmountEstimateDetail>
<EstimateStatusDetail> <EstimateStatusDetail>

View File

@@ -25,20 +25,27 @@ export default function EstimateDetailTableFooter() {
value={estimate.formatted_subtotal} value={estimate.formatted_subtotal}
borderStyle={TotalLineBorderStyle.SingleDark} borderStyle={TotalLineBorderStyle.SingleDark}
/> />
{estimate.discount_amount > 0 && ( {estimate?.discount_amount_formatted && (
<TotalLine <TotalLine
title={ title={
estimate.discount_percentage_formatted estimate.discount_percentage_formatted
? `Discount [${invoice.discount_percentage_formatted}]` ? `Discount [${estimate.discount_percentage_formatted}]`
: 'Discount' : 'Discount'
} }
value={estimate.discount_amount_formatted} value={estimate.discount_amount_formatted}
textStyle={TotalLineTextStyle.Regular} textStyle={TotalLineTextStyle.Regular}
/> />
)} )}
{estimate?.adjustment_formatted && (
<TotalLine
title="Adjustment"
value={estimate.adjustment_formatted}
textStyle={TotalLineTextStyle.Regular}
/>
)}
<TotalLine <TotalLine
title={<T id={'estimate.details.total'} />} title={<T id={'estimate.details.total'} />}
value={estimate.formatted_amount} value={estimate.total_formatted}
borderStyle={TotalLineBorderStyle.DoubleDark} borderStyle={TotalLineBorderStyle.DoubleDark}
textStyle={TotalLineTextStyle.Bold} textStyle={TotalLineTextStyle.Bold}
/> />

View File

@@ -5,12 +5,10 @@ import styled from 'styled-components';
import { defaultTo } from 'lodash'; import { defaultTo } from 'lodash';
import { import {
ButtonLink,
Row, Row,
Col, Col,
DetailsMenu, DetailsMenu,
DetailItem, DetailItem,
FormatDate,
CommercialDocHeader, CommercialDocHeader,
CommercialDocTopHeader, CommercialDocTopHeader,
CustomerDrawerLink, CustomerDrawerLink,

View File

@@ -26,7 +26,7 @@ export function InvoiceDetailTableFooter() {
value={invoice.subtotal_formatted} value={invoice.subtotal_formatted}
borderStyle={TotalLineBorderStyle.SingleDark} borderStyle={TotalLineBorderStyle.SingleDark}
/> />
{invoice.discount_amount > 0 && ( {invoice?.discount_amount > 0 && (
<TotalLine <TotalLine
title={ title={
invoice.discount_percentage_formatted invoice.discount_percentage_formatted
@@ -37,7 +37,14 @@ export function InvoiceDetailTableFooter() {
textStyle={TotalLineTextStyle.Regular} textStyle={TotalLineTextStyle.Regular}
/> />
)} )}
{invoice.taxes.map((taxRate) => ( {invoice?.adjustment_formatted && (
<TotalLine
title="Adjustment"
value={invoice.adjustment_formatted}
textStyle={TotalLineTextStyle.Regular}
/>
)}
{invoice?.taxes?.map((taxRate) => (
<TotalLine <TotalLine
key={taxRate.id} key={taxRate.id}
title={`${taxRate.name} [${taxRate.tax_rate}%]`} title={`${taxRate.name} [${taxRate.tax_rate}%]`}
@@ -45,7 +52,6 @@ export function InvoiceDetailTableFooter() {
textStyle={TotalLineTextStyle.Regular} textStyle={TotalLineTextStyle.Regular}
/> />
))} ))}
<TotalLine <TotalLine
title={<T id={'invoice.details.total'} />} title={<T id={'invoice.details.total'} />}
value={invoice.total_formatted} value={invoice.total_formatted}

View File

@@ -31,7 +31,7 @@ export default function ReceiptDetailHeader() {
<CommercialDocTopHeader> <CommercialDocTopHeader>
<DetailsMenu> <DetailsMenu>
<AmountReceiptItem label={intl.get('amount')}> <AmountReceiptItem label={intl.get('amount')}>
<h3 class="big-number">{receipt.formatted_amount}</h3> <h3 class="big-number">{receipt.total_formatted}</h3>
</AmountReceiptItem> </AmountReceiptItem>
<StatusReceiptItem> <StatusReceiptItem>

View File

@@ -23,7 +23,7 @@ export default function ReceiptDetailTableFooter() {
<ReceiptTotalLines labelColWidth={'180px'} amountColWidth={'180px'}> <ReceiptTotalLines labelColWidth={'180px'} amountColWidth={'180px'}>
<TotalLine <TotalLine
title={<T id={'receipt.details.subtotal'} />} title={<T id={'receipt.details.subtotal'} />}
value={receipt.formatted_subtotal} value={receipt.subtotal_formatted}
/> />
{receipt.discount_amount > 0 && ( {receipt.discount_amount > 0 && (
<TotalLine <TotalLine
@@ -36,9 +36,16 @@ export default function ReceiptDetailTableFooter() {
textStyle={TotalLineTextStyle.Regular} textStyle={TotalLineTextStyle.Regular}
/> />
)} )}
{receipt.adjustment > 0 && (
<TotalLine
title={'Adjustment'}
value={receipt.adjustment_formatted}
textStyle={TotalLineTextStyle.Regular}
/>
)}
<TotalLine <TotalLine
title={<T id={'receipt.details.total'} />} title={<T id={'receipt.details.total'} />}
value={receipt.formatted_amount} value={receipt.total_formatted}
borderStyle={TotalLineBorderStyle.DoubleDark} borderStyle={TotalLineBorderStyle.DoubleDark}
textStyle={TotalLineTextStyle.Bold} textStyle={TotalLineTextStyle.Bold}
/> />

View File

@@ -25,17 +25,24 @@ export default function VendorCreditDetailDrawerFooter() {
value={vendorCredit.formatted_subtotal} value={vendorCredit.formatted_subtotal}
borderStyle={TotalLineBorderStyle.SingleDark} borderStyle={TotalLineBorderStyle.SingleDark}
/> />
{vendorCredit.discount_amount > 0 && ( {vendorCredit?.discount_amount_formatted && (
<TotalLine <TotalLine
title={ title={
bill.discount_percentage_formatted vendorCredit.discount_percentage_formatted
? `Discount [${bill.discount_percentage_formatted}]` ? `Discount [${vendorCredit.discount_percentage_formatted}]`
: 'Discount' : 'Discount'
} }
value={vendorCredit.discount_amount_formatted} value={vendorCredit.discount_amount_formatted}
textStyle={TotalLineTextStyle.Regular} textStyle={TotalLineTextStyle.Regular}
/> />
)} )}
{vendorCredit?.adjustment_formatted && (
<TotalLine
title={'Adjustment'}
value={vendorCredit.adjustment_formatted}
textStyle={TotalLineTextStyle.Regular}
/>
)}
<TotalLine <TotalLine
title={<T id={'vendor_credit.drawer.label_total'} />} title={<T id={'vendor_credit.drawer.label_total'} />}
value={vendorCredit.formatted_amount} value={vendorCredit.formatted_amount}

View File

@@ -8,21 +8,25 @@ import {
TotalLineBorderStyle, TotalLineBorderStyle,
TotalLineTextStyle, TotalLineTextStyle,
} from '@/components'; } from '@/components';
import { useExpensesTotals } from './utils'; import {
useExpenseSubtotalFormatted,
useExpenseTotalFormatted,
} from './utils';
export function ExpenseFormFooterRight() { export function ExpenseFormFooterRight() {
const { formattedSubtotal, formattedTotal } = useExpensesTotals(); const totalFormatted = useExpenseTotalFormatted();
const subtotalFormatted = useExpenseSubtotalFormatted();
return ( return (
<ExpensesTotalLines> <ExpensesTotalLines>
<TotalLine <TotalLine
title={<T id={'expense.label.subtotal'} />} title={<T id={'expense.label.subtotal'} />}
value={formattedSubtotal} value={subtotalFormatted}
borderStyle={TotalLineBorderStyle.None} borderStyle={TotalLineBorderStyle.None}
/> />
<TotalLine <TotalLine
title={<T id={'expense.label.total'} />} title={<T id={'expense.label.total'} />}
value={formattedTotal} value={totalFormatted}
textStyle={TotalLineTextStyle.Bold} textStyle={TotalLineTextStyle.Bold}
/> />
</ExpensesTotalLines> </ExpensesTotalLines>

View File

@@ -1,34 +1,23 @@
// @ts-nocheck // @ts-nocheck
import React, { useMemo } from 'react'; import React from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { sumBy } from 'lodash';
import { useFormikContext } from 'formik';
import { FormattedMessage as T } from '@/components'; import { FormattedMessage as T } from '@/components';
import { CLASSES } from '@/constants/classes'; import { CLASSES } from '@/constants/classes';
import ExpenseFormHeaderFields from './ExpenseFormHeaderFields'; import ExpenseFormHeaderFields from './ExpenseFormHeaderFields';
import { PageFormBigNumber } from '@/components'; import { PageFormBigNumber } from '@/components';
import { useExpenseTotalFormatted } from './utils';
// Expense form header. // Expense form header.
export default function ExpenseFormHeader() { export default function ExpenseFormHeader() {
const { const totalFormatted = useExpenseTotalFormatted();
values: { currency_code, categories },
} = useFormikContext();
// Calculates the expense entries amount.
const totalExpenseAmount = useMemo(
() => sumBy(categories, 'amount'),
[categories],
);
return ( return (
<div className={classNames(CLASSES.PAGE_FORM_HEADER)}> <div className={classNames(CLASSES.PAGE_FORM_HEADER)}>
<ExpenseFormHeaderFields /> <ExpenseFormHeaderFields />
<PageFormBigNumber <PageFormBigNumber
label={<T id={'expense_amount'} />} label={<T id={'expense_amount'} />}
amount={totalExpenseAmount} amount={totalFormatted}
currencyCode={currency_code}
/> />
</div> </div>
); );

View File

@@ -166,30 +166,52 @@ export const useSetPrimaryBranchToForm = () => {
}; };
/** /**
* Retreives the Journal totals. * Retrieves the expense subtotal.
* @returns {number}
*/ */
export const useExpensesTotals = () => { export const useExpenseSubtotal = () => {
const { const {
values: { categories, currency_code: currencyCode }, values: { categories },
} = useFormikContext(); } = useFormikContext();
const total = sumBy(categories, 'amount'); // Calculates the expense entries amount.
return React.useMemo(() => sumBy(categories, 'amount'), [categories]);
// Retrieves the formatted total money.
const formattedTotal = React.useMemo(
() => formattedAmount(total, currencyCode),
[total, currencyCode],
);
// Retrieves the formatted subtotal.
const formattedSubtotal = React.useMemo(
() => formattedAmount(total, currencyCode, { money: false }),
[total, currencyCode],
);
return {
formattedTotal,
formattedSubtotal,
}; };
/**
* Retrieves the expense subtotal formatted.
* @returns {string}
*/
export const useExpenseSubtotalFormatted = () => {
const subtotal = useExpenseSubtotal();
const {
values: { currency_code },
} = useFormikContext();
return formattedAmount(subtotal, currency_code);
};
/**
* Retrieves the expense total.
* @returns {number}
*/
export const useExpenseTotal = () => {
const subtotal = useExpenseSubtotal();
return subtotal;
};
/**
* Retrieves the expense total formatted.
* @returns {string}
*/
export const useExpenseTotalFormatted = () => {
const total = useExpenseTotal();
const {
values: { currency_code },
} = useFormikContext();
return formattedAmount(total, currency_code);
}; };
/** /**

View File

@@ -1,13 +1,12 @@
// @ts-nocheck // @ts-nocheck
import React, { useMemo } from 'react'; import React from 'react';
import intl from 'react-intl-universal'; import intl from 'react-intl-universal';
import classNames from 'classnames'; import classNames from 'classnames';
import { sumBy } from 'lodash';
import { useFormikContext } from 'formik';
import { CLASSES } from '@/constants/classes'; import { CLASSES } from '@/constants/classes';
import { PageFormBigNumber } from '@/components'; import { PageFormBigNumber } from '@/components';
import BillFormHeaderFields from './BillFormHeaderFields'; import BillFormHeaderFields from './BillFormHeaderFields';
import { useBillTotalFormatted } from './utils';
/** /**
* Fill form header. * Fill form header.
@@ -22,19 +21,10 @@ function BillFormHeader() {
} }
function BillFormBigTotal() { function BillFormBigTotal() {
const { const totalFormatted = useBillTotalFormatted();
values: { currency_code, entries },
} = useFormikContext();
// Calculate the total due amount of bill entries.
const totalDueAmount = useMemo(() => sumBy(entries, 'amount'), [entries]);
return ( return (
<PageFormBigNumber <PageFormBigNumber label={intl.get('due_amount')} amount={totalFormatted} />
label={intl.get('due_amount')}
amount={totalDueAmount}
currencyCode={currency_code}
/>
); );
} }

View File

@@ -336,8 +336,12 @@ export const useBillSubtotalFormatted = () => {
*/ */
export const useBillDiscountAmount = () => { export const useBillDiscountAmount = () => {
const { values } = useFormikContext(); const { values } = useFormikContext();
const subtotal = useBillSubtotal();
const discount = toSafeNumber(values.discount);
return toSafeNumber(values.discount); return values?.discount_type === 'percentage'
? (subtotal * discount) / 100
: discount;
}; };
/** /**
@@ -384,7 +388,6 @@ export const useBillTotalTaxAmount = () => {
.filter((entry) => entry.tax_amount) .filter((entry) => entry.tax_amount)
.sumBy('tax_amount') .sumBy('tax_amount')
.value(); .value();
}, [values.entries]); }, [values.entries]);
}; };

View File

@@ -2,33 +2,23 @@
import React from 'react'; import React from 'react';
import intl from 'react-intl-universal'; import intl from 'react-intl-universal';
import classNames from 'classnames'; import classNames from 'classnames';
import { useFormikContext } from 'formik';
import { CLASSES } from '@/constants/classes'; import { CLASSES } from '@/constants/classes';
import VendorCreditNoteFormHeaderFields from './VendorCreditNoteFormHeaderFields'; import VendorCreditNoteFormHeaderFields from './VendorCreditNoteFormHeaderFields';
import { getEntriesTotal } from '@/containers/Entries/utils';
import { PageFormBigNumber } from '@/components'; import { PageFormBigNumber } from '@/components';
import { useVendorCreditTotalFormatted } from './utils';
/** /**
* Vendor Credit note header. * Vendor Credit note header.
*/ */
function VendorCreditNoteFormHeader() { function VendorCreditNoteFormHeader() {
const { values:{entries ,currency_code} } = useFormikContext(); const totalFormatted = useVendorCreditTotalFormatted();
// Calculate the total amount.
const totalAmount = React.useMemo(
() => getEntriesTotal(entries),
[entries],
);
return ( return (
<div className={classNames(CLASSES.PAGE_FORM_HEADER)}> <div className={classNames(CLASSES.PAGE_FORM_HEADER)}>
<VendorCreditNoteFormHeaderFields /> <VendorCreditNoteFormHeaderFields />
<PageFormBigNumber <PageFormBigNumber
label={intl.get('vendor_credits.label.amount_to_credit')} label={intl.get('vendor_credits.label.amount_to_credit')}
amount={totalAmount} amount={totalFormatted}
currencyCode={currency_code}
/> />
</div> </div>
); );

View File

@@ -206,8 +206,12 @@ export const useVendorCreditSubtotal = () => {
*/ */
export const useVendorCreditDiscountAmount = () => { export const useVendorCreditDiscountAmount = () => {
const { values } = useFormikContext(); const { values } = useFormikContext();
const subtotal = useVendorCreditSubtotal();
const discount = toSafeNumber(values.discount);
return toSafeNumber(values.discount); return values.discount_type === 'percentage'
? (subtotal * discount) / 100
: discount;
}; };
/** /**

View File

@@ -1,11 +1,9 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import intl from 'react-intl-universal'; import intl from 'react-intl-universal';
import { useFormikContext } from 'formik';
import CreditNoteFormHeaderFields from './CreditNoteFormHeaderFields'; import CreditNoteFormHeaderFields from './CreditNoteFormHeaderFields';
import { getEntriesTotal } from '@/containers/Entries/utils';
import { Group, PageFormBigNumber } from '@/components'; import { Group, PageFormBigNumber } from '@/components';
import { useCreditNoteTotalFormatted } from './utils';
/** /**
* Credit note header. * Credit note header.
@@ -31,18 +29,12 @@ function CreditNoteFormHeader() {
* @returns {React.ReactNode} * @returns {React.ReactNode}
*/ */
function CreditNoteFormBigNumber() { function CreditNoteFormBigNumber() {
const { const totalFormatted = useCreditNoteTotalFormatted();
values: { entries, currency_code },
} = useFormikContext();
// Calculate the total amount.
const totalAmount = React.useMemo(() => getEntriesTotal(entries), [entries]);
return ( return (
<PageFormBigNumber <PageFormBigNumber
label={intl.get('credit_note.label_amount_to_credit')} label={intl.get('credit_note.label_amount_to_credit')}
amount={totalAmount} amount={totalFormatted}
currencyCode={currency_code}
/> />
); );
} }

View File

@@ -1,5 +1,6 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import { useFormikContext } from 'formik';
import EstimateNumberDialog from '@/containers/Dialogs/EstimateNumberDialog'; import EstimateNumberDialog from '@/containers/Dialogs/EstimateNumberDialog';
/** /**

View File

@@ -1,12 +1,10 @@
// @ts-nocheck // @ts-nocheck
import React, { useMemo } from 'react'; import React from 'react';
import intl from 'react-intl-universal'; import intl from 'react-intl-universal';
import { useFormikContext } from 'formik';
import { x } from '@xstyled/emotion';
import EstimateFormHeaderFields from './EstimateFormHeaderFields'; import EstimateFormHeaderFields from './EstimateFormHeaderFields';
import { getEntriesTotal } from '@/containers/Entries/utils';
import { Group, PageFormBigNumber } from '@/components'; import { Group, PageFormBigNumber } from '@/components';
import { useEstimateTotalFormatted } from './utils';
// Estimate form top header. // Estimate form top header.
function EstimateFormHeader() { function EstimateFormHeader() {
@@ -29,19 +27,10 @@ function EstimateFormHeader() {
* @returns {React.ReactNode} * @returns {React.ReactNode}
*/ */
function EstimateFormBigTotal() { function EstimateFormBigTotal() {
const { const totalFormatted = useEstimateTotalFormatted();
values: { entries, currency_code },
} = useFormikContext();
// Calculate the total due amount of bill entries.
const totalDueAmount = useMemo(() => getEntriesTotal(entries), [entries]);
return ( return (
<PageFormBigNumber <PageFormBigNumber label={intl.get('amount')} amount={totalFormatted} />
label={intl.get('amount')}
amount={totalDueAmount}
currencyCode={currency_code}
/>
); );
} }

View File

@@ -245,6 +245,7 @@ export const useEstimateSubtotalFormatted = () => {
*/ */
export const useEstimateDiscount = () => { export const useEstimateDiscount = () => {
const { values } = useFormikContext(); const { values } = useFormikContext();
const subtotal = useEstimateSubtotal();
const discount = toSafeNumber(values.discount); const discount = toSafeNumber(values.discount);
return values?.discount_type === 'percentage' return values?.discount_type === 'percentage'

View File

@@ -1,10 +1,9 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React from 'react';
import intl from 'react-intl-universal'; import intl from 'react-intl-universal';
import { useFormikContext } from 'formik';
import { Group, PageFormBigNumber } from '@/components'; import { Group, PageFormBigNumber } from '@/components';
import InvoiceFormHeaderFields from './InvoiceFormHeaderFields'; import InvoiceFormHeaderFields from './InvoiceFormHeaderFields';
import { useInvoiceDueAmount } from './utils'; import { useInvoiceTotalFormatted } from './utils';
/** /**
* Invoice form header section. * Invoice form header section.
@@ -29,19 +28,11 @@ function InvoiceFormHeader() {
* @returns {React.ReactNode} * @returns {React.ReactNode}
*/ */
function InvoiceFormBigTotal() { function InvoiceFormBigTotal() {
const {
values: { currency_code },
} = useFormikContext();
// Calculate the total due amount of invoice entries. // Calculate the total due amount of invoice entries.
const totalDueAmount = useInvoiceDueAmount(); const totalFormatted = useInvoiceTotalFormatted();
return ( return (
<PageFormBigNumber <PageFormBigNumber label={intl.get('due_amount')} amount={totalFormatted} />
label={intl.get('due_amount')}
amount={totalDueAmount}
currencyCode={currency_code}
/>
); );
} }
export default InvoiceFormHeader; export default InvoiceFormHeader;

View File

@@ -324,7 +324,7 @@ export const useInvoiceSubtotalFormatted = () => {
export const useInvoiceDiscountAmount = () => { export const useInvoiceDiscountAmount = () => {
const { values } = useFormikContext(); const { values } = useFormikContext();
const subtotal = useInvoiceSubtotal(); const subtotal = useInvoiceSubtotal();
const discount = parseFloat(values.discount); const discount = toSafeNumber(values.discount);
return values?.discount_type === 'percentage' return values?.discount_type === 'percentage'
? (subtotal * discount) / 100 ? (subtotal * discount) / 100
@@ -350,7 +350,7 @@ export const useInvoiceDiscountAmountFormatted = () => {
*/ */
export const useInvoiceAdjustmentAmount = () => { export const useInvoiceAdjustmentAmount = () => {
const { values } = useFormikContext(); const { values } = useFormikContext();
const adjustment = parseFloat(values.adjustment); const adjustment = toSafeNumber(values.adjustment);
return adjustment; return adjustment;
}; };

View File

@@ -1,10 +1,9 @@
// @ts-nocheck // @ts-nocheck
import React, { useMemo } from 'react'; import React from 'react';
import intl from 'react-intl-universal'; import intl from 'react-intl-universal';
import { useFormikContext } from 'formik';
import { Group, PageFormBigNumber } from '@/components'; import { Group, PageFormBigNumber } from '@/components';
import ReceiptFormHeaderFields from './ReceiptFormHeaderFields'; import ReceiptFormHeaderFields from './ReceiptFormHeaderFields';
import { getEntriesTotal } from '@/containers/Entries/utils'; import { useReceiptTotalFormatted } from './utils';
/** /**
* Receipt form header section. * Receipt form header section.
@@ -35,19 +34,10 @@ function ReceiptFormHeader({
* @returns {React.ReactNode} * @returns {React.ReactNode}
*/ */
function ReceiptFormHeaderBigTotal() { function ReceiptFormHeaderBigTotal() {
const { const totalFormatted = useReceiptTotalFormatted();
values: { currency_code, entries },
} = useFormikContext();
// Calculate the total due amount of bill entries.
const totalDueAmount = useMemo(() => getEntriesTotal(entries), [entries]);
return ( return (
<PageFormBigNumber <PageFormBigNumber label={intl.get('due_amount')} amount={totalFormatted} />
label={intl.get('due_amount')}
amount={totalDueAmount}
currencyCode={currency_code}
/>
); );
} }

View File

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

View File

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

View File

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

View File

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

View File

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