feat: implement auto entries rates re-calculation after change the exchange rate

This commit is contained in:
Ahmed Bouhuolia
2024-01-14 14:44:48 +02:00
parent 2cb8c2932f
commit 2b03ac7f16
24 changed files with 522 additions and 241 deletions

View File

@@ -1,5 +1,4 @@
// @ts-nocheck
import React, { useMemo } from 'react';
import intl from 'react-intl-universal';
import classNames from 'classnames';
import { Formik, Form } from 'formik';
@@ -19,7 +18,10 @@ import EstimateFloatingActions from './EstimateFloatingActions';
import EstimateFormFooter from './EstimateFormFooter';
import EstimateFormDialogs from './EstimateFormDialogs';
import EstimtaeFormTopBar from './EstimtaeFormTopBar';
import { EstimateIncrementSyncSettingsToForm } from './components';
import {
EstimateIncrementSyncSettingsToForm,
EstimateSyncAutoExRateToForm,
} from './components';
import withSettings from '@/containers/Settings/withSettings';
import withCurrentOrganization from '@/containers/Organization/withCurrentOrganization';
@@ -170,6 +172,7 @@ function EstimateForm({
{/*------- Effects -------*/}
<EstimateIncrementSyncSettingsToForm />
<EstimateSyncAutoExRateToForm />
</Form>
</Formik>
</div>

View File

@@ -1,5 +1,4 @@
// @ts-nocheck
import React from 'react';
import styled from 'styled-components';
import classNames from 'classnames';
import { FormGroup, InputGroup, Position, Classes } from '@blueprintjs/core';
@@ -24,7 +23,6 @@ import {
import { customersFieldShouldUpdate } from './utils';
import { CLASSES } from '@/constants/classes';
import { Features } from '@/constants';
import { ProjectsSelect } from '@/containers/Projects/components';
import {
EstimateExchangeRateInputField,
@@ -32,12 +30,13 @@ import {
} from './components';
import { EstimateFormEstimateNumberField } from './EstimateFormEstimateNumberField';
import { useEstimateFormContext } from './EstimateFormProvider';
import { useCustomerUpdateExRate } from '@/containers/Entries/withExRateItemEntriesPriceRecalc';
/**
* Estimate form header.
*/
export default function EstimateFormHeader() {
const { customers, projects } = useEstimateFormContext();
const { projects } = useEstimateFormContext();
return (
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
@@ -45,10 +44,8 @@ export default function EstimateFormHeader() {
<EstimateFormCustomerSelect />
{/* ----------- Exchange Rate ----------- */}
<EstimateExchangeRateInputField
name={'exchange_rate'}
formGroupProps={{ label: ' ', inline: true }}
/>
<EstimateExchangeRateInputField />
{/* ----------- Estimate Date ----------- */}
<FastField name={'estimate_date'}>
{({ form, field: { value }, meta: { error, touched } }) => (
@@ -151,6 +148,16 @@ function EstimateFormCustomerSelect() {
const { setFieldValue, values } = useFormikContext();
const { customers } = useEstimateFormContext();
const updateEntries = useCustomerUpdateExRate();
// Handles the customer item change.
const handleItemChange = (customer) => {
setFieldValue('customer_id', customer.id);
setFieldValue('currency_code', customer?.currency_code);
updateEntries(customer);
};
return (
<FFormGroup
label={<T id={'customer_name'} />}
@@ -165,10 +172,7 @@ function EstimateFormCustomerSelect() {
name={'customer_id'}
items={customers}
placeholder={<T id={'select_customer_account'} />}
onItemChange={(customer) => {
setFieldValue('customer_id', customer.id);
setFieldValue('currency_code', customer?.currency_code);
}}
onItemChange={handleItemChange}
popoverFill={true}
allowCreate={true}
fastField={true}

View File

@@ -6,6 +6,7 @@ import '@/style/pages/SaleEstimate/PageForm.scss';
import EstimateForm from './EstimateForm';
import { EstimateFormProvider } from './EstimateFormProvider';
import { AutoExchangeRateProvider } from '@/containers/Entries/AutoExchangeProvider';
/**
* Estimate form page.
@@ -16,7 +17,9 @@ export default function EstimateFormPage() {
return (
<EstimateFormProvider estimateId={idInteger}>
<EstimateForm />
<AutoExchangeRateProvider>
<EstimateForm />
</AutoExchangeRateProvider>
</EstimateFormProvider>
);
}

View File

@@ -1,24 +1,30 @@
// @ts-nocheck
import React, { useEffect } from 'react';
import React, { useRef } from 'react';
import intl from 'react-intl-universal';
import { Button } from '@blueprintjs/core';
import * as R from 'ramda';
import { useFormikContext } from 'formik';
import { ExchangeRateInputGroup } from '@/components';
import { useCurrentOrganization } from '@/hooks/state';
import { useEstimateIsForeignCustomer } from './utils';
import withSettings from '@/containers/Settings/withSettings';
import { useEstimateIsForeignCustomer, useEstimateTotals } from './utils';
import { transactionNumber } from '@/utils';
import { useUpdateEffect } from '@/hooks';
import withSettings from '@/containers/Settings/withSettings';
import {
useSyncExRateToForm,
withExchangeRateFetchingLoading,
withExchangeRateItemEntriesPriceRecalc,
} from '@/containers/Entries/withExRateItemEntriesPriceRecalc';
import withDialogActions from '@/containers/Dialog/withDialogActions';
import { DialogsName } from '@/constants/dialogs';
/**
* Estimate exchange rate input field.
* @returns {JSX.Element}
*/
export function EstimateExchangeRateInputField({ ...props }) {
function EstimateExchangeRateInputFieldRoot({ ...props }) {
const currentOrganization = useCurrentOrganization();
const { values } = useFormikContext();
const isForeignCustomer = useEstimateIsForeignCustomer();
// Can't continue if the customer is not foreign.
@@ -27,13 +33,26 @@ export function EstimateExchangeRateInputField({ ...props }) {
}
return (
<ExchangeRateInputGroup
name={'exchange_rate'}
fromCurrency={values.currency_code}
toCurrency={currentOrganization.base_currency}
formGroupProps={{ label: ' ', inline: true }}
withPopoverRecalcConfirm
{...props}
/>
);
}
/**
* Renders the estimate exchange rate input field with exchange rate
* with item entries price re-calc once exchange rate change.
* @returns {JSX.Element}
*/
export const EstimateExchangeRateInputField = R.compose(
withExchangeRateFetchingLoading,
withExchangeRateItemEntriesPriceRecalc,
)(EstimateExchangeRateInputFieldRoot);
/**
* Estimate project select.
* @returns {JSX.Element}
@@ -72,3 +91,32 @@ export const EstimateIncrementSyncSettingsToForm = R.compose(
return null;
});
/**
* Syncs the auto exchange rate to the estimate form and shows up popup to user
* as an indication the entries rates have been changed.
* @returns {React.ReactNode}
*/
export const EstimateSyncAutoExRateToForm = R.compose(withDialogActions)(
({
// #withDialogActions
openDialog,
}) => {
const { total } = useEstimateTotals();
const timeout = useRef();
useSyncExRateToForm({
onSynced: () => {
// If the total bigger then zero show alert to the user after adjusting entries.
if (total > 0) {
clearTimeout(timeout.current);
timeout.current = setTimeout(() => {
openDialog(DialogsName.InvoiceExchangeRateChangeNotice);
}, 500);
}
},
});
return null;
},
);