fix: wrong invoice due amount

This commit is contained in:
Ahmed Bouhuolia
2024-08-07 18:52:36 +02:00
parent 8cab012324
commit 3d200f4d7d
3 changed files with 88 additions and 71 deletions

View File

@@ -10,18 +10,16 @@ import {
TotalLineBorderStyle, TotalLineBorderStyle,
TotalLineTextStyle, TotalLineTextStyle,
} from '@/components'; } from '@/components';
import { useInvoiceAggregatedTaxRates, useInvoiceTotals } from './utils'; import { useInvoiceAggregatedTaxRates } from './utils';
import { TaxType } from '@/interfaces/TaxRates'; import { TaxType } from '@/interfaces/TaxRates';
import {
InvoiceDueAmountFormatted,
InvoicePaidAmountFormatted,
InvoiceSubTotalFormatted,
InvoiceTotalFormatted,
} from './components';
export function InvoiceFormFooterRight() { export function InvoiceFormFooterRight() {
// Calculate the total due amount of invoice entries.
const {
formattedSubtotal,
formattedTotal,
formattedDueTotal,
formattedPaymentTotal,
} = useInvoiceTotals();
const { const {
values: { inclusive_exclusive_tax, currency_code }, values: { inclusive_exclusive_tax, currency_code },
} = useFormikContext(); } = useFormikContext();
@@ -38,7 +36,7 @@ export function InvoiceFormFooterRight() {
: 'Subtotal'} : 'Subtotal'}
</> </>
} }
value={formattedSubtotal} value={<InvoiceSubTotalFormatted />}
/> />
{taxEntries.map((tax, index) => ( {taxEntries.map((tax, index) => (
<TotalLine <TotalLine
@@ -50,18 +48,18 @@ export function InvoiceFormFooterRight() {
))} ))}
<TotalLine <TotalLine
title={`Total (${currency_code})`} title={`Total (${currency_code})`}
value={formattedTotal} value={<InvoiceTotalFormatted />}
borderStyle={TotalLineBorderStyle.SingleDark} borderStyle={TotalLineBorderStyle.SingleDark}
textStyle={TotalLineTextStyle.Bold} textStyle={TotalLineTextStyle.Bold}
/> />
<TotalLine <TotalLine
title={<T id={'invoice_form.label.payment_amount'} />} title={<T id={'invoice_form.label.payment_amount'} />}
value={formattedPaymentTotal} value={<InvoicePaidAmountFormatted />}
borderStyle={TotalLineBorderStyle.None} borderStyle={TotalLineBorderStyle.None}
/> />
<TotalLine <TotalLine
title={<T id={'invoice_form.label.due_amount'} />} title={<T id={'invoice_form.label.due_amount'} />}
value={formattedDueTotal} value={<InvoiceDueAmountFormatted />}
textStyle={TotalLineTextStyle.Bold} textStyle={TotalLineTextStyle.Bold}
/> />
</InvoiceTotalLines> </InvoiceTotalLines>

View File

@@ -4,14 +4,21 @@ import intl from 'react-intl-universal';
import * as R from 'ramda'; import * as R from 'ramda';
import { Button } from '@blueprintjs/core'; import { Button } from '@blueprintjs/core';
import { useFormikContext } from 'formik'; import { useFormikContext } from 'formik';
import { ExchangeRateInputGroup } from '@/components'; import { ExchangeRateInputGroup, FormatNumber } from '@/components';
import { useCurrentOrganization } from '@/hooks/state'; import { useCurrentOrganization } from '@/hooks/state';
import { useInvoiceIsForeignCustomer, useInvoiceTotal } from './utils'; import {
import withSettings from '@/containers/Settings/withSettings'; useInvoiceCurrencyCode,
useInvoiceDueAmount,
useInvoiceIsForeignCustomer,
useInvoicePaidAmount,
useInvoiceSubtotal,
useInvoiceTotal,
} from './utils';
import { useUpdateEffect } from '@/hooks'; import { useUpdateEffect } from '@/hooks';
import { transactionNumber } from '@/utils'; import { transactionNumber } from '@/utils';
import withDialogActions from '@/containers/Dialog/withDialogActions';
import { DialogsName } from '@/constants/dialogs'; import { DialogsName } from '@/constants/dialogs';
import withSettings from '@/containers/Settings/withSettings';
import withDialogActions from '@/containers/Dialog/withDialogActions';
import { import {
useSyncExRateToForm, useSyncExRateToForm,
withExchangeRateFetchingLoading, withExchangeRateFetchingLoading,
@@ -109,3 +116,47 @@ export const InvoiceExchangeRateSync = R.compose(withDialogActions)(
return null; return null;
}, },
); );
/**
*Renders the invoice formatted total.
* @returns {JSX.Element}
*/
export const InvoiceTotalFormatted = () => {
const currencyCode = useInvoiceCurrencyCode();
const total = useInvoiceTotal();
return <FormatNumber value={total} currency={currencyCode} />;
};
/**
* Renders the invoice formatted subtotal.
* @returns {JSX.Element}
*/
export const InvoiceSubTotalFormatted = () => {
const currencyCode = useInvoiceCurrencyCode();
const subTotal = useInvoiceSubtotal();
return <FormatNumber value={subTotal} currency={currencyCode} />;
};
/**
* Renders the invoice formatted due amount.
* @returns {JSX.Element}
*/
export const InvoiceDueAmountFormatted = () => {
const currencyCode = useInvoiceCurrencyCode();
const dueAmount = useInvoiceDueAmount();
return <FormatNumber value={dueAmount} currency={currencyCode} />;
};
/**
* Renders the invoice formatted paid amount.
* @returns {JSX.Element}
*/
export const InvoicePaidAmountFormatted = () => {
const currencyCode = useInvoiceCurrencyCode();
const paidAmount = useInvoicePaidAmount();
return <FormatNumber value={paidAmount} currency={currencyCode} />;
};

View File

@@ -269,59 +269,6 @@ export const useInvoiceSubtotal = () => {
return React.useMemo(() => getEntriesTotal(entries), [entries]); return React.useMemo(() => getEntriesTotal(entries), [entries]);
}; };
/**
* Retreives the invoice totals.
*/
export const useInvoiceTotals = () => {
const {
values: { entries, currency_code: currencyCode },
} = useFormikContext();
// Retrieves the invoice entries total.
const total = React.useMemo(() => getEntriesTotal(entries), [entries]);
const total_ = useInvoiceTotal();
// 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],
);
// Retrieves the payment total.
const paymentTotal = React.useMemo(() => 0, []);
// Retireves the formatted payment total.
const formattedPaymentTotal = React.useMemo(
() => formattedAmount(paymentTotal, currencyCode),
[paymentTotal, currencyCode],
);
// Retrieves the formatted due total.
const dueTotal = React.useMemo(
() => total_ - paymentTotal,
[total_, paymentTotal],
);
// Retrieves the formatted due total.
const formattedDueTotal = React.useMemo(
() => formattedAmount(dueTotal, currencyCode),
[dueTotal, currencyCode],
);
return {
total,
paymentTotal,
dueTotal,
formattedTotal,
formattedSubtotal,
formattedPaymentTotal,
formattedDueTotal,
};
};
/** /**
* Detarmines whether the invoice has foreign customer. * Detarmines whether the invoice has foreign customer.
* @returns {boolean} * @returns {boolean}
@@ -409,14 +356,25 @@ export const useInvoiceTotal = () => {
); );
}; };
/**
* Retrieves the paid amount of the invoice.
* @returns {number}
*/
export const useInvoicePaidAmount = () => {
const { invoice } = useInvoiceFormContext();
return invoice?.payment_amount || 0;
};
/** /**
* Retreives the invoice due amount. * Retreives the invoice due amount.
* @returns {number} * @returns {number}
*/ */
export const useInvoiceDueAmount = () => { export const useInvoiceDueAmount = () => {
const total = useInvoiceTotal(); const total = useInvoiceTotal();
const paidAmount = useInvoicePaidAmount();
return total; return Math.max(total - paidAmount, 0);
}; };
/** /**
@@ -438,3 +396,13 @@ export const useIsInvoiceTaxExclusive = () => {
return values.inclusive_exclusive_tax === TaxType.Exclusive; return values.inclusive_exclusive_tax === TaxType.Exclusive;
}; };
/**
* Retrieves the invoice currency code.
* @returns {string}
*/
export const useInvoiceCurrencyCode = () => {
const { values } = useFormikContext();
return values.currency_code;
};