feat(design): fix issues in sidebar design.

feat(sales): reference number auto-increment optimizations.
fix(payments): payment receive/made statement.
This commit is contained in:
a.bouhuolia
2021-03-11 14:29:38 +02:00
parent 59f8010122
commit 30cd6c8a61
62 changed files with 921 additions and 378 deletions

View File

@@ -30,7 +30,7 @@ function ItemDeleteAlert({
closeAlert,
// #withItemsActions
addItemsTableQueries,
setItemsTableState,
}) {
const { mutateAsync: deleteItem, isLoading } = useDeleteItem();
const { formatMessage } = useIntl();
@@ -51,7 +51,7 @@ function ItemDeleteAlert({
intent: Intent.SUCCESS,
});
// Reset to page number one.
addItemsTableQueries({ page: 1 });
setItemsTableState({ page: 1 });
})
.catch(
({

View File

@@ -54,7 +54,7 @@ function ContactDuplicateForm({
{({ isSubmitting }) => (
<Form>
<div className={Classes.DIALOG_BODY}>
<p>
<p class="paragraph">
<T id={'are_you_sure_want_to_duplicate'} />
</p>
@@ -66,7 +66,6 @@ function ContactDuplicateForm({
labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
className={'form-group--select-list'}
inline={true}
helperText={<ErrorMessage name="contact_type" />}
>
<ListSelect

View File

@@ -6,41 +6,52 @@ import ReferenceNumberForm from 'containers/JournalNumber/ReferenceNumberForm';
import withDialogActions from 'containers/Dialog/withDialogActions';
import withSettings from 'containers/Settings/withSettings';
import { compose, optionsMapToArray, saveInvoke } from 'utils';
import { compose, saveInvoke } from 'utils';
import {
transformFormToSettings,
transformSettingsToForm,
} from 'containers/JournalNumber/utils';
/**
* Estimate number dialog's content.
*/
function EstimateNumberDialogContent({
// #withSettings
nextNumber,
numberPrefix,
autoIncrement,
// #withDialogActions
closeDialog,
// #ownProps
initialValues,
onConfirm,
}) {
// Fetches the estimates settings.
const { isLoading: isSettingsLoading } = useSettingsEstimates();
// Mutates the settings.
const { mutateAsync: saveSettingsMutate } = useSaveSettings();
// Handle the submit form.
const handleSubmitForm = (values, { setSubmitting }) => {
const options = optionsMapToArray(values).map((option) => ({
key: option.key,
...option,
group: 'sales_estimates',
}));
saveSettingsMutate({ options })
.then(() => {
setSubmitting(false);
closeDialog('estimate-number-form');
saveInvoke(onConfirm, values);
})
.catch(() => {
setSubmitting(false);
});
// Transformes the form values to settings to save it.
const options = transformFormToSettings(values, 'sales_estimates');
const handleSuccess = () => {
setSubmitting(false);
closeDialog('estimate-number-form');
saveInvoke(onConfirm, values);
};
const handleErrors = () => {
setSubmitting(false);
};
if (values.incrementMode === 'manual-transaction') {
handleSuccess();
return;
}
saveSettingsMutate({ options }).then(handleSuccess).catch(handleErrors);
};
const handleClose = useCallback(() => {
@@ -50,8 +61,14 @@ function EstimateNumberDialogContent({
return (
<DialogContent isLoading={isSettingsLoading}>
<ReferenceNumberForm
initialNumber={nextNumber}
initialPrefix={numberPrefix}
initialValues={{
...transformSettingsToForm({
nextNumber,
numberPrefix,
autoIncrement,
}),
...initialValues,
}}
onSubmit={handleSubmitForm}
onClose={handleClose}
/>
@@ -64,5 +81,6 @@ export default compose(
withSettings(({ estimatesSettings }) => ({
nextNumber: estimatesSettings?.nextNumber,
numberPrefix: estimatesSettings?.numberPrefix,
autoIncrement: estimatesSettings?.autoIncrement,
})),
)(EstimateNumberDialogContent);

View File

@@ -8,12 +8,19 @@ const EstimateNumberDialogContent = lazy(() =>
import('./EstimateNumberDialogContent'),
);
/**
* Estimate number dialog.
*/
function EstimateNumberDialog({
dialogName,
paylaod = { id: null },
payload: { initialFormValues },
isOpen,
onConfirm
}) {
const handleConfirm = (values) => {
saveInvoke(onConfirm, values);
};
return (
<Dialog
name={dialogName}
@@ -25,8 +32,8 @@ function EstimateNumberDialog({
>
<DialogSuspense>
<EstimateNumberDialogContent
estimateNumberId={paylaod.id}
onConfirm={(values) => saveInvoke(onConfirm, values)}/>
initialValues={{ ...initialFormValues }}
onConfirm={handleConfirm}/>
</DialogSuspense>
</Dialog>
);

View File

@@ -1,4 +1,4 @@
import React, { useCallback } from 'react';
import React from 'react';
import { useSaveSettings } from 'hooks/query';
import { InvoiceNumberDialogProvider } from './InvoiceNumberDialogProvider';
@@ -7,57 +7,69 @@ import ReferenceNumberForm from 'containers/JournalNumber/ReferenceNumberForm';
import withDialogActions from 'containers/Dialog/withDialogActions';
import withSettings from 'containers/Settings/withSettings';
import withSettingsActions from 'containers/Settings/withSettingsActions';
// import withInvoicesActions from 'containers/Sales/Invoice/withInvoiceActions';
import { compose, optionsMapToArray } from 'utils';
import { compose } from 'utils';
import {
transformFormToSettings,
transformSettingsToForm,
} from 'containers/JournalNumber/utils';
/**
* invoice number dialog's content.
*/
function InvoiceNumberDialogContent({
// #ownProps
initialValues,
onConfirm,
// #withSettings
nextNumber,
numberPrefix,
autoIncrement,
// #withDialogActions
closeDialog,
}) {
const { mutateAsync: saveSettings } = useSaveSettings();
// Handle the submit form.
const handleSubmitForm = (values, { setSubmitting }) => {
const { mode, ...autoModeValues } = values;
// Handle the form success.
const handleSuccess = () => {
setSubmitting(false);
closeDialog('invoice-number-form');
onConfirm(values);
};
// Handle the form errors.
const handleErrors = () => {
setSubmitting(false);
};
if (values.incrementMode === 'manual-transaction') {
handleSuccess();
return;
}
// Transformes the form values to settings to save it.
const options = transformFormToSettings(values, 'sales_invoices');
const options = optionsMapToArray(autoModeValues).map((option) => ({
key: option.key,
...option,
group: 'sales_invoices',
}));
saveSettings({ options })
.then(() => {
setSubmitting(false);
closeDialog('invoice-number-form');
onConfirm(values);
})
.catch(() => {
setSubmitting(false);
});
// Save the goddamn settings.
saveSettings({ options }).then(handleSuccess).catch(handleErrors);
};
// Handle the dialog close.
const handleClose = useCallback(() => {
const handleClose = () => {
closeDialog('invoice-number-form');
}, [closeDialog]);
};
return (
<InvoiceNumberDialogProvider>
<ReferenceNumberForm
initialNumber={nextNumber}
initialPrefix={numberPrefix}
initialValues={{
...transformSettingsToForm({
nextNumber,
numberPrefix,
autoIncrement,
}),
...initialValues,
}}
onSubmit={handleSubmitForm}
onClose={handleClose}
/>
@@ -71,5 +83,6 @@ export default compose(
withSettings(({ invoiceSettings }) => ({
nextNumber: invoiceSettings?.nextNumber,
numberPrefix: invoiceSettings?.numberPrefix,
autoIncrement: invoiceSettings?.autoIncrement,
})),
)(InvoiceNumberDialogContent);

View File

@@ -8,24 +8,32 @@ const InvoiceNumberDialogContent = lazy(() =>
import('./InvoiceNumberDialogContent'),
);
/**
* Invoice number dialog.
*/
function InvoiceNumberDialog({
dialogName,
payload = { id: null },
payload: { initialFormValues },
isOpen,
onConfirm,
}) {
const handleConfirm = (values) => {
saveInvoke(onConfirm, values);
};
return (
<Dialog
title={<T id={'invoice_number_settings'} />}
name={dialogName}
autoFocus={true}
canEscapeKeyClose={true}
isOpen={isOpen}
title={<T id={'invoice_number_settings'} />}
name={dialogName}
autoFocus={true}
canEscapeKeyClose={true}
isOpen={isOpen}
>
<DialogSuspense>
<InvoiceNumberDialogContent
InvoiceNumberId={payload.id}
onConfirm={(values) => saveInvoke(onConfirm, values)} />
initialValues={{ ...initialFormValues }}
onConfirm={handleConfirm}
/>
</DialogSuspense>
</Dialog>
);

View File

@@ -8,43 +8,50 @@ import withDialogActions from 'containers/Dialog/withDialogActions';
import withSettingsActions from 'containers/Settings/withSettingsActions';
import withSettings from 'containers/Settings/withSettings';
import { saveInvoke, compose, optionsMapToArray } from 'utils';
import { saveInvoke, compose } from 'utils';
import {
transformFormToSettings,
transformSettingsToForm,
} from 'containers/JournalNumber/utils';
/**
* payment receive number dialog's content.
* Payment receive number dialog's content.
*/
function PaymentNumberDialogContent({
// #withSettings
nextNumber,
numberPrefix,
autoIncrement,
// #withDialogActions
closeDialog,
// #ownProps
onConfirm,
initialValues
}) {
const { isLoading: isSettingsLoading } = useSettingsPaymentReceives();
const { mutateAsync: saveSettingsMutate } = useSaveSettings();
// Handle submit form.
const handleSubmitForm = (values, { setSubmitting }) => {
const options = optionsMapToArray(values).map((option) => ({
key: option.key,
...option,
group: 'payment_receives',
}));
// Transformes the form values to settings to save it.
const options = transformFormToSettings(values, 'payment_receives');
saveSettingsMutate({ options })
.then(() => {
setSubmitting(false);
closeDialog('payment-receive-number-form');
const handleSuccess = () => {
setSubmitting(false);
closeDialog('payment-receive-number-form');
saveInvoke(onConfirm, values);
})
.catch(() => {
setSubmitting(false);
});
saveInvoke(onConfirm, values);
};
const handleErrors = () => {
setSubmitting(false);
};
if (values.incrementMode === 'manual-transaction') {
handleSuccess();
return;
}
saveSettingsMutate({ options }).then(handleSuccess).catch(handleErrors);
};
const handleClose = useCallback(() => {
@@ -54,8 +61,14 @@ function PaymentNumberDialogContent({
return (
<DialogContent isLoading={isSettingsLoading}>
<ReferenceNumberForm
initialNumber={nextNumber}
initialPrefix={numberPrefix}
initialValues={{
...transformSettingsToForm({
nextNumber,
numberPrefix,
autoIncrement,
}),
...initialValues,
}}
onSubmit={handleSubmitForm}
onClose={handleClose}
/>
@@ -69,5 +82,6 @@ export default compose(
withSettings(({ paymentReceiveSettings }) => ({
nextNumber: paymentReceiveSettings?.nextNumber,
numberPrefix: paymentReceiveSettings?.numberPrefix,
autoIncrement: paymentReceiveSettings?.autoIncrement,
})),
)(PaymentNumberDialogContent);

View File

@@ -4,7 +4,7 @@ import { Dialog, DialogSuspense } from 'components';
import withDialogRedux from 'components/DialogReduxConnect';
import { saveInvoke, compose } from 'utils';
const PaymentReceiveNumbereDialogConetnet = lazy(() =>
const PaymentReceiveNumbereDialogContent = lazy(() =>
import('./PaymentReceiveNumberDialogContent'),
);
@@ -13,7 +13,7 @@ const PaymentReceiveNumbereDialogConetnet = lazy(() =>
*/
function PaymentReceiveNumberDialog({
dialogName,
payload = { id: null },
payload: { initialFormValues },
isOpen,
onConfirm
}) {
@@ -26,8 +26,8 @@ function PaymentReceiveNumberDialog({
isOpen={isOpen}
>
<DialogSuspense>
<PaymentReceiveNumbereDialogConetnet
paymentReceiveNumberId={payload.id}
<PaymentReceiveNumbereDialogContent
initialValues={initialFormValues}
onConfirm={(values) => saveInvoke(onConfirm, values)}
/>
</DialogSuspense>

View File

@@ -7,20 +7,25 @@ import ReferenceNumberForm from 'containers/JournalNumber/ReferenceNumberForm';
import withDialogActions from 'containers/Dialog/withDialogActions';
import withSettings from 'containers/Settings/withSettings';
import { compose, optionsMapToArray, saveInvoke } from 'utils';
import { compose, saveInvoke } from 'utils';
import {
transformFormToSettings,
transformSettingsToForm,
} from 'containers/JournalNumber/utils';
/**
* Receipt number dialog's content.
*/
function ReceiptNumberDialogContent({
// #ownProps
receiptId,
receiptId,
onConfirm,
initialValues,
// #withSettings
nextNumber,
numberPrefix,
autoIncrement,
// #withDialogActions
closeDialog,
@@ -28,22 +33,24 @@ function ReceiptNumberDialogContent({
const { isLoading: isSettingsLoading } = useSettingsReceipts();
const { mutateAsync: saveSettingsMutate } = useSaveSettings();
// Handle the form submit.
const handleSubmitForm = (values, { setSubmitting }) => {
const options = optionsMapToArray(values).map((option) => ({
key: option.key,
...option,
group: 'sales_receipts',
}));
const handleSuccess = () => {
setSubmitting(false);
closeDialog('receipt-number-form');
saveInvoke(onConfirm, values);
};
const handleErrors = () => {
setSubmitting(false);
};
if (values.incrementMode === 'manual-transaction') {
handleSuccess();
return;
}
// Transformes the form values to settings to save it.
const options = transformFormToSettings(values, 'sales_receipts');
saveSettingsMutate({ options })
.then(() => {
setSubmitting(false);
closeDialog('receipt-number-form');
saveInvoke(onConfirm, values)
})
.catch(() => {
setSubmitting(false);
});
saveSettingsMutate({ options }).then(handleSuccess).catch(handleErrors);
};
const handleClose = useCallback(() => {
@@ -53,8 +60,14 @@ function ReceiptNumberDialogContent({
return (
<DialogContent isLoading={isSettingsLoading}>
<ReferenceNumberForm
initialNumber={nextNumber}
initialPrefix={numberPrefix}
initialValues={{
...transformSettingsToForm({
nextNumber,
numberPrefix,
autoIncrement,
}),
...initialValues,
}}
onSubmit={handleSubmitForm}
onClose={handleClose}
/>
@@ -67,5 +80,6 @@ export default compose(
withSettings(({ receiptSettings }) => ({
nextNumber: receiptSettings?.nextNumber,
numberPrefix: receiptSettings?.numberPrefix,
autoIncrement: receiptSettings?.autoIncrement,
})),
)(ReceiptNumberDialogContent);

View File

@@ -13,7 +13,7 @@ const ReceiptNumberDialogContent = lazy(() =>
*/
function ReceiptNumberDialog({
dialogName,
paylaod = { id: null },
payload: { initialFormValues = {} },
isOpen,
onConfirm,
}) {
@@ -31,7 +31,7 @@ function ReceiptNumberDialog({
>
<DialogSuspense>
<ReceiptNumberDialogContent
receiptId={paylaod.id}
initialValues={{ ...initialFormValues }}
onConfirm={handleConfirm}
/>
</DialogSuspense>

View File

@@ -4,8 +4,12 @@ import { Formik, Form } from 'formik';
import { FormattedMessage as T } from 'react-intl';
import { Button, Classes } from '@blueprintjs/core';
import { Intent } from '@blueprintjs/core';
import { saveInvoke } from 'utils';
import 'style/pages/ReferenceNumber/ReferenceNumber.scss';
import ReferenceNumberFormContent from './ReferenceNumberFormContent';
import { transformValuesToForm } from './utils';
import { saveInvoke } from 'utils';
/**
* Reference number form.
@@ -13,42 +17,45 @@ import ReferenceNumberFormContent from './ReferenceNumberFormContent';
export default function ReferenceNumberForm({
onSubmit,
onClose,
initialPrefix,
initialNumber,
initialValues,
}) {
// Validation schema.
const validationSchema = Yup.object().shape({
// mode: Yup.string(),
number_prefix: Yup.string(),
next_number: Yup.number(),
incrementMode: Yup.string(),
numberPrefix: Yup.string(),
nextNumber: Yup.number(),
manualTransactionNo: Yup.string(),
});
const initialValues = useMemo(
// Initial values.
const formInitialValues = useMemo(
() => ({
number_prefix: initialPrefix || '',
next_number: initialNumber || '',
...initialValues,
incrementMode:
initialValues.incrementMode === 'auto' &&
initialValues.manualTransactionNo
? 'manual-transaction'
: initialValues.incrementMode,
}),
[initialPrefix, initialNumber],
[initialValues],
);
const handleSubmit = (values) => {
debugger;
saveInvoke(onSubmit, values);
// Handle the form submit.
const handleSubmit = (values, methods) => {
const parsed = transformValuesToForm(values);
saveInvoke(onSubmit, { ...parsed, ...values }, methods);
};
return (
<Formik
initialValues={initialValues}
initialValues={formInitialValues}
validationSchema={validationSchema}
onSubmit={handleSubmit}
>
{({ isSubmitting }) => (
<Form>
<Form className={'reference-number-form'}>
<div className={Classes.DIALOG_BODY}>
<p className="paragraph">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce
tincidunt porta quam,
Your invoice numbers are set on auto-increment mod. Are you sure changing this setting?
</p>
<ReferenceNumberFormContent />
</div>

View File

@@ -1,71 +1,103 @@
import React from 'react';
import { FastField } from 'formik';
import { FastField, useFormikContext } from 'formik';
import { FormattedMessage as T } from 'react-intl';
import { FormGroup, InputGroup, Radio } from '@blueprintjs/core';
import { Row, Col, ErrorMessage } from 'components';
import { If, Row, Col, ErrorMessage } from 'components';
import { inputIntent } from 'utils';
/**
* Reference number form content.
*/
export default function ReferenceNumberFormContent() {
const { values } = useFormikContext();
return (
<>
<FastField name={'mode'}>
{/* ------------- Auto increment mode ------------- */}
<FastField name={'incrementMode'}>
{({ form, field, meta: { error, touched } }) => (
<Radio
label="Auto-incrementing invoice number."
value="auto-increment"
{...field}
onChange={() => {
form.setFieldValue('incrementMode', 'auto');
}}
checked={field.value === 'auto'}
/>
)}
</FastField>
<Row>
{/* ------------- Prefix ------------- */}
<Col xs={6}>
<FastField name={'prefix'}>
{({ form, field, meta: { error, touched } }) => (
<FormGroup
label={<T id={'prefix'} />}
className={'form-group--'}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name={'prefix'} />}
>
<InputGroup
<If condition={values.incrementMode === 'auto'}>
<Row>
{/* ------------- Prefix ------------- */}
<Col xs={4}>
<FastField name={'numberPrefix'}>
{({ form, field, meta: { error, touched } }) => (
<FormGroup
label={<T id={'prefix'} />}
className={'form-group--'}
intent={inputIntent({ error, touched })}
{...field}
/>
</FormGroup>
)}
</FastField>
</Col>
helperText={<ErrorMessage name={'numberPrefix'} />}
>
<InputGroup
intent={inputIntent({ error, touched })}
{...field}
/>
</FormGroup>
)}
</FastField>
</Col>
{/* ------------- Next number ------------- */}
<Col xs={6}>
<FastField name={'next_number'}>
{({ form, field, meta: { error, touched } }) => (
<FormGroup
label={<T id={'next_number'} />}
className={'form-group--'}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name={'next_number'} />}
>
<InputGroup
{/* ------------- Next number ------------- */}
<Col xs={6}>
<FastField name={'nextNumber'}>
{({ form, field, meta: { error, touched } }) => (
<FormGroup
label={<T id={'next_number'} />}
className={'form-group--next-number'}
intent={inputIntent({ error, touched })}
{...field}
/>
</FormGroup>
)}
</FastField>
</Col>
</Row>
helperText={<ErrorMessage name={'nextNumber'} />}
>
<InputGroup
intent={inputIntent({ error, touched })}
{...field}
/>
</FormGroup>
)}
</FastField>
</Col>
</Row>
</If>
<FastField name={'mode'}>
{/* ------------- Manual increment mode ------------- */}
<FastField name={'incrementMode'}>
{({ form, field, meta: { error, touched } }) => (
<Radio label="Manual entring for this transaction." value="manual" {...field} />
<Radio
label="I will enter them manully each time."
value="manual"
onChange={() => {
form.setFieldValue('incrementMode', 'manual');
}}
checked={field.value === 'manual'}
/>
)}
</FastField>
{/* ------------- Transaction manual increment mode ------------- */}
<If condition={values.manualTransactionNo}>
<FastField name={'incrementMode'}>
{({ form, field, meta: { error, touched } }) => (
<Radio
label="Manual entring for this transaction."
value="manual"
onChange={() => {
form.setFieldValue('incrementMode', 'manual-transaction');
}}
checked={field.value === 'manual-transaction'}
/>
)}
</FastField>
</If>
</>
);
}

View File

@@ -0,0 +1,36 @@
import {
transformToForm,
optionsMapToArray,
transfromToSnakeCase,
transactionNumber,
} from 'utils';
export const defaultInvoiceNoSettings = {
nextNumber: '',
numberPrefix: '',
autoIncrement: '',
};
export const transformSettingsToForm = (settings) => ({
...settings,
incrementMode: settings.autoIncrement === 'true' ? 'auto' : 'manual',
});
export const transformFormToSettings = (values, group) => {
const options = transfromToSnakeCase({
...transformToForm(values, defaultInvoiceNoSettings),
autoIncrement: values.incrementMode === 'auto',
});
return optionsMapToArray(options).map((option) => ({ ...option, group }));
};
export const transformValuesToForm = (values) => {
const incrementNumber =
values.incrementMode === 'auto'
? transactionNumber(values.numberPrefix, values.nextNumber)
: values.manualTransactionNo;
const manually = values.incrementMode === 'auto' ? false : true;
return { incrementNumber, manually };
};

View File

@@ -16,7 +16,7 @@ export default function PaymentMadeFooter() {
<Row>
<Col md={8}>
{/* --------- Statement --------- */}
<FastField name={'customer_name'}>
<FastField name={'statement'}>
{({ form, field, meta: { error, touched } }) => (
<FormGroup
label={<T id={'statement'} />}

View File

@@ -21,7 +21,7 @@ export const defaultPaymentMade = {
payment_date: moment(new Date()).format('YYYY-MM-DD'),
reference: '',
payment_number: '',
description: '',
statement: '',
entries: [],
};

View File

@@ -1,10 +1,11 @@
import React from 'react';
import ListSelect from 'components/ListSelect';
import { Button, MenuItem } from '@blueprintjs/core';
import { FormattedMessage as T } from 'react-intl';
import { useHistory } from 'react-router-dom';
import { Icon } from 'components';
import { Position } from '@blueprintjs/core';
import quickNewOptions from 'common/quickNewOptions';
import { Select } from '@blueprintjs/select';
/**
* Quick New Dropdown.
@@ -12,26 +13,29 @@ import quickNewOptions from 'common/quickNewOptions';
function QuickNewDropdown() {
const history = useHistory();
const handleClickQuickNew = ({path }) => {
const handleClickQuickNew = ({ path }) => {
history.push(`/${path}`);
};
const itemRenderer = (item, { handleClick, modifiers, query }) => (
<MenuItem text={item.name} label={item.label} onClick={handleClick} />
);
return (
<ListSelect
<Select
items={quickNewOptions}
itemRenderer={itemRenderer}
onItemSelect={(type) => handleClickQuickNew(type)}
textProp={'name'}
labelProp={'label'}
filterable={false}
popoverProps={{ minimal: false, position: Position.BOTTOM }}
defaultText={'Select'}
buttonProps={{
text: <T id={'quick_new'} />,
icon: <Icon icon={'plus-24'} iconSize={20} />,
minimal: true,
}}
className={'form-group-quick-new-downDrop'}
/>
className={'form-group--quick-new-downDrop'}
filterable={false}
>
<Button
text={<T id={'quick_new'} />}
icon={<Icon icon={'plus-24'} iconSize={20} />}
minimal={true}
/>
</Select>
);
}

View File

@@ -22,7 +22,7 @@ import withSettings from 'containers/Settings/withSettings';
import { AppToaster } from 'components';
import { ERROR } from 'common/errors';
import { compose, orderingLinesIndexes } from 'utils';
import { compose, transactionNumber, orderingLinesIndexes } from 'utils';
import { useEstimateFormContext } from './EstimateFormProvider';
import { transformToEditForm, defaultEstimate } from './utils';
@@ -33,6 +33,7 @@ function EstimateForm({
// #withSettings
estimateNextNumber,
estimateNumberPrefix,
estimateIncrementMode,
}) {
const { formatMessage } = useIntl();
const history = useHistory();
@@ -44,24 +45,25 @@ function EstimateForm({
editEstimateMutate,
} = useEstimateFormContext();
const estimateNumber = estimateNumberPrefix
? `${estimateNumberPrefix}-${estimateNextNumber}`
: estimateNextNumber;
const estimateNumber = transactionNumber(
estimateNumberPrefix,
estimateNextNumber,
);
// Initial values in create and edit mode.
const initialValues = useMemo(
() => ({
...(!isEmpty(estimate)
? {
...transformToEditForm(estimate),
}
? { ...transformToEditForm(estimate) }
: {
...defaultEstimate,
estimate_number: estimateNumber,
...(estimateIncrementMode) && ({
estimate_number: estimateNumber,
}),
entries: orderingLinesIndexes(defaultEstimate.entries),
}),
}),
[estimate, estimateNumber],
[estimate, estimateNumber, estimateIncrementMode],
);
// Transform response errors to fields.
@@ -98,7 +100,10 @@ function EstimateForm({
return;
}
const form = {
...values,
...omit(values, ['estimate_number_manually', 'estimate_number']),
...(values.estimate_number_manually) && ({
estimate_number: values.estimate_number,
}),
delivered: submitPayload.deliver,
entries: entries.map((entry) => ({ ...omit(entry, ['total']) })),
};
@@ -134,7 +139,6 @@ function EstimateForm({
}
setSubmitting(false);
};
if (!isNewMode) {
editEstimateMutate([estimate.id, form]).then(onSuccess).catch(onError);
} else {
@@ -174,5 +178,6 @@ export default compose(
withSettings(({ estimatesSettings }) => ({
estimateNextNumber: estimatesSettings?.nextNumber,
estimateNumberPrefix: estimatesSettings?.numberPrefix,
estimateIncrementMode: estimatesSettings?.autoIncrement,
})),
)(EstimateForm);

View File

@@ -1,7 +1,6 @@
import React from 'react';
import { useFormikContext } from 'formik';
import EstimateNumberDialog from 'containers/Dialogs/EstimateNumberDialog';
import { transactionNumber } from 'utils';
/**
* Estimate form dialogs.
@@ -10,11 +9,9 @@ export default function EstimateFormDialogs() {
const { setFieldValue } = useFormikContext();
// Update the form once the invoice number form submit confirm.
const handleEstimateNumberFormConfirm = (values) => {
setFieldValue(
'estimate_number',
transactionNumber(values.number_prefix, values.next_number),
);
const handleEstimateNumberFormConfirm = ({ incrementNumber, manually }) => {
setFieldValue('estimate_number', incrementNumber || '');
setFieldValue('estimate_number_manually', manually);
};
return (

View File

@@ -8,7 +8,13 @@ import {
import { DateInput } from '@blueprintjs/datetime';
import { FormattedMessage as T } from 'react-intl';
import { FastField, ErrorMessage } from 'formik';
import { momentFormatter, compose, tansformDateValue } from 'utils';
import {
momentFormatter,
compose,
tansformDateValue,
inputIntent,
handleDateChange,
} from 'utils';
import classNames from 'classnames';
import { CLASSES } from 'common/classes';
import {
@@ -19,8 +25,9 @@ import {
} from 'components';
import withDialogActions from 'containers/Dialog/withDialogActions';
import withSettings from 'containers/Settings/withSettings';
import { inputIntent, handleDateChange } from 'utils';
import { useObserveEstimateNoSettings } from './utils';
import { useEstimateFormContext } from './EstimateFormProvider';
/**
@@ -29,6 +36,11 @@ import { useEstimateFormContext } from './EstimateFormProvider';
function EstimateFormHeader({
// #withDialogActions
openDialog,
// #withSettings
estimateAutoIncrement,
estimateNumberPrefix,
estimateNextNumber,
}) {
const { customers } = useEstimateFormContext();
@@ -36,6 +48,22 @@ function EstimateFormHeader({
openDialog('estimate-number-form', {});
};
const handleEstimateNoBlur = (form, field) => (event) => {
const newValue = event.target.value;
if (field.value !== newValue && estimateAutoIncrement) {
openDialog('estimate-number-form', {
initialFormValues: {
manualTransactionNo: newValue,
incrementMode: 'manual-transaction',
},
});
}
};
// Syncs estimate number settings with the form.
useObserveEstimateNoSettings(estimateNumberPrefix, estimateNextNumber);
return (
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
{/* ----------- Customer name ----------- */}
@@ -131,7 +159,9 @@ function EstimateFormHeader({
<ControlGroup fill={true}>
<InputGroup
minimal={true}
{...field}
value={field.value}
asyncControl={true}
onBlur={handleEstimateNoBlur(form, field)}
/>
<InputPrependButton
buttonProps={{
@@ -169,4 +199,9 @@ function EstimateFormHeader({
export default compose(
withDialogActions,
withSettings(({ estimatesSettings }) => ({
estimateNextNumber: estimatesSettings?.nextNumber,
estimateNumberPrefix: estimatesSettings?.numberPrefix,
estimateAutoIncrement: estimatesSettings?.autoIncrement,
})),
)(EstimateFormHeader);

View File

@@ -4,7 +4,7 @@ import {
useEstimate,
useCustomers,
useItems,
useSettings,
useSettingsEstimates,
useCreateEstimate,
useEditEstimate
} from 'hooks/query';
@@ -32,7 +32,7 @@ function EstimateFormProvider({ estimateId, ...props }) {
} = useCustomers({ page_size: 10000 });
// Handle fetch settings.
useSettings();
useSettingsEstimates();
// Form submit payload.
const [submitPayload, setSubmitPayload] = React.useState({});

View File

@@ -1,5 +1,7 @@
import React from 'react';
import { useFormikContext } from 'formik';
import moment from 'moment';
import { repeatValue, transformToForm } from 'utils';
import { transactionNumber, repeatValue, transformToForm } from 'utils';
export const MIN_LINES_NUMBER = 4;
@@ -35,4 +37,16 @@ export const transformToEditForm = (estimate) => ({
Math.max(MIN_LINES_NUMBER - estimate.entries.length, 0),
),
],
});
});
/**
* 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]);
}

View File

@@ -33,6 +33,7 @@ function InvoiceForm({
// #withSettings
invoiceNextNumber,
invoiceNumberPrefix,
invoiceIncrementMode,
}) {
const { formatMessage } = useIntl();
const history = useHistory();
@@ -53,7 +54,6 @@ function InvoiceForm({
invoiceNumberPrefix,
invoiceNextNumber,
);
// Form initial values.
const initialValues = useMemo(
() => ({
@@ -61,12 +61,14 @@ function InvoiceForm({
? transformToEditForm(invoice)
: {
...defaultInvoice,
invoice_no: invoiceNumber,
...(invoiceIncrementMode) && ({
invoice_no: invoiceNumber,
}),
entries: orderingLinesIndexes(defaultInvoice.entries),
...newInvoice,
}),
}),
[invoice, newInvoice,invoiceNumber],
[invoice, newInvoice, invoiceNumber, invoiceIncrementMode],
);
// Handles form submit.
@@ -88,7 +90,10 @@ function InvoiceForm({
return;
}
const form = {
...values,
...omit(values, ['invoice_no', 'invoice_no_manually']),
...(values.invoice_no_manually) && ({
invoice_no: values.invoice_no,
}),
delivered: submitPayload.deliver,
from_estimate_id: estimateId,
entries: entries.map((entry) => ({ ...omit(entry, ['total']) })),
@@ -127,7 +132,6 @@ function InvoiceForm({
}
setSubmitting(false);
};
if (!isEmpty(invoice)) {
editInvoiceMutate([invoice.id, form]).then(onSuccess).catch(onError);
} else {
@@ -144,7 +148,6 @@ function InvoiceForm({
)}
>
<Formik
enableReinitialize={true}
validationSchema={
isNewMode ? CreateInvoiceFormSchema : EditInvoiceFormSchema
}
@@ -169,5 +172,6 @@ export default compose(
withSettings(({ invoiceSettings }) => ({
invoiceNextNumber: invoiceSettings?.nextNumber,
invoiceNumberPrefix: invoiceSettings?.numberPrefix,
invoiceIncrementMode: invoiceSettings?.incrementMode,
})),
)(InvoiceForm);

View File

@@ -1,7 +1,6 @@
import React from 'react';
import InvoiceNumberDialog from 'containers/Dialogs/InvoiceNumberDialog';
import { useFormikContext } from 'formik';
import { transactionNumber } from 'utils';
/**
* Invoice form dialogs.
@@ -10,15 +9,11 @@ export default function InvoiceFormDialogs() {
const { setFieldValue } = useFormikContext();
// Update the form once the invoice number form submit confirm.
const handleInvoiceNumberFormConfirm = (values) => {
debugger;
console.log(values, 'XX');
setFieldValue(
'invoice_no',
transactionNumber(values.number_prefix, values.next_number),
);
const handleInvoiceNumberFormConfirm = ({ incrementNumber, manually }) => {
setFieldValue('invoice_no', incrementNumber || '');
setFieldValue('invoice_no_manually', manually);
};
return (
<>
<InvoiceNumberDialog

View File

@@ -6,10 +6,11 @@ import {
ControlGroup,
} from '@blueprintjs/core';
import { DateInput } from '@blueprintjs/datetime';
import { FastField, ErrorMessage } from 'formik';
import { FastField, Field, ErrorMessage } from 'formik';
import { FormattedMessage as T } from 'react-intl';
import { momentFormatter, compose, tansformDateValue } from 'utils';
import classNames from 'classnames';
import { useObserveInvoiceNoSettings } from './utils';
import { CLASSES } from 'common/classes';
import {
ContactSelecetList,
@@ -17,8 +18,8 @@ import {
Icon,
InputPrependButton,
} from 'components';
import { useInvoiceFormContext } from './InvoiceFormProvider';
import withSettings from 'containers/Settings/withSettings';
import withDialogActions from 'containers/Dialog/withDialogActions';
import { inputIntent, handleDateChange } from 'utils';
@@ -28,15 +29,40 @@ import { inputIntent, handleDateChange } from 'utils';
function InvoiceFormHeaderFields({
// #withDialogActions
openDialog,
// #withSettings
invoiceAutoIncrement,
invoiceNumberPrefix,
invoiceNextNumber,
}) {
// Invoice form context.
const { customers } = useInvoiceFormContext();
// Handle invoice number changing.
const handleInvoiceNumberChange = () => {
openDialog('invoice-number-form', {});
openDialog('invoice-number-form');
};
// Handle invoice no. field blur.
const handleInvoiceNoBlur = (form, field) => (event) => {
const newValue = event.target.value;
if (field.value !== newValue && invoiceAutoIncrement) {
openDialog('invoice-number-form', {
initialFormValues: {
manualTransactionNo: newValue,
incrementMode: 'manual-transaction',
},
});
}
};
// Syncs invoice number settings with form.
useObserveInvoiceNoSettings(
invoiceNumberPrefix,
invoiceNextNumber,
);
return (
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
{/* ----------- Customer name ----------- */}
@@ -45,7 +71,11 @@ function InvoiceFormHeaderFields({
<FormGroup
label={<T id={'customer_name'} />}
inline={true}
className={classNames('form-group--customer-name', 'form-group--select-list', CLASSES.FILL)}
className={classNames(
'form-group--customer-name',
'form-group--select-list',
CLASSES.FILL,
)}
labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name={'customer_id'} />}
@@ -115,7 +145,7 @@ function InvoiceFormHeaderFields({
</FastField>
{/* ----------- Invoice number ----------- */}
<FastField name={'invoice_no'}>
<Field name={'invoice_no'}>
{({ form, field, meta: { error, touched } }) => (
<FormGroup
label={<T id={'invoice_no'} />}
@@ -127,7 +157,9 @@ function InvoiceFormHeaderFields({
<ControlGroup fill={true}>
<InputGroup
minimal={true}
{...field}
value={field.value}
asyncControl={true}
onBlur={handleInvoiceNoBlur(form, field)}
/>
<InputPrependButton
buttonProps={{
@@ -143,7 +175,7 @@ function InvoiceFormHeaderFields({
</ControlGroup>
</FormGroup>
)}
</FastField>
</Field>
{/* ----------- Reference ----------- */}
<FastField name={'reference'}>
@@ -165,4 +197,9 @@ function InvoiceFormHeaderFields({
export default compose(
withDialogActions,
withSettings(({ invoiceSettings }) => ({
invoiceAutoIncrement: invoiceSettings?.autoIncrement,
invoiceNextNumber: invoiceSettings?.nextNumber,
invoiceNumberPrefix: invoiceSettings?.numberPrefix,
})),
)(InvoiceFormHeaderFields);

View File

@@ -26,6 +26,7 @@ function InvoiceFormProvider({ invoiceId, ...props }) {
enabled: !!invoiceId,
});
// Fetches the estimate by the given id.
const {
data: estimate,
isFetching: isEstimateFetching,

View File

@@ -1,10 +1,19 @@
import React from 'react';
import moment from 'moment';
import { compose, transformToForm, repeatValue } from 'utils';
import { isEmpty } from 'lodash';
import {
compose,
transformToForm,
repeatValue,
transactionNumber,
} from 'utils';
import { updateItemsEntriesTotal } from 'containers/Entries/utils';
import { ERROR } from 'common/errors';
import { useFormikContext } from 'formik';
import { Intent } from '@blueprintjs/core';
import { orderingLinesIndexes } from 'utils';
import { formatMessage } from 'services/intl';
import { ERROR } from 'common/errors';
import { AppToaster } from 'components';
export const MIN_LINES_NUMBER = 4;
@@ -27,6 +36,7 @@ export const defaultInvoice = {
due_date: moment().format('YYYY-MM-DD'),
delivered: '',
invoice_no: '',
invoice_no_manually: false,
reference_no: '',
invoice_message: '',
terms_conditions: '',
@@ -72,4 +82,24 @@ export const transformErrors = (errors, { setErrors }) => {
intent: Intent.DANGER,
});
}
if (
errors.some((error) => error.type === ERROR.SALE_INVOICE_NO_IS_REQUIRED)
) {
setErrors({
invoice_no:
'Invoice number is required, use auto-increment mode or enter manually.',
});
}
};
/**
* 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]);
};

View File

@@ -186,7 +186,7 @@ export function useInvoicesTableColumns() {
{
id: 'invoice_no',
Header: formatMessage({ id: 'invoice_no__' }),
accessor: (row) => (row.invoice_no ? `#${row.invoice_no}` : null),
accessor: 'invoice_no',
width: 100,
className: 'invoice_no',
},

View File

@@ -1,7 +1,7 @@
import React, { useMemo } from 'react';
import { Formik, Form } from 'formik';
import { useIntl } from 'react-intl';
import { sumBy, pick, isEmpty } from 'lodash';
import { omit, sumBy, pick, isEmpty } from 'lodash';
import { Intent } from '@blueprintjs/core';
import classNames from 'classnames';
import { useHistory } from 'react-router-dom';
@@ -23,13 +23,10 @@ import {
CreatePaymentReceiveFormSchema,
} from './PaymentReceiveForm.schema';
import { AppToaster } from 'components';
import { compose } from 'utils';
import { transactionNumber, compose } from 'utils';
import { usePaymentReceiveFormContext } from './PaymentReceiveFormProvider';
import {
defaultPaymentReceive,
transformToEditForm,
} from './utils';
import { defaultPaymentReceive, transformToEditForm } from './utils';
/**
* Payment Receive form.
@@ -38,6 +35,7 @@ function PaymentReceiveForm({
// #withSettings
paymentReceiveNextNumber,
paymentReceiveNumberPrefix,
paymentReceiveAutoIncrement,
}) {
const history = useHistory();
const { formatMessage } = useIntl();
@@ -54,10 +52,10 @@ function PaymentReceiveForm({
} = usePaymentReceiveFormContext();
// Payment receive number.
const paymentReceiveNumber = paymentReceiveNumberPrefix
? `${paymentReceiveNumberPrefix}-${paymentReceiveNextNumber}`
: paymentReceiveNextNumber;
const nextPaymentNumber = transactionNumber(
paymentReceiveNumberPrefix,
paymentReceiveNextNumber
);
// Form initial values.
const initialValues = useMemo(
() => ({
@@ -65,10 +63,17 @@ function PaymentReceiveForm({
? transformToEditForm(paymentReceiveEditPage, paymentEntriesEditPage)
: {
...defaultPaymentReceive,
payment_receive_no: paymentReceiveNumber,
...(paymentReceiveAutoIncrement && {
payment_receive_no: nextPaymentNumber,
}),
}),
}),
[paymentReceiveEditPage, paymentReceiveNumber, paymentEntriesEditPage],
[
paymentReceiveEditPage,
nextPaymentNumber,
paymentEntriesEditPage,
paymentReceiveAutoIncrement,
],
);
// Handle form submit.
@@ -98,7 +103,13 @@ function PaymentReceiveForm({
setSubmitting(false);
return;
}
const form = { ...values, entries };
const form = {
...omit(values, ['payment_receive_no_manually', 'payment_receive_no']),
...(values.payment_receive_no_manually) && ({
payment_receive_no: values.payment_receive_no,
}),
entries
};
// Handle request response success.
const onSaved = (response) => {
@@ -120,7 +131,11 @@ function PaymentReceiveForm({
}
};
// Handle request response errors.
const onError = ({ response: { data: { errors } } }) => {
const onError = ({
response: {
data: { errors },
},
}) => {
const getError = (errorType) => errors.find((e) => e.type === errorType);
if (getError('PAYMENT_RECEIVE_NO_EXISTS')) {
@@ -179,5 +194,6 @@ export default compose(
withSettings(({ paymentReceiveSettings }) => ({
paymentReceiveNextNumber: paymentReceiveSettings?.nextNumber,
paymentReceiveNumberPrefix: paymentReceiveSettings?.numberPrefix,
paymentReceiveAutoIncrement: paymentReceiveSettings?.autoIncrement,
})),
)(PaymentReceiveForm);

View File

@@ -1,7 +1,6 @@
import React from 'react';
import { useFormikContext } from 'formik';
import PaymentReceiveNumberDialog from 'containers/Dialogs/PaymentReceiveNumberDialog';
import { transactionNumber } from 'utils';
/**
* Payment receive form dialogs.
@@ -9,11 +8,9 @@ import { transactionNumber } from 'utils';
export default function PaymentReceiveFormDialogs() {
const { setFieldValue } = useFormikContext();
const handleUpdatePaymentNumber = (values) => {
setFieldValue(
'payment_receive_no',
transactionNumber(values.number_prefix, values.next_number),
);
const handleUpdatePaymentNumber = ({ incrementNumber, manually }) => {
setFieldValue('payment_receive_no', incrementNumber);
setFieldValue('payment_receive_no_manually', manually)
};
return (

View File

@@ -1,7 +1,7 @@
import React, { createContext, useContext } from 'react';
import { DashboardInsider } from 'components';
import {
useSettings,
useSettingsPaymentReceives,
usePaymentReceiveEditPage,
useAccounts,
useCustomers,
@@ -34,7 +34,7 @@ function PaymentReceiveFormProvider({ paymentReceiveId, ...props }) {
const { data: accounts, isFetching: isAccountsFetching } = useAccounts();
// Fetch payment made settings.
const fetchSettings = useSettings();
const fetchSettings = useSettingsPaymentReceives();
// Fetches customers list.
const {

View File

@@ -36,7 +36,11 @@ import { usePaymentReceiveFormContext } from './PaymentReceiveFormProvider';
import withDialogActions from 'containers/Dialog/withDialogActions';
import withSettings from 'containers/Settings/withSettings';
import { amountPaymentEntries, fullAmountPaymentEntries } from './utils';
import {
useObservePaymentNoSettings,
amountPaymentEntries,
fullAmountPaymentEntries,
} from './utils';
import { toSafeInteger } from 'lodash';
/**
@@ -47,6 +51,11 @@ function PaymentReceiveHeaderFields({
// #withDialogActions
openDialog,
// #withSettings
paymentReceiveAutoIncrement,
paymentReceiveNumberPrefix,
paymentReceiveNextNumber,
}) {
// Payment receive form context.
const { customers, accounts, isNewMode } = usePaymentReceiveFormContext();
@@ -63,7 +72,6 @@ function PaymentReceiveHeaderFields({
const totalDueAmount = useMemo(() => safeSumBy(entries, 'due_amount'), [
entries,
]);
// Handle receive full-amount link click.
const handleReceiveFullAmountClick = () => {
const newEntries = fullAmountPaymentEntries(entries);
@@ -72,18 +80,36 @@ function PaymentReceiveHeaderFields({
setFieldValue('entries', newEntries);
setFieldValue('full_amount', fullAmount);
};
// Handles the full-amount field blur.
const onFullAmountBlur = (value) => {
const newEntries = amountPaymentEntries(toSafeInteger(value), entries);
setFieldValue('entries', newEntries);
};
// Handle click open payment receive number dialog.
const handleClickOpenDialog = () => {
openDialog('payment-receive-number-form');
};
// Handle payment number field blur.
const handlePaymentNoBlur = (form, field) => (event) => {
const newValue = event.target.value;
if (field.value !== newValue && paymentReceiveAutoIncrement) {
openDialog('payment-receive-number-form', {
initialFormValues: {
manualTransactionNo: newValue,
incrementMode: 'manual-transaction',
},
});
}
};
// Syncs payment receive number from settings to the form.
useObservePaymentNoSettings(
paymentReceiveNumberPrefix,
paymentReceiveNextNumber,
);
return (
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
{/* ------------- Customer name ------------- */}
@@ -194,7 +220,9 @@ function PaymentReceiveHeaderFields({
<InputGroup
intent={inputIntent({ error, touched })}
minimal={true}
{...field}
value={field.value}
asyncControl={true}
onBlur={handlePaymentNoBlur(form, field)}
/>
<InputPrependButton
buttonProps={{
@@ -263,8 +291,11 @@ function PaymentReceiveHeaderFields({
}
export default compose(
withSettings(({ organizationSettings }) => ({
withSettings(({ organizationSettings, paymentReceiveSettings }) => ({
baseCurrency: organizationSettings?.baseCurrency,
paymentReceiveNextNumber: paymentReceiveSettings?.nextNumber,
paymentReceiveNumberPrefix: paymentReceiveSettings?.numberPrefix,
paymentReceiveAutoIncrement: paymentReceiveSettings?.autoIncrement,
})),
withDialogActions,
)(PaymentReceiveHeaderFields);

View File

@@ -1,5 +1,7 @@
import React from 'react';
import { useFormikContext } from 'formik';
import moment from 'moment';
import { transformToForm, safeSumBy } from 'utils';
import { transactionNumber, transformToForm, safeSumBy } from 'utils';
// Default payment receive entry.
export const defaultPaymentReceiveEntry = {
@@ -18,7 +20,7 @@ export const defaultPaymentReceive = {
payment_date: moment(new Date()).format('YYYY-MM-DD'),
reference_no: '',
payment_receive_no: '',
description: '',
statement: '',
full_amount: '',
entries: [],
};
@@ -81,4 +83,16 @@ export const fullAmountPaymentEntries = (entries) => {
...item,
payment_amount: item.due_amount,
}));
}
}
/**
* Syncs payment receive number settings with form.
*/
export const useObservePaymentNoSettings = (prefix, nextNumber) => {
const { setFieldValue } = useFormikContext();
React.useEffect(() => {
const invoiceNo = transactionNumber(prefix, nextNumber);
setFieldValue('payment_receive_no', invoiceNo);
}, [setFieldValue, prefix, nextNumber]);
};

View File

@@ -10,7 +10,7 @@ import { CLASSES } from 'common/classes';
import { ERROR } from 'common/errors';
import {
EditReceiptFormSchema,
CreateReceiptFormSchema,
CreateReceiptFormSchema,
} from './ReceiptForm.schema';
import { useReceiptFormContext } from './ReceiptFormProvider';
@@ -25,13 +25,8 @@ import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import withSettings from 'containers/Settings/withSettings';
import { AppToaster } from 'components';
import {
compose,
orderingLinesIndexes,
transactionNumber,
} from 'utils';
import { transformToEditForm, defaultReceipt } from './utils'
import { compose, orderingLinesIndexes, transactionNumber } from 'utils';
import { transformToEditForm, defaultReceipt } from './utils';
/**
* Receipt form.
@@ -40,6 +35,7 @@ function ReceiptForm({
// #withSettings
receiptNextNumber,
receiptNumberPrefix,
receiptAutoIncrement,
preferredDepositAccount,
}) {
const { formatMessage } = useIntl();
@@ -47,16 +43,15 @@ function ReceiptForm({
// Receipt form context.
const {
receiptId,
receipt,
editReceiptMutate,
createReceiptMutate,
submitPayload,
isNewMode
isNewMode,
} = useReceiptFormContext();
// The next receipt number.
const receiptNumber = transactionNumber(
const nextReceiptNumber = transactionNumber(
receiptNumberPrefix,
receiptNextNumber,
);
@@ -67,12 +62,14 @@ function ReceiptForm({
? transformToEditForm(receipt)
: {
...defaultReceipt,
receipt_number: receiptNumber,
...(receiptAutoIncrement && {
receipt_number: nextReceiptNumber,
}),
deposit_account_id: parseInt(preferredDepositAccount),
entries: orderingLinesIndexes(defaultReceipt.entries),
}),
}),
[receipt, preferredDepositAccount, receiptNumber],
[receipt, preferredDepositAccount, nextReceiptNumber, receiptAutoIncrement],
);
// Transform response error to fields.
@@ -107,9 +104,12 @@ function ReceiptForm({
return;
}
const form = {
...values,
...omit(values, ['receipt_number_manually', 'receipt_number']),
...(values.receipt_number_manually) && ({
receipt_number: values.receipt_number,
}),
closed: submitPayload.status,
entries: entries.map((entry) => ({ ...omit(entry, ['total']), })),
entries: entries.map((entry) => ({ ...omit(entry, ['total']) })),
};
// Handle the request success.
const onSuccess = (response) => {
@@ -135,13 +135,16 @@ function ReceiptForm({
};
// Handle the request error.
const onError = ({response:{data:{errors}}}) => {
if(errors){
const onError = ({
response: {
data: { errors },
},
}) => {
if (errors) {
handleErrors(errors, { setErrors });
}
setSubmitting(false);
};
if (!isNewMode) {
editReceiptMutate([receipt.id, form]).then(onSuccess).catch(onError);
} else {
@@ -182,6 +185,7 @@ export default compose(
withSettings(({ receiptSettings }) => ({
receiptNextNumber: receiptSettings?.nextNumber,
receiptNumberPrefix: receiptSettings?.numberPrefix,
receiptAutoIncrement: receiptSettings?.autoIncrement,
preferredDepositAccount: receiptSettings?.preferredDepositAccount,
})),
)(ReceiptForm);

View File

@@ -1,7 +1,6 @@
import React from 'react';
import { useFormikContext } from 'formik';
import ReceiptNumberDialog from 'containers/Dialogs/ReceiptNumberDialog';
import { transactionNumber } from 'utils';
/**
* Receipt form dialogs.
@@ -10,11 +9,9 @@ export default function ReceiptFormDialogs() {
const { setFieldValue } = useFormikContext();
// Update the form once the receipt number form submit confirm.
const handleReceiptNumberFormConfirm = (values) => {
setFieldValue(
'receipt_number',
transactionNumber(values.number_prefix, values.next_number),
);
const handleReceiptNumberFormConfirm = ({ incrementNumber, manually }) => {
setFieldValue('receipt_number', incrementNumber || '');
setFieldValue('receipt_number_manually', manually);
};
return (

View File

@@ -5,12 +5,10 @@ import {
Position,
ControlGroup,
} from '@blueprintjs/core';
import { DateInput } from '@blueprintjs/datetime';
import { FormattedMessage as T } from 'react-intl';
import classNames from 'classnames';
import { FastField, ErrorMessage } from 'formik';
import { CLASSES } from 'common/classes';
import {
AccountsSelectList,
@@ -19,17 +17,17 @@ import {
Icon,
InputPrependButton,
} from 'components';
import withSettings from 'containers/Settings/withSettings';
import withDialogActions from 'containers/Dialog/withDialogActions';
import {
momentFormatter,
compose,
tansformDateValue,
saveInvoke,
handleDateChange,
inputIntent,
} from 'utils';
import { useReceiptFormContext } from './ReceiptFormProvider';
import { useObserveReceiptNoSettings } from './utils';
/**
* Receipt form header fields.
@@ -40,6 +38,11 @@ function ReceiptFormHeader({
// #ownProps
onReceiptNumberChanged,
// #withSettings
receiptAutoIncrement,
receiptNextNumber,
receiptNumberPrefix,
}) {
const { accounts, customers } = useReceiptFormContext();
@@ -47,10 +50,25 @@ function ReceiptFormHeader({
openDialog('receipt-number-form', {});
}, [openDialog]);
const handleReceiptNumberChanged = (event) => {
saveInvoke(onReceiptNumberChanged, event.currentTarget.value);
const handleReceiptNoBlur = (form, field) => (event) => {
const newValue = event.target.value;
if (field.value !== newValue && receiptAutoIncrement) {
openDialog('receipt-number-form', {
initialFormValues: {
manualTransactionNo: newValue,
incrementMode: 'manual-transaction',
},
});
}
};
// Synsc receipt number settings with the form.
useObserveReceiptNoSettings(
receiptNumberPrefix,
receiptNextNumber,
);
return (
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
{/* ----------- Customer name ----------- */}
@@ -129,7 +147,7 @@ function ReceiptFormHeader({
{/* ----------- Receipt number ----------- */}
<FastField name={'receipt_number'}>
{({ field, meta: { error, touched } }) => (
{({ form, field, meta: { error, touched } }) => (
<FormGroup
label={<T id={'receipt'} />}
inline={true}
@@ -141,8 +159,9 @@ function ReceiptFormHeader({
<ControlGroup fill={true}>
<InputGroup
minimal={true}
{...field}
onBlur={handleReceiptNumberChanged}
value={field.value}
asyncControl={true}
onBlur={handleReceiptNoBlur(form, field)}
/>
<InputPrependButton
buttonProps={{
@@ -183,4 +202,9 @@ function ReceiptFormHeader({
export default compose(
withDialogActions,
withSettings(({ receiptSettings }) => ({
receiptAutoIncrement: receiptSettings?.autoIncrement,
receiptNextNumber: receiptSettings?.nextNumber,
receiptNumberPrefix: receiptSettings?.numberPrefix,
})),
)(ReceiptFormHeader);

View File

@@ -3,7 +3,7 @@ import DashboardInsider from 'components/Dashboard/DashboardInsider';
import {
useReceipt,
useAccounts,
useSettings,
useSettingsReceipts,
useCustomers,
useItems,
useCreateReceipt,
@@ -39,7 +39,7 @@ function ReceiptFormProvider({ receiptId, ...props }) {
} = useItems({ page_size: 10000 });
// Fetch receipt settings.
const { isLoading: isSettingLoading } = useSettings();
const { isLoading: isSettingLoading } = useSettingsReceipts();
const { mutateAsync: createReceiptMutate } = useCreateReceipt();
const { mutateAsync: editReceiptMutate } = useEditReceipt();

View File

@@ -1,5 +1,7 @@
import React from 'react';
import { useFormikContext } from 'formik';
import moment from 'moment';
import { repeatValue, transformToForm } from 'utils';
import { transactionNumber, repeatValue, transformToForm } from 'utils';
export const MIN_LINES_NUMBER = 4;
@@ -39,3 +41,13 @@ 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]);
}

View File

@@ -114,8 +114,7 @@ export function useReceiptsTableColumns() {
{
id: 'receipt_number',
Header: formatMessage({ id: 'receipt_number' }),
accessor: (row) =>
row.receipt_number ? `#${row.receipt_number}` : null,
accessor: 'receipt_number',
width: 140,
className: 'receipt_number',
},
@@ -138,7 +137,7 @@ export function useReceiptsTableColumns() {
Header: formatMessage({ id: 'status' }),
accessor: StatusAccessor,
width: 140,
className: 'amount',
className: 'status',
},
{
id: 'reference_no',