mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-21 23:30:32 +00:00
fix: the auto-increment of transactions.
This commit is contained in:
@@ -46,4 +46,5 @@ export enum DialogsName {
|
|||||||
EstimateExpenseForm = 'estimate-expense-form',
|
EstimateExpenseForm = 'estimate-expense-form',
|
||||||
ProjectInvoicingForm = 'project-invoicing-form',
|
ProjectInvoicingForm = 'project-invoicing-form',
|
||||||
ProjectBillableEntriesForm = 'project-billable-entries',
|
ProjectBillableEntriesForm = 'project-billable-entries',
|
||||||
|
InvoiceNumberSettings = 'InvoiceNumberSettings'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { Formik, Form } from 'formik';
|
|||||||
import { Intent } from '@blueprintjs/core';
|
import { Intent } from '@blueprintjs/core';
|
||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
import * as R from 'ramda';
|
import * as R from 'ramda';
|
||||||
import { defaultTo, isEmpty, omit } from 'lodash';
|
import { isEmpty, omit } from 'lodash';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { useHistory } from 'react-router-dom';
|
import { useHistory } from 'react-router-dom';
|
||||||
|
|
||||||
@@ -31,6 +31,7 @@ import {
|
|||||||
transformToEditForm,
|
transformToEditForm,
|
||||||
defaultManualJournal,
|
defaultManualJournal,
|
||||||
} from './utils';
|
} from './utils';
|
||||||
|
import { JournalSyncIncrementSettingsToForm } from './components';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Journal entries form.
|
* Journal entries form.
|
||||||
@@ -40,6 +41,7 @@ function MakeJournalEntriesForm({
|
|||||||
journalNextNumber,
|
journalNextNumber,
|
||||||
journalNumberPrefix,
|
journalNumberPrefix,
|
||||||
journalAutoIncrement,
|
journalAutoIncrement,
|
||||||
|
|
||||||
// #withCurrentOrganization
|
// #withCurrentOrganization
|
||||||
organization: { base_currency },
|
organization: { base_currency },
|
||||||
}) {
|
}) {
|
||||||
@@ -179,6 +181,9 @@ function MakeJournalEntriesForm({
|
|||||||
|
|
||||||
{/* --------- Dialogs --------- */}
|
{/* --------- Dialogs --------- */}
|
||||||
<MakeJournalFormDialogs />
|
<MakeJournalFormDialogs />
|
||||||
|
|
||||||
|
{/* --------- Effects --------- */}
|
||||||
|
<JournalSyncIncrementSettingsToForm />
|
||||||
</Form>
|
</Form>
|
||||||
</Formik>
|
</Formik>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -8,6 +8,19 @@ import { PageFormBigNumber, FormattedMessage as T } from '@/components';
|
|||||||
import MakeJournalEntriesHeaderFields from './MakeJournalEntriesHeaderFields';
|
import MakeJournalEntriesHeaderFields from './MakeJournalEntriesHeaderFields';
|
||||||
|
|
||||||
export default function MakeJournalEntriesHeader() {
|
export default function MakeJournalEntriesHeader() {
|
||||||
|
return (
|
||||||
|
<div className={classNames(CLASSES.PAGE_FORM_HEADER)}>
|
||||||
|
<MakeJournalEntriesHeaderFields />
|
||||||
|
<MakeJournalHeaderBigNumber />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Big total number of make journal header.
|
||||||
|
* @returns {React.ReactNode}
|
||||||
|
*/
|
||||||
|
function MakeJournalHeaderBigNumber() {
|
||||||
const {
|
const {
|
||||||
values: { entries, currency_code },
|
values: { entries, currency_code },
|
||||||
} = useFormikContext();
|
} = useFormikContext();
|
||||||
@@ -17,14 +30,10 @@ export default function MakeJournalEntriesHeader() {
|
|||||||
const total = Math.max(totalCredit, totalDebit);
|
const total = Math.max(totalCredit, totalDebit);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classNames(CLASSES.PAGE_FORM_HEADER)}>
|
<PageFormBigNumber
|
||||||
<MakeJournalEntriesHeaderFields />
|
label={<T id={'amount'} />}
|
||||||
|
amount={total}
|
||||||
<PageFormBigNumber
|
currencyCode={currency_code}
|
||||||
label={<T id={'amount'} />}
|
/>
|
||||||
amount={total}
|
|
||||||
currencyCode={currency_code}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,30 +25,24 @@ import {
|
|||||||
Icon,
|
Icon,
|
||||||
InputPrependButton,
|
InputPrependButton,
|
||||||
CurrencySelectList,
|
CurrencySelectList,
|
||||||
FormattedMessage as T
|
FormattedMessage as T,
|
||||||
} from '@/components';
|
} from '@/components';
|
||||||
import { useMakeJournalFormContext } from './MakeJournalProvider';
|
import { useMakeJournalFormContext } from './MakeJournalProvider';
|
||||||
import { JournalExchangeRateInputField } from './components';
|
import { JournalExchangeRateInputField } from './components';
|
||||||
|
import { currenciesFieldShouldUpdate } from './utils';
|
||||||
|
|
||||||
import withSettings from '@/containers/Settings/withSettings';
|
import withSettings from '@/containers/Settings/withSettings';
|
||||||
import withDialogActions from '@/containers/Dialog/withDialogActions';
|
import withDialogActions from '@/containers/Dialog/withDialogActions';
|
||||||
import {
|
|
||||||
currenciesFieldShouldUpdate,
|
|
||||||
useObserveJournalNoSettings,
|
|
||||||
} from './utils';
|
|
||||||
/**
|
/**
|
||||||
* Make journal entries header.
|
* Make journal entries header.
|
||||||
*/
|
*/
|
||||||
function MakeJournalEntriesHeader({
|
function MakeJournalEntriesHeader({
|
||||||
// #ownProps
|
|
||||||
onJournalNumberChanged,
|
|
||||||
|
|
||||||
// #withDialog
|
// #withDialog
|
||||||
openDialog,
|
openDialog,
|
||||||
|
|
||||||
// #withSettings
|
// #withSettings
|
||||||
journalAutoIncrement,
|
journalAutoIncrement,
|
||||||
journalNextNumber,
|
|
||||||
journalNumberPrefix,
|
|
||||||
}) {
|
}) {
|
||||||
const { currencies } = useMakeJournalFormContext();
|
const { currencies } = useMakeJournalFormContext();
|
||||||
|
|
||||||
@@ -71,8 +65,6 @@ function MakeJournalEntriesHeader({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
useObserveJournalNoSettings(journalNumberPrefix, journalNextNumber);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
|
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
|
||||||
{/*------------ Posting date -----------*/}
|
{/*------------ Posting date -----------*/}
|
||||||
@@ -224,7 +216,5 @@ export default compose(
|
|||||||
withDialogActions,
|
withDialogActions,
|
||||||
withSettings(({ manualJournalsSettings }) => ({
|
withSettings(({ manualJournalsSettings }) => ({
|
||||||
journalAutoIncrement: manualJournalsSettings?.autoIncrement,
|
journalAutoIncrement: manualJournalsSettings?.autoIncrement,
|
||||||
journalNextNumber: manualJournalsSettings?.nextNumber,
|
|
||||||
journalNumberPrefix: manualJournalsSettings?.numberPrefix,
|
|
||||||
})),
|
})),
|
||||||
)(MakeJournalEntriesHeader);
|
)(MakeJournalEntriesHeader);
|
||||||
|
|||||||
@@ -16,11 +16,9 @@ export default function MakeJournalFormDialogs() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<JournalNumberDialog
|
||||||
<JournalNumberDialog
|
dialogName={'journal-number-form'}
|
||||||
dialogName={'journal-number-form'}
|
onConfirm={handleConfirm}
|
||||||
onConfirm={handleConfirm}
|
/>
|
||||||
/>
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import React from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
import { Menu, MenuItem, Position, Button } from '@blueprintjs/core';
|
import { Menu, MenuItem, Position, Button } from '@blueprintjs/core';
|
||||||
import { Popover2 } from '@blueprintjs/popover2';
|
import { Popover2 } from '@blueprintjs/popover2';
|
||||||
import { useFormikContext } from 'formik';
|
import { useFormikContext } from 'formik';
|
||||||
|
import * as R from 'ramda';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ExchangeRateInputGroup,
|
ExchangeRateInputGroup,
|
||||||
@@ -24,6 +25,9 @@ import { CellType, Features, Align } from '@/constants';
|
|||||||
|
|
||||||
import { useCurrentOrganization, useFeatureCan } from '@/hooks/state';
|
import { useCurrentOrganization, useFeatureCan } from '@/hooks/state';
|
||||||
import { useJournalIsForeign } from './utils';
|
import { useJournalIsForeign } from './utils';
|
||||||
|
import withSettings from '@/containers/Settings/withSettings';
|
||||||
|
import { transactionNumber } from '@/utils';
|
||||||
|
import { useUpdateEffect } from '@/hooks';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contact header cell.
|
* Contact header cell.
|
||||||
@@ -199,3 +203,34 @@ export function JournalExchangeRateInputField({ ...props }) {
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Syncs journal auto-increment settings to form.
|
||||||
|
* @return {React.ReactNode}
|
||||||
|
*/
|
||||||
|
export const JournalSyncIncrementSettingsToForm = R.compose(
|
||||||
|
withSettings(({ manualJournalsSettings }) => ({
|
||||||
|
journalAutoIncrement: manualJournalsSettings?.autoIncrement,
|
||||||
|
journalNextNumber: manualJournalsSettings?.nextNumber,
|
||||||
|
journalNumberPrefix: manualJournalsSettings?.numberPrefix,
|
||||||
|
})),
|
||||||
|
)(({ journalAutoIncrement, journalNextNumber, journalNumberPrefix }) => {
|
||||||
|
const { setFieldValue } = useFormikContext();
|
||||||
|
|
||||||
|
useUpdateEffect(() => {
|
||||||
|
if (!journalAutoIncrement) return null;
|
||||||
|
|
||||||
|
const journalNo = transactionNumber(journalNumberPrefix, journalNextNumber);
|
||||||
|
setFieldValue('journal_number', journalNo);
|
||||||
|
}, [
|
||||||
|
setFieldValue,
|
||||||
|
journalNumberPrefix,
|
||||||
|
journalNextNumber,
|
||||||
|
journalAutoIncrement,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
JournalSyncIncrementSettingsToForm.displayName =
|
||||||
|
'JournalSyncIncrementSettingsToForm';
|
||||||
|
|||||||
@@ -174,15 +174,6 @@ export const transformErrors = (resErrors, { setErrors, errors }) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useObserveJournalNoSettings = (prefix, nextNumber) => {
|
|
||||||
const { setFieldValue } = useFormikContext();
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
const journalNo = transactionNumber(prefix, nextNumber);
|
|
||||||
setFieldValue('journal_number', journalNo);
|
|
||||||
}, [setFieldValue, prefix, nextNumber]);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detarmines entries fast field should update.
|
* Detarmines entries fast field should update.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
transformFormToSettings,
|
transformFormToSettings,
|
||||||
transformSettingsToForm,
|
transformSettingsToForm,
|
||||||
} from '@/containers/JournalNumber/utils';
|
} from '@/containers/JournalNumber/utils';
|
||||||
|
import { DialogsName } from '@/constants/dialogs';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* invoice number dialog's content.
|
* invoice number dialog's content.
|
||||||
@@ -39,7 +40,7 @@ function InvoiceNumberDialogContent({
|
|||||||
// Handle the form success.
|
// Handle the form success.
|
||||||
const handleSuccess = () => {
|
const handleSuccess = () => {
|
||||||
setSubmitting(false);
|
setSubmitting(false);
|
||||||
closeDialog('invoice-number-form');
|
closeDialog(DialogsName.InvoiceNumberSettings);
|
||||||
onConfirm(values);
|
onConfirm(values);
|
||||||
};
|
};
|
||||||
// Handle the form errors.
|
// Handle the form errors.
|
||||||
@@ -56,10 +57,9 @@ function InvoiceNumberDialogContent({
|
|||||||
// Save the settings.
|
// Save the settings.
|
||||||
saveSettings({ options }).then(handleSuccess).catch(handleErrors);
|
saveSettings({ options }).then(handleSuccess).catch(handleErrors);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle the dialog close.
|
// Handle the dialog close.
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
closeDialog('invoice-number-form');
|
closeDialog(DialogsName.InvoiceNumberSettings);
|
||||||
};
|
};
|
||||||
// Handle form change.
|
// Handle form change.
|
||||||
const handleChange = (values) => {
|
const handleChange = (values) => {
|
||||||
@@ -71,17 +71,19 @@ function InvoiceNumberDialogContent({
|
|||||||
? intl.get('invoice.auto_increment.auto')
|
? intl.get('invoice.auto_increment.auto')
|
||||||
: intl.get('invoice.auto_increment.manually');
|
: intl.get('invoice.auto_increment.manually');
|
||||||
|
|
||||||
|
const initialFormValues = {
|
||||||
|
...transformSettingsToForm({
|
||||||
|
nextNumber,
|
||||||
|
numberPrefix,
|
||||||
|
autoIncrement,
|
||||||
|
}),
|
||||||
|
...initialValues,
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InvoiceNumberDialogProvider>
|
<InvoiceNumberDialogProvider>
|
||||||
<ReferenceNumberForm
|
<ReferenceNumberForm
|
||||||
initialValues={{
|
initialValues={initialFormValues}
|
||||||
...transformSettingsToForm({
|
|
||||||
nextNumber,
|
|
||||||
numberPrefix,
|
|
||||||
autoIncrement,
|
|
||||||
}),
|
|
||||||
...initialValues,
|
|
||||||
}}
|
|
||||||
description={description}
|
description={description}
|
||||||
onSubmit={handleSubmitForm}
|
onSubmit={handleSubmitForm}
|
||||||
onClose={handleClose}
|
onClose={handleClose}
|
||||||
|
|||||||
@@ -16,10 +16,10 @@ import { saveInvoke } from '@/utils';
|
|||||||
* Reference number form.
|
* Reference number form.
|
||||||
*/
|
*/
|
||||||
export default function ReferenceNumberForm({
|
export default function ReferenceNumberForm({
|
||||||
onSubmit,
|
|
||||||
onClose,
|
|
||||||
initialValues,
|
initialValues,
|
||||||
description,
|
description,
|
||||||
|
onSubmit,
|
||||||
|
onClose,
|
||||||
onChange,
|
onChange,
|
||||||
}) {
|
}) {
|
||||||
// Validation schema.
|
// Validation schema.
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export const defaultInvoiceNoSettings = {
|
|||||||
|
|
||||||
export const transformSettingsToForm = (settings) => ({
|
export const transformSettingsToForm = (settings) => ({
|
||||||
...settings,
|
...settings,
|
||||||
incrementMode: settings.autoIncrement === 'true' ? 'auto' : 'manual',
|
incrementMode: settings.autoIncrement ? 'auto' : 'manual',
|
||||||
});
|
});
|
||||||
|
|
||||||
export const transformFormToSettings = (values, group) => {
|
export const transformFormToSettings = (values, group) => {
|
||||||
|
|||||||
@@ -13,6 +13,15 @@ import BillFormHeaderFields from './BillFormHeaderFields';
|
|||||||
* Fill form header.
|
* Fill form header.
|
||||||
*/
|
*/
|
||||||
function BillFormHeader() {
|
function BillFormHeader() {
|
||||||
|
return (
|
||||||
|
<div className={classNames(CLASSES.PAGE_FORM_HEADER)}>
|
||||||
|
<BillFormHeaderFields />
|
||||||
|
<BillFormBigTotal />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function BillFormBigTotal() {
|
||||||
const {
|
const {
|
||||||
values: { currency_code, entries },
|
values: { currency_code, entries },
|
||||||
} = useFormikContext();
|
} = useFormikContext();
|
||||||
@@ -21,14 +30,12 @@ function BillFormHeader() {
|
|||||||
const totalDueAmount = useMemo(() => sumBy(entries, 'amount'), [entries]);
|
const totalDueAmount = useMemo(() => sumBy(entries, 'amount'), [entries]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classNames(CLASSES.PAGE_FORM_HEADER)}>
|
<PageFormBigNumber
|
||||||
<BillFormHeaderFields />
|
label={intl.get('due_amount')}
|
||||||
<PageFormBigNumber
|
amount={totalDueAmount}
|
||||||
label={intl.get('due_amount')}
|
currencyCode={currency_code}
|
||||||
amount={totalDueAmount}
|
/>
|
||||||
currencyCode={currency_code}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default BillFormHeader;
|
export default BillFormHeader;
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ import {
|
|||||||
|
|
||||||
import withSettings from '@/containers/Settings/withSettings';
|
import withSettings from '@/containers/Settings/withSettings';
|
||||||
import withCurrentOrganization from '@/containers/Organization/withCurrentOrganization';
|
import withCurrentOrganization from '@/containers/Organization/withCurrentOrganization';
|
||||||
|
import { CreditNoteSyncIncrementSettingsToForm } from './components';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Credit note form.
|
* Credit note form.
|
||||||
@@ -162,6 +163,7 @@ function CreditNoteForm({
|
|||||||
<CreditNoteFormFooter />
|
<CreditNoteFormFooter />
|
||||||
<CreditNoteFloatingActions />
|
<CreditNoteFloatingActions />
|
||||||
<CreditNoteFormDialogs />
|
<CreditNoteFormDialogs />
|
||||||
|
<CreditNoteSyncIncrementSettingsToForm />
|
||||||
</Form>
|
</Form>
|
||||||
</Formik>
|
</Formik>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -13,6 +13,19 @@ import { PageFormBigNumber } from '@/components';
|
|||||||
* Credit note header.
|
* Credit note header.
|
||||||
*/
|
*/
|
||||||
function CreditNoteFormHeader() {
|
function CreditNoteFormHeader() {
|
||||||
|
return (
|
||||||
|
<div className={classNames(CLASSES.PAGE_FORM_HEADER)}>
|
||||||
|
<CreditNoteFormHeaderFields />
|
||||||
|
<CreditNoteFormBigNumber />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Big total number of credit note form header.
|
||||||
|
* @returns {React.ReactNode}
|
||||||
|
*/
|
||||||
|
function CreditNoteFormBigNumber() {
|
||||||
const {
|
const {
|
||||||
values: { entries, currency_code },
|
values: { entries, currency_code },
|
||||||
} = useFormikContext();
|
} = useFormikContext();
|
||||||
@@ -21,14 +34,11 @@ function CreditNoteFormHeader() {
|
|||||||
const totalAmount = React.useMemo(() => getEntriesTotal(entries), [entries]);
|
const totalAmount = React.useMemo(() => getEntriesTotal(entries), [entries]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classNames(CLASSES.PAGE_FORM_HEADER)}>
|
<PageFormBigNumber
|
||||||
<CreditNoteFormHeaderFields />
|
label={intl.get('credit_note.label_amount_to_credit')}
|
||||||
<PageFormBigNumber
|
amount={totalAmount}
|
||||||
label={intl.get('credit_note.label_amount_to_credit')}
|
currencyCode={currency_code}
|
||||||
amount={totalAmount}
|
/>
|
||||||
currencyCode={currency_code}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import {
|
|||||||
} from '@/components';
|
} from '@/components';
|
||||||
import {
|
import {
|
||||||
customerNameFieldShouldUpdate,
|
customerNameFieldShouldUpdate,
|
||||||
useObserveCreditNoSettings,
|
|
||||||
} from './utils';
|
} from './utils';
|
||||||
|
|
||||||
import { useCreditNoteFormContext } from './CreditNoteFormProvider';
|
import { useCreditNoteFormContext } from './CreditNoteFormProvider';
|
||||||
@@ -45,8 +44,6 @@ function CreditNoteFormHeaderFields({
|
|||||||
|
|
||||||
// #withSettings
|
// #withSettings
|
||||||
creditAutoIncrement,
|
creditAutoIncrement,
|
||||||
creditNumberPrefix,
|
|
||||||
creditNextNumber,
|
|
||||||
}) {
|
}) {
|
||||||
// Credit note form context.
|
// Credit note form context.
|
||||||
const { customers } = useCreditNoteFormContext();
|
const { customers } = useCreditNoteFormContext();
|
||||||
@@ -70,9 +67,6 @@ function CreditNoteFormHeaderFields({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Syncs credit number settings with form.
|
|
||||||
useObserveCreditNoSettings(creditNumberPrefix, creditNextNumber);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
|
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
|
||||||
{/* ----------- Customer name ----------- */}
|
{/* ----------- Customer name ----------- */}
|
||||||
|
|||||||
@@ -1,16 +1,18 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import React from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import { useFormikContext } from 'formik';
|
import { useFormikContext } from 'formik';
|
||||||
|
import * as R from 'ramda';
|
||||||
import { ExchangeRateInputGroup } from '@/components';
|
import { ExchangeRateInputGroup } from '@/components';
|
||||||
import { useCurrentOrganization } from '@/hooks/state';
|
import { useCurrentOrganization } from '@/hooks/state';
|
||||||
import { useCreditNoteIsForeignCustomer } from './utils';
|
import { useCreditNoteIsForeignCustomer } from './utils';
|
||||||
|
import withSettings from '@/containers/Settings/withSettings';
|
||||||
|
import { transactionNumber } from '@/utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* credit exchange rate input field.
|
* credit exchange rate input field.
|
||||||
* @returns {JSX.Element}
|
* @returns {JSX.Element}
|
||||||
*/
|
*/
|
||||||
export function CreditNoteExchangeRateInputField({ ...props }) {
|
export function CreditNoteExchangeRateInputField({ ...props }) {
|
||||||
const currentOrganization = useCurrentOrganization();
|
const currentOrganization = useCurrentOrganization();
|
||||||
const { values } = useFormikContext();
|
const { values } = useFormikContext();
|
||||||
|
|
||||||
@@ -27,4 +29,27 @@ import { useCreditNoteIsForeignCustomer } from './utils';
|
|||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Syncs credit note auto-increment settings to form.
|
||||||
|
* @return {React.ReactNode}
|
||||||
|
*/
|
||||||
|
export const CreditNoteSyncIncrementSettingsToForm = R.compose(
|
||||||
|
withSettings(({ creditNoteSettings }) => ({
|
||||||
|
creditAutoIncrement: creditNoteSettings?.autoIncrement,
|
||||||
|
creditNextNumber: creditNoteSettings?.nextNumber,
|
||||||
|
creditNumberPrefix: creditNoteSettings?.numberPrefix,
|
||||||
|
})),
|
||||||
|
)(({ creditAutoIncrement, creditNextNumber, creditNumberPrefix }) => {
|
||||||
|
const { setFieldValue } = useFormikContext();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!creditAutoIncrement) return;
|
||||||
|
|
||||||
|
const creditNo = transactionNumber(creditNumberPrefix, creditNextNumber);
|
||||||
|
setFieldValue('credit_note_number', creditNo);
|
||||||
|
}, [setFieldValue, creditNumberPrefix, creditNextNumber]);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|||||||
@@ -130,18 +130,6 @@ export const entriesFieldShouldUpdate = (newProps, oldProps) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Syncs invoice no. settings with form.
|
|
||||||
*/
|
|
||||||
export const useObserveCreditNoSettings = (prefix, nextNumber) => {
|
|
||||||
const { setFieldValue } = useFormikContext();
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
const creditNo = transactionNumber(prefix, nextNumber);
|
|
||||||
setFieldValue('credit_note_number', creditNo);
|
|
||||||
}, [setFieldValue, prefix, nextNumber]);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const useSetPrimaryBranchToForm = () => {
|
export const useSetPrimaryBranchToForm = () => {
|
||||||
const { setFieldValue } = useFormikContext();
|
const { setFieldValue } = useFormikContext();
|
||||||
const { branches, isBranchesSuccess } = useCreditNoteFormContext();
|
const { branches, isBranchesSuccess } = useCreditNoteFormContext();
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import {
|
|||||||
transfromsFormValuesToRequest,
|
transfromsFormValuesToRequest,
|
||||||
handleErrors,
|
handleErrors,
|
||||||
} from './utils';
|
} from './utils';
|
||||||
|
import { EstimateIncrementSyncSettingsToForm } from './components';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Estimate form.
|
* Estimate form.
|
||||||
@@ -160,8 +161,8 @@ function EstimateForm({
|
|||||||
<EstimateItemsEntriesField />
|
<EstimateItemsEntriesField />
|
||||||
<EstimateFormFooter />
|
<EstimateFormFooter />
|
||||||
<EstimateFloatingActions />
|
<EstimateFloatingActions />
|
||||||
|
|
||||||
<EstimateFormDialogs />
|
<EstimateFormDialogs />
|
||||||
|
<EstimateIncrementSyncSettingsToForm />
|
||||||
</Form>
|
</Form>
|
||||||
</Formik>
|
</Formik>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -12,6 +12,19 @@ import { PageFormBigNumber } from '@/components';
|
|||||||
|
|
||||||
// Estimate form top header.
|
// Estimate form top header.
|
||||||
function EstimateFormHeader() {
|
function EstimateFormHeader() {
|
||||||
|
return (
|
||||||
|
<div className={classNames(CLASSES.PAGE_FORM_HEADER)}>
|
||||||
|
<EstimateFormHeaderFields />
|
||||||
|
<EstimateFormBigTotal />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Big total of estimate form header.
|
||||||
|
* @returns {React.ReactNode}
|
||||||
|
*/
|
||||||
|
function EstimateFormBigTotal() {
|
||||||
const {
|
const {
|
||||||
values: { entries, currency_code },
|
values: { entries, currency_code },
|
||||||
} = useFormikContext();
|
} = useFormikContext();
|
||||||
@@ -20,15 +33,11 @@ function EstimateFormHeader() {
|
|||||||
const totalDueAmount = useMemo(() => getEntriesTotal(entries), [entries]);
|
const totalDueAmount = useMemo(() => getEntriesTotal(entries), [entries]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classNames(CLASSES.PAGE_FORM_HEADER)}>
|
<PageFormBigNumber
|
||||||
<EstimateFormHeaderFields />
|
label={intl.get('amount')}
|
||||||
|
amount={totalDueAmount}
|
||||||
<PageFormBigNumber
|
currencyCode={currency_code}
|
||||||
label={intl.get('amount')}
|
/>
|
||||||
amount={totalDueAmount}
|
|
||||||
currencyCode={currency_code}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ import {
|
|||||||
EstimateProjectSelectButton,
|
EstimateProjectSelectButton,
|
||||||
} from './components';
|
} from './components';
|
||||||
|
|
||||||
import { useObserveEstimateNoSettings } from './utils';
|
|
||||||
import { useEstimateFormContext } from './EstimateFormProvider';
|
import { useEstimateFormContext } from './EstimateFormProvider';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -71,8 +70,7 @@ function EstimateFormHeader({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// Syncs estimate number settings with the form.
|
|
||||||
useObserveEstimateNoSettings(estimateNumberPrefix, estimateNextNumber);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
|
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
|
||||||
|
|||||||
@@ -1,18 +1,20 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import React from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
import { Button } from '@blueprintjs/core';
|
import { Button } from '@blueprintjs/core';
|
||||||
|
import * as R from 'ramda';
|
||||||
import { useFormikContext } from 'formik';
|
import { useFormikContext } from 'formik';
|
||||||
import { ExchangeRateInputGroup } from '@/components';
|
import { ExchangeRateInputGroup } from '@/components';
|
||||||
import { useCurrentOrganization } from '@/hooks/state';
|
import { useCurrentOrganization } from '@/hooks/state';
|
||||||
import { useEstimateIsForeignCustomer } from './utils';
|
import { useEstimateIsForeignCustomer } from './utils';
|
||||||
|
import withSettings from '@/containers/Settings/withSettings';
|
||||||
|
import { transactionNumber } from '@/utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Estimate exchange rate input field.
|
* Estimate exchange rate input field.
|
||||||
* @returns {JSX.Element}
|
* @returns {JSX.Element}
|
||||||
*/
|
*/
|
||||||
export function EstimateExchangeRateInputField({ ...props }) {
|
export function EstimateExchangeRateInputField({ ...props }) {
|
||||||
const currentOrganization = useCurrentOrganization();
|
const currentOrganization = useCurrentOrganization();
|
||||||
const { values } = useFormikContext();
|
const { values } = useFormikContext();
|
||||||
|
|
||||||
@@ -35,6 +37,32 @@ import { useEstimateIsForeignCustomer } from './utils';
|
|||||||
* Estimate project select.
|
* Estimate project select.
|
||||||
* @returns {JSX.Element}
|
* @returns {JSX.Element}
|
||||||
*/
|
*/
|
||||||
export function EstimateProjectSelectButton({ label }) {
|
export function EstimateProjectSelectButton({ label }) {
|
||||||
return <Button text={label ?? intl.get('select_project')} />;
|
return <Button text={label ?? intl.get('select_project')} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Syncs the estimate auto-increment settings to estimate form.
|
||||||
|
* @returns {React.ReactNode}
|
||||||
|
*/
|
||||||
|
export const EstimateIncrementSyncSettingsToForm = R.compose(
|
||||||
|
withSettings(({ estimatesSettings }) => ({
|
||||||
|
estimateNextNumber: estimatesSettings?.nextNumber,
|
||||||
|
estimateNumberPrefix: estimatesSettings?.numberPrefix,
|
||||||
|
estimateAutoIncrement: estimatesSettings?.autoIncrement,
|
||||||
|
})),
|
||||||
|
)(({ estimateNextNumber, estimateNumberPrefix, estimateAutoIncrement }) => {
|
||||||
|
const { setFieldValue } = useFormikContext();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!estimateAutoIncrement) return null;
|
||||||
|
|
||||||
|
const estimateNo = transactionNumber(
|
||||||
|
estimateNumberPrefix,
|
||||||
|
estimateNextNumber,
|
||||||
|
);
|
||||||
|
setFieldValue('estimate_number', estimateNo);
|
||||||
|
}, [setFieldValue, estimateNumberPrefix, estimateNextNumber]);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|||||||
@@ -74,18 +74,6 @@ export const transformToEditForm = (estimate) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Syncs estimate number of the settings with the context form.
|
|
||||||
*/
|
|
||||||
export const useObserveEstimateNoSettings = (prefix, nextNumber) => {
|
|
||||||
const { setFieldValue } = useFormikContext();
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
const estimateNo = transactionNumber(prefix, nextNumber);
|
|
||||||
setFieldValue('estimate_number', estimateNo);
|
|
||||||
}, [setFieldValue, prefix, nextNumber]);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detarmines customers fast field when update.
|
* Detarmines customers fast field when update.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import {
|
|||||||
transformErrors,
|
transformErrors,
|
||||||
transformValueToRequest,
|
transformValueToRequest,
|
||||||
} from './utils';
|
} from './utils';
|
||||||
|
import { InvoiceNoSyncSettingsToForm } from './components';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoice form.
|
* Invoice form.
|
||||||
@@ -64,23 +65,19 @@ function InvoiceForm({
|
|||||||
invoiceNextNumber,
|
invoiceNextNumber,
|
||||||
);
|
);
|
||||||
// Form initial values.
|
// Form initial values.
|
||||||
const initialValues = useMemo(
|
const initialValues = {
|
||||||
() => ({
|
...(!isEmpty(invoice)
|
||||||
...(!isEmpty(invoice)
|
? { ...transformToEditForm(invoice) }
|
||||||
? { ...transformToEditForm(invoice) }
|
: {
|
||||||
: {
|
...defaultInvoice,
|
||||||
...defaultInvoice,
|
...(invoiceIncrementMode && {
|
||||||
...(invoiceIncrementMode && {
|
|
||||||
invoice_no: invoiceNumber,
|
invoice_no: invoiceNumber,
|
||||||
}),
|
}),
|
||||||
entries: orderingLinesIndexes(defaultInvoice.entries),
|
entries: orderingLinesIndexes(defaultInvoice.entries),
|
||||||
currency_code: base_currency,
|
currency_code: base_currency,
|
||||||
...newInvoice,
|
...newInvoice,
|
||||||
}),
|
}),
|
||||||
}),
|
};
|
||||||
[invoice, newInvoice, invoiceNumber, invoiceIncrementMode, base_currency],
|
|
||||||
);
|
|
||||||
|
|
||||||
// Handles form submit.
|
// Handles form submit.
|
||||||
const handleSubmit = (values, { setSubmitting, setErrors, resetForm }) => {
|
const handleSubmit = (values, { setSubmitting, setErrors, resetForm }) => {
|
||||||
setSubmitting(true);
|
setSubmitting(true);
|
||||||
@@ -105,7 +102,6 @@ function InvoiceForm({
|
|||||||
delivered: submitPayload.deliver,
|
delivered: submitPayload.deliver,
|
||||||
from_estimate_id: estimateId,
|
from_estimate_id: estimateId,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle the request success.
|
// Handle the request success.
|
||||||
const onSuccess = () => {
|
const onSuccess = () => {
|
||||||
AppToaster.show({
|
AppToaster.show({
|
||||||
@@ -173,6 +169,7 @@ function InvoiceForm({
|
|||||||
<InvoiceFormFooter />
|
<InvoiceFormFooter />
|
||||||
<InvoiceFloatingActions />
|
<InvoiceFloatingActions />
|
||||||
<InvoiceFormDialogs />
|
<InvoiceFormDialogs />
|
||||||
|
<InvoiceNoSyncSettingsToForm />
|
||||||
</Form>
|
</Form>
|
||||||
</Formik>
|
</Formik>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import InvoiceNumberDialog from '@/containers/Dialogs/InvoiceNumberDialog';
|
import InvoiceNumberDialog from '@/containers/Dialogs/InvoiceNumberDialog';
|
||||||
import { useFormikContext } from 'formik';
|
import { useFormikContext } from 'formik';
|
||||||
|
import { DialogsName } from '@/constants/dialogs';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoice form dialogs.
|
* Invoice form dialogs.
|
||||||
@@ -16,11 +17,9 @@ export default function InvoiceFormDialogs() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<InvoiceNumberDialog
|
||||||
<InvoiceNumberDialog
|
dialogName={DialogsName.InvoiceNumberSettings}
|
||||||
dialogName={'invoice-number-form'}
|
onConfirm={handleInvoiceNumberFormConfirm}
|
||||||
onConfirm={handleInvoiceNumberFormConfirm}
|
/>
|
||||||
/>
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import { momentFormatter, compose, tansformDateValue } from '@/utils';
|
|||||||
import { CLASSES } from '@/constants/classes';
|
import { CLASSES } from '@/constants/classes';
|
||||||
import { inputIntent, handleDateChange } from '@/utils';
|
import { inputIntent, handleDateChange } from '@/utils';
|
||||||
import {
|
import {
|
||||||
useObserveInvoiceNoSettings,
|
|
||||||
customerNameFieldShouldUpdate,
|
customerNameFieldShouldUpdate,
|
||||||
} from './utils';
|
} from './utils';
|
||||||
|
|
||||||
@@ -42,6 +41,7 @@ import {
|
|||||||
ProjectBillableEntriesLink,
|
ProjectBillableEntriesLink,
|
||||||
} from '@/containers/Projects/components';
|
} from '@/containers/Projects/components';
|
||||||
import { Features } from '@/constants';
|
import { Features } from '@/constants';
|
||||||
|
import { DialogsName } from '@/constants/dialogs';
|
||||||
|
|
||||||
import withSettings from '@/containers/Settings/withSettings';
|
import withSettings from '@/containers/Settings/withSettings';
|
||||||
import withDialogActions from '@/containers/Dialog/withDialogActions';
|
import withDialogActions from '@/containers/Dialog/withDialogActions';
|
||||||
@@ -55,8 +55,6 @@ function InvoiceFormHeaderFields({
|
|||||||
|
|
||||||
// #withSettings
|
// #withSettings
|
||||||
invoiceAutoIncrement,
|
invoiceAutoIncrement,
|
||||||
invoiceNumberPrefix,
|
|
||||||
invoiceNextNumber,
|
|
||||||
}) {
|
}) {
|
||||||
// Invoice form context.
|
// Invoice form context.
|
||||||
const { customers, projects } = useInvoiceFormContext();
|
const { customers, projects } = useInvoiceFormContext();
|
||||||
@@ -66,14 +64,14 @@ function InvoiceFormHeaderFields({
|
|||||||
|
|
||||||
// Handle invoice number changing.
|
// Handle invoice number changing.
|
||||||
const handleInvoiceNumberChange = () => {
|
const handleInvoiceNumberChange = () => {
|
||||||
openDialog('invoice-number-form');
|
openDialog(DialogsName.InvoiceNumberSettings);
|
||||||
};
|
};
|
||||||
// Handle invoice no. field blur.
|
// Handle invoice no. field blur.
|
||||||
const handleInvoiceNoBlur = (form, field) => (event) => {
|
const handleInvoiceNoBlur = (form, field) => (event) => {
|
||||||
const newValue = event.target.value;
|
const newValue = event.target.value;
|
||||||
|
|
||||||
if (field.value !== newValue && invoiceAutoIncrement) {
|
if (field.value !== newValue && invoiceAutoIncrement) {
|
||||||
openDialog('invoice-number-form', {
|
openDialog(DialogsName.InvoiceNumberSettings, {
|
||||||
initialFormValues: {
|
initialFormValues: {
|
||||||
manualTransactionNo: newValue,
|
manualTransactionNo: newValue,
|
||||||
incrementMode: 'manual-transaction',
|
incrementMode: 'manual-transaction',
|
||||||
@@ -81,8 +79,6 @@ function InvoiceFormHeaderFields({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// Syncs invoice number settings with form.
|
|
||||||
useObserveInvoiceNoSettings(invoiceNumberPrefix, invoiceNextNumber);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
|
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
|
||||||
@@ -268,8 +264,6 @@ export default compose(
|
|||||||
withDialogActions,
|
withDialogActions,
|
||||||
withSettings(({ invoiceSettings }) => ({
|
withSettings(({ invoiceSettings }) => ({
|
||||||
invoiceAutoIncrement: invoiceSettings?.autoIncrement,
|
invoiceAutoIncrement: invoiceSettings?.autoIncrement,
|
||||||
invoiceNextNumber: invoiceSettings?.nextNumber,
|
|
||||||
invoiceNumberPrefix: invoiceSettings?.numberPrefix,
|
|
||||||
})),
|
})),
|
||||||
)(InvoiceFormHeaderFields);
|
)(InvoiceFormHeaderFields);
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
// @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 * 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 } from '@/components';
|
||||||
import { useCurrentOrganization } from '@/hooks/state';
|
import { useCurrentOrganization } from '@/hooks/state';
|
||||||
import { useInvoiceIsForeignCustomer } from './utils';
|
import { useInvoiceIsForeignCustomer } from './utils';
|
||||||
|
import withSettings from '@/containers/Settings/withSettings';
|
||||||
|
import { useUpdateEffect } from '@/hooks';
|
||||||
|
import { transactionNumber } from '@/utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoice exchange rate input field.
|
* Invoice exchange rate input field.
|
||||||
@@ -37,3 +41,26 @@ export function InvoiceExchangeRateInputField({ ...props }) {
|
|||||||
export function InvoiceProjectSelectButton({ label }) {
|
export function InvoiceProjectSelectButton({ label }) {
|
||||||
return <Button text={label ?? intl.get('select_project')} />;
|
return <Button text={label ?? intl.get('select_project')} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Syncs invoice auto-increment settings to invoice form once update.
|
||||||
|
*/
|
||||||
|
export const InvoiceNoSyncSettingsToForm = R.compose(
|
||||||
|
withSettings(({ invoiceSettings }) => ({
|
||||||
|
invoiceAutoIncrement: invoiceSettings?.autoIncrement,
|
||||||
|
invoiceNextNumber: invoiceSettings?.nextNumber,
|
||||||
|
invoiceNumberPrefix: invoiceSettings?.numberPrefix,
|
||||||
|
})),
|
||||||
|
)(({ invoiceAutoIncrement, invoiceNextNumber, invoiceNumberPrefix }) => {
|
||||||
|
const { setFieldValue } = useFormikContext();
|
||||||
|
|
||||||
|
useUpdateEffect(() => {
|
||||||
|
// Do not update if the invoice auto-increment is disabled.
|
||||||
|
if (!invoiceAutoIncrement) return null;
|
||||||
|
|
||||||
|
const invoiceNo = transactionNumber(invoiceNumberPrefix, invoiceNextNumber);
|
||||||
|
setFieldValue('invoice_no', invoiceNo);
|
||||||
|
}, [setFieldValue, invoiceNumberPrefix, invoiceNextNumber]);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|||||||
@@ -108,18 +108,6 @@ export const transformErrors = (errors, { setErrors }) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Syncs invoice no. settings with form.
|
|
||||||
*/
|
|
||||||
export const useObserveInvoiceNoSettings = (prefix, nextNumber) => {
|
|
||||||
const { setFieldValue } = useFormikContext();
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
const invoiceNo = transactionNumber(prefix, nextNumber);
|
|
||||||
setFieldValue('invoice_no', invoiceNo);
|
|
||||||
}, [setFieldValue, prefix, nextNumber]);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detarmines customer name field when should update.
|
* Detarmines customer name field when should update.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import {
|
|||||||
transformFormToRequest,
|
transformFormToRequest,
|
||||||
transformErrors,
|
transformErrors,
|
||||||
} from './utils';
|
} from './utils';
|
||||||
|
import { PaymentReceiveSyncIncrementSettingsToForm } from './components';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Payment Receive form.
|
* Payment Receive form.
|
||||||
@@ -176,6 +177,8 @@ function PaymentReceiveForm({
|
|||||||
<PaymentReceiveFormFooter />
|
<PaymentReceiveFormFooter />
|
||||||
<PaymentReceiveFloatingActions />
|
<PaymentReceiveFloatingActions />
|
||||||
|
|
||||||
|
<PaymentReceiveSyncIncrementSettingsToForm />
|
||||||
|
|
||||||
{/* ------- Alerts & Dialogs ------- */}
|
{/* ------- Alerts & Dialogs ------- */}
|
||||||
<PaymentReceiveFormAlerts />
|
<PaymentReceiveFormAlerts />
|
||||||
<PaymentReceiveFormDialogs />
|
<PaymentReceiveFormDialogs />
|
||||||
|
|||||||
@@ -13,6 +13,21 @@ import PaymentReceiveHeaderFields from './PaymentReceiveHeaderFields';
|
|||||||
* Payment receive form header.
|
* Payment receive form header.
|
||||||
*/
|
*/
|
||||||
function PaymentReceiveFormHeader() {
|
function PaymentReceiveFormHeader() {
|
||||||
|
return (
|
||||||
|
<div className={classNames(CLASSES.PAGE_FORM_HEADER)}>
|
||||||
|
<div className={classNames(CLASSES.PAGE_FORM_HEADER_PRIMARY)}>
|
||||||
|
<PaymentReceiveHeaderFields />
|
||||||
|
<PaymentReceiveFormBigTotal />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Big total amount of payment receive form.
|
||||||
|
* @returns {React.ReactNode}
|
||||||
|
*/
|
||||||
|
function PaymentReceiveFormBigTotal() {
|
||||||
// Formik form context.
|
// Formik form context.
|
||||||
const {
|
const {
|
||||||
values: { currency_code, entries },
|
values: { currency_code, entries },
|
||||||
@@ -25,20 +40,14 @@ function PaymentReceiveFormHeader() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classNames(CLASSES.PAGE_FORM_HEADER)}>
|
<div className={classNames(CLASSES.PAGE_FORM_HEADER_BIG_NUMBERS)}>
|
||||||
<div className={classNames(CLASSES.PAGE_FORM_HEADER_PRIMARY)}>
|
<div class="big-amount">
|
||||||
<PaymentReceiveHeaderFields />
|
<span class="big-amount__label">
|
||||||
|
<T id={'amount_received'} />
|
||||||
<div className={classNames(CLASSES.PAGE_FORM_HEADER_BIG_NUMBERS)}>
|
</span>
|
||||||
<div class="big-amount">
|
<h1 class="big-amount__number">
|
||||||
<span class="big-amount__label">
|
<Money amount={paymentFullAmount} currency={currency_code} />
|
||||||
<T id={'amount_received'} />
|
</h1>
|
||||||
</span>
|
|
||||||
<h1 class="big-amount__number">
|
|
||||||
<Money amount={paymentFullAmount} currency={currency_code} />
|
|
||||||
</h1>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -51,7 +51,6 @@ import withSettings from '@/containers/Settings/withSettings';
|
|||||||
import withCurrentOrganization from '@/containers/Organization/withCurrentOrganization';
|
import withCurrentOrganization from '@/containers/Organization/withCurrentOrganization';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
useObservePaymentNoSettings,
|
|
||||||
amountPaymentEntries,
|
amountPaymentEntries,
|
||||||
fullAmountPaymentEntries,
|
fullAmountPaymentEntries,
|
||||||
customersFieldShouldUpdate,
|
customersFieldShouldUpdate,
|
||||||
@@ -71,8 +70,6 @@ function PaymentReceiveHeaderFields({
|
|||||||
|
|
||||||
// #withSettings
|
// #withSettings
|
||||||
paymentReceiveAutoIncrement,
|
paymentReceiveAutoIncrement,
|
||||||
paymentReceiveNumberPrefix,
|
|
||||||
paymentReceiveNextNumber,
|
|
||||||
}) {
|
}) {
|
||||||
// Payment receive form context.
|
// Payment receive form context.
|
||||||
const { customers, accounts, projects, isNewMode } =
|
const { customers, accounts, projects, isNewMode } =
|
||||||
@@ -123,12 +120,6 @@ function PaymentReceiveHeaderFields({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Syncs payment receive number from settings to the form.
|
|
||||||
useObservePaymentNoSettings(
|
|
||||||
paymentReceiveNumberPrefix,
|
|
||||||
paymentReceiveNextNumber,
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
|
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
|
||||||
{/* ------------- Customer name ------------- */}
|
{/* ------------- Customer name ------------- */}
|
||||||
@@ -351,8 +342,6 @@ function PaymentReceiveHeaderFields({
|
|||||||
|
|
||||||
export default compose(
|
export default compose(
|
||||||
withSettings(({ paymentReceiveSettings }) => ({
|
withSettings(({ paymentReceiveSettings }) => ({
|
||||||
paymentReceiveNextNumber: paymentReceiveSettings?.nextNumber,
|
|
||||||
paymentReceiveNumberPrefix: paymentReceiveSettings?.numberPrefix,
|
|
||||||
paymentReceiveAutoIncrement: paymentReceiveSettings?.autoIncrement,
|
paymentReceiveAutoIncrement: paymentReceiveSettings?.autoIncrement,
|
||||||
})),
|
})),
|
||||||
withDialogActions,
|
withDialogActions,
|
||||||
|
|||||||
@@ -1,14 +1,17 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import React from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
import { Button } from '@blueprintjs/core';
|
import { Button } from '@blueprintjs/core';
|
||||||
import { useFormikContext } from 'formik';
|
import { useFormikContext } from 'formik';
|
||||||
|
import * as R from 'ramda';
|
||||||
|
|
||||||
import { Money, ExchangeRateInputGroup, MoneyFieldCell } from '@/components';
|
import { Money, ExchangeRateInputGroup, MoneyFieldCell } from '@/components';
|
||||||
|
|
||||||
import { useCurrentOrganization } from '@/hooks/state';
|
import { useCurrentOrganization } from '@/hooks/state';
|
||||||
import { useEstimateIsForeignCustomer } from './utils';
|
import { useEstimateIsForeignCustomer } from './utils';
|
||||||
|
import { transactionNumber } from '@/utils';
|
||||||
|
import withSettings from '@/containers/Settings/withSettings';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoice date cell.
|
* Invoice date cell.
|
||||||
@@ -109,6 +112,42 @@ export function PaymentReceiveExchangeRateInputField({ ...props }) {
|
|||||||
* payment receive project select.
|
* payment receive project select.
|
||||||
* @returns {JSX.Element}
|
* @returns {JSX.Element}
|
||||||
*/
|
*/
|
||||||
export function PaymentReceiveProjectSelectButton({ label }) {
|
export function PaymentReceiveProjectSelectButton({ label }) {
|
||||||
return <Button text={label ?? intl.get('select_project')} />;
|
return <Button text={label ?? intl.get('select_project')} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Syncs the auto-increment settings to payment receive form.
|
||||||
|
* @returns {React.ReactNode}
|
||||||
|
*/
|
||||||
|
export const PaymentReceiveSyncIncrementSettingsToForm = R.compose(
|
||||||
|
withSettings(({ paymentReceiveSettings }) => ({
|
||||||
|
paymentReceiveNextNumber: paymentReceiveSettings?.nextNumber,
|
||||||
|
paymentReceiveNumberPrefix: paymentReceiveSettings?.numberPrefix,
|
||||||
|
paymentReceiveAutoIncrement: paymentReceiveSettings?.autoIncrement,
|
||||||
|
})),
|
||||||
|
)(
|
||||||
|
({
|
||||||
|
paymentReceiveNextNumber,
|
||||||
|
paymentReceiveNumberPrefix,
|
||||||
|
paymentReceiveAutoIncrement,
|
||||||
|
}) => {
|
||||||
|
const { setFieldValue } = useFormikContext();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!paymentReceiveAutoIncrement) return;
|
||||||
|
|
||||||
|
const paymentReceiveNo = transactionNumber(
|
||||||
|
paymentReceiveNumberPrefix,
|
||||||
|
paymentReceiveNextNumber,
|
||||||
|
);
|
||||||
|
setFieldValue('payment_receive_no', paymentReceiveNo);
|
||||||
|
}, [
|
||||||
|
setFieldValue,
|
||||||
|
paymentReceiveNumberPrefix,
|
||||||
|
paymentReceiveNextNumber,
|
||||||
|
paymentReceiveAutoIncrement,
|
||||||
|
]);
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import {
|
|||||||
handleErrors,
|
handleErrors,
|
||||||
transformFormValuesToRequest,
|
transformFormValuesToRequest,
|
||||||
} from './utils';
|
} from './utils';
|
||||||
|
import { ReceiptSyncIncrementSettingsToForm } from './components';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Receipt form.
|
* Receipt form.
|
||||||
@@ -164,8 +165,8 @@ function ReceiptForm({
|
|||||||
<ReceiptItemsEntriesEditor />
|
<ReceiptItemsEntriesEditor />
|
||||||
<ReceiptFormFooter />
|
<ReceiptFormFooter />
|
||||||
<ReceiptFormFloatingActions />
|
<ReceiptFormFloatingActions />
|
||||||
|
|
||||||
<ReceiptFormDialogs />
|
<ReceiptFormDialogs />
|
||||||
|
<ReceiptSyncIncrementSettingsToForm />
|
||||||
</Form>
|
</Form>
|
||||||
</Formik>
|
</Formik>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -17,6 +17,21 @@ function ReceiptFormHeader({
|
|||||||
// #ownProps
|
// #ownProps
|
||||||
onReceiptNumberChanged,
|
onReceiptNumberChanged,
|
||||||
}) {
|
}) {
|
||||||
|
return (
|
||||||
|
<div className={classNames(CLASSES.PAGE_FORM_HEADER)}>
|
||||||
|
<ReceiptFormHeaderFields
|
||||||
|
onReceiptNumberChanged={onReceiptNumberChanged}
|
||||||
|
/>
|
||||||
|
<ReceiptFormHeaderBigTotal />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The big total amount of receipt form.
|
||||||
|
* @returns {React.ReactNode}
|
||||||
|
*/
|
||||||
|
function ReceiptFormHeaderBigTotal() {
|
||||||
const {
|
const {
|
||||||
values: { currency_code, entries },
|
values: { currency_code, entries },
|
||||||
} = useFormikContext();
|
} = useFormikContext();
|
||||||
@@ -25,16 +40,11 @@ function ReceiptFormHeader({
|
|||||||
const totalDueAmount = useMemo(() => getEntriesTotal(entries), [entries]);
|
const totalDueAmount = useMemo(() => getEntriesTotal(entries), [entries]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classNames(CLASSES.PAGE_FORM_HEADER)}>
|
<PageFormBigNumber
|
||||||
<ReceiptFormHeaderFields
|
label={intl.get('due_amount')}
|
||||||
onReceiptNumberChanged={onReceiptNumberChanged}
|
amount={totalDueAmount}
|
||||||
/>
|
currencyCode={currency_code}
|
||||||
<PageFormBigNumber
|
/>
|
||||||
label={intl.get('due_amount')}
|
|
||||||
amount={totalDueAmount}
|
|
||||||
currencyCode={currency_code}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ import { useReceiptFormContext } from './ReceiptFormProvider';
|
|||||||
import {
|
import {
|
||||||
accountsFieldShouldUpdate,
|
accountsFieldShouldUpdate,
|
||||||
customersFieldShouldUpdate,
|
customersFieldShouldUpdate,
|
||||||
useObserveReceiptNoSettings,
|
|
||||||
} from './utils';
|
} from './utils';
|
||||||
import {
|
import {
|
||||||
ReceiptExchangeRateInputField,
|
ReceiptExchangeRateInputField,
|
||||||
@@ -56,8 +55,6 @@ function ReceiptFormHeader({
|
|||||||
|
|
||||||
// #withSettings
|
// #withSettings
|
||||||
receiptAutoIncrement,
|
receiptAutoIncrement,
|
||||||
receiptNextNumber,
|
|
||||||
receiptNumberPrefix,
|
|
||||||
}) {
|
}) {
|
||||||
const { accounts, customers, projects } = useReceiptFormContext();
|
const { accounts, customers, projects } = useReceiptFormContext();
|
||||||
|
|
||||||
@@ -78,9 +75,6 @@ function ReceiptFormHeader({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Synsc receipt number settings with the form.
|
|
||||||
useObserveReceiptNoSettings(receiptNumberPrefix, receiptNextNumber);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
|
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
|
||||||
{/* ----------- Customer name ----------- */}
|
{/* ----------- Customer name ----------- */}
|
||||||
@@ -255,8 +249,6 @@ export default compose(
|
|||||||
withDialogActions,
|
withDialogActions,
|
||||||
withSettings(({ receiptSettings }) => ({
|
withSettings(({ receiptSettings }) => ({
|
||||||
receiptAutoIncrement: receiptSettings?.autoIncrement,
|
receiptAutoIncrement: receiptSettings?.autoIncrement,
|
||||||
receiptNextNumber: receiptSettings?.nextNumber,
|
|
||||||
receiptNumberPrefix: receiptSettings?.numberPrefix,
|
|
||||||
})),
|
})),
|
||||||
)(ReceiptFormHeader);
|
)(ReceiptFormHeader);
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,14 @@ import React from 'react';
|
|||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
import { Button } from '@blueprintjs/core';
|
import { Button } from '@blueprintjs/core';
|
||||||
import { useFormikContext } from 'formik';
|
import { useFormikContext } from 'formik';
|
||||||
|
import * as R from 'ramda';
|
||||||
|
|
||||||
import { ExchangeRateInputGroup } from '@/components';
|
import { ExchangeRateInputGroup } from '@/components';
|
||||||
import { useCurrentOrganization } from '@/hooks/state';
|
import { useCurrentOrganization } from '@/hooks/state';
|
||||||
import { useReceiptIsForeignCustomer } from './utils';
|
import { useReceiptIsForeignCustomer } from './utils';
|
||||||
|
import { useUpdateEffect } from '@/hooks';
|
||||||
|
import withSettings from '@/containers/Settings/withSettings';
|
||||||
|
import { transactionNumber } from '@/utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Receipt exchange rate input field.
|
* Receipt exchange rate input field.
|
||||||
@@ -37,3 +42,31 @@ export function ReceiptExchangeRateInputField({ ...props }) {
|
|||||||
export function ReceiptProjectSelectButton({ label }) {
|
export function ReceiptProjectSelectButton({ label }) {
|
||||||
return <Button text={label ?? intl.get('select_project')} />;
|
return <Button text={label ?? intl.get('select_project')} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Syncs receipt auto-increment settings to form.
|
||||||
|
* @return {React.ReactNode}
|
||||||
|
*/
|
||||||
|
export const ReceiptSyncIncrementSettingsToForm = R.compose(
|
||||||
|
withSettings(({ receiptSettings }) => ({
|
||||||
|
receiptAutoIncrement: receiptSettings?.autoIncrement,
|
||||||
|
receiptNextNumber: receiptSettings?.nextNumber,
|
||||||
|
receiptNumberPrefix: receiptSettings?.numberPrefix,
|
||||||
|
})),
|
||||||
|
)(({ receiptAutoIncrement, receiptNextNumber, receiptNumberPrefix }) => {
|
||||||
|
const { setFieldValue } = useFormikContext();
|
||||||
|
|
||||||
|
useUpdateEffect(() => {
|
||||||
|
if (!receiptAutoIncrement) return;
|
||||||
|
|
||||||
|
const receiptNo = transactionNumber(receiptNumberPrefix, receiptNextNumber);
|
||||||
|
setFieldValue('receipt_number', receiptNo);
|
||||||
|
}, [
|
||||||
|
setFieldValue,
|
||||||
|
receiptNumberPrefix,
|
||||||
|
receiptAutoIncrement,
|
||||||
|
receiptNextNumber,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|||||||
@@ -77,15 +77,6 @@ export const transformToEditForm = (receipt) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useObserveReceiptNoSettings = (prefix, nextNumber) => {
|
|
||||||
const { setFieldValue } = useFormikContext();
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
const receiptNo = transactionNumber(prefix, nextNumber);
|
|
||||||
setFieldValue('receipt_number', receiptNo);
|
|
||||||
}, [setFieldValue, prefix, nextNumber]);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detarmines entries fast field should update.
|
* Detarmines entries fast field should update.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -21,6 +21,9 @@ const commonInvalidateQueries = (client) => {
|
|||||||
client.invalidateQueries(t.ACCOUNTS);
|
client.invalidateQueries(t.ACCOUNTS);
|
||||||
client.invalidateQueries(t.ACCOUNT);
|
client.invalidateQueries(t.ACCOUNT);
|
||||||
|
|
||||||
|
// Invalidate settings.
|
||||||
|
client.invalidateQueries([t.SETTING, t.SETTING_MANUAL_JOURNALS]);
|
||||||
|
|
||||||
// Invalidate financial reports.
|
// Invalidate financial reports.
|
||||||
client.invalidateQueries(t.FINANCIAL_REPORT);
|
client.invalidateQueries(t.FINANCIAL_REPORT);
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { useRequestQuery } from '../useQueryRequest';
|
|||||||
import useApiRequest from '../useRequest';
|
import useApiRequest from '../useRequest';
|
||||||
import { useSetSettings } from '@/hooks/state';
|
import { useSetSettings } from '@/hooks/state';
|
||||||
import t from './types';
|
import t from './types';
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves the settings.
|
* Saves the settings.
|
||||||
@@ -23,18 +24,23 @@ export function useSaveSettings(props) {
|
|||||||
function useSettingsQuery(key, query, props) {
|
function useSettingsQuery(key, query, props) {
|
||||||
const setSettings = useSetSettings();
|
const setSettings = useSetSettings();
|
||||||
|
|
||||||
return useRequestQuery(
|
const settingsQuery = useRequestQuery(
|
||||||
key,
|
key,
|
||||||
{ method: 'get', url: 'settings', params: query },
|
{ method: 'get', url: 'settings', params: query },
|
||||||
{
|
{
|
||||||
select: (res) => res.data.settings,
|
select: (res) => res.data.settings,
|
||||||
defaultData: [],
|
defaultData: [],
|
||||||
onSuccess: (settings) => {
|
|
||||||
setSettings(settings);
|
|
||||||
},
|
|
||||||
...props,
|
...props,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
useEffect(() => {
|
||||||
|
// Sync to Redux state if the reqeust success and is not fetching.
|
||||||
|
if (!settingsQuery.isFetching && settingsQuery.isSuccess) {
|
||||||
|
setSettings(settingsQuery.data);
|
||||||
|
}
|
||||||
|
}, [settingsQuery.isFetching, settingsQuery.isSuccess, settingsQuery.data]);
|
||||||
|
|
||||||
|
return settingsQuery;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user