feat: add Auto increment in credit note number.

This commit is contained in:
elforjani13
2021-12-01 14:02:31 +02:00
parent eeb16f4362
commit 432e2d202a
10 changed files with 311 additions and 13 deletions

View File

@@ -0,0 +1,102 @@
import React from 'react';
import intl from 'react-intl-universal';
import { useSaveSettings } from 'hooks/query';
import { CreditNoteNumberDialogProvider } from './CreditNoteNumberDialogProvider';
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 { compose } from 'utils';
import {
transformFormToSettings,
transformSettingsToForm,
} from 'containers/JournalNumber/utils';
/**
* credit note number dialog content
*/
function CreditNoteNumberDialogContent({
// #ownProps
initialValues,
onConfirm,
// #withSettings
nextNumber,
numberPrefix,
autoIncrement,
// #withDialogActions
closeDialog,
}) {
const { mutateAsync: saveSettings } = useSaveSettings();
const [referenceFormValues, setReferenceFormValues] = React.useState(null);
// Handle the submit form.
const handleSubmitForm = (values, { setSubmitting }) => {
// Handle the form success.
const handleSuccess = () => {
setSubmitting(false);
closeDialog('credit-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, 'credit_note');
// Save the settings.
saveSettings({ options }).then(handleSuccess).catch(handleErrors);
};
// Handle the dialog close.
const handleClose = () => {
closeDialog('credit-number-form');
};
// Handle form change.
const handleChange = (values) => {
setReferenceFormValues(values);
};
// Description.
const description =
referenceFormValues?.incrementMode === 'auto'
? intl.get('credit_note.auto_increment.auto')
: intl.get('credit_note.auto_increment.manually');
return (
<CreditNoteNumberDialogProvider>
<ReferenceNumberForm
initialValues={{
...transformSettingsToForm({
nextNumber,
numberPrefix,
autoIncrement,
}),
...initialValues,
}}
description={description}
onSubmit={handleSubmitForm}
onClose={handleClose}
onChange={handleChange}
/>
</CreditNoteNumberDialogProvider>
);
}
export default compose(
withDialogActions,
withSettingsActions,
withSettings(({ creditNoteSettings }) => ({
autoIncrement: creditNoteSettings?.autoIncrement,
nextNumber: creditNoteSettings?.nextNumber,
numberPrefix: creditNoteSettings?.numberPrefix,
})),
)(CreditNoteNumberDialogContent);

View File

@@ -0,0 +1,28 @@
import React from 'react';
import { DialogContent } from 'components';
import { useSettingsCreditNotes } from 'hooks/query';
const CreditNoteNumberDialogContext = React.createContext();
/**
*Credit Note number dialog provider
*/
function CreditNoteNumberDialogProvider({ query, ...props }) {
const { isLoading: isSettingsLoading } = useSettingsCreditNotes();
// Provider payload.
const provider = {
isSettingsLoading,
};
return (
<DialogContent isLoading={isSettingsLoading}>
<CreditNoteNumberDialogContext.Provider value={provider} {...props} />
</DialogContent>
);
}
const useCreditNoteNumberDialogContext = () =>
React.useContext(CreditNoteNumberDialogContext);
export { CreditNoteNumberDialogProvider, useCreditNoteNumberDialogContext };

View File

@@ -0,0 +1,40 @@
import React from 'react';
import { Dialog, DialogSuspense, FormattedMessage as T } from 'components';
import withDialogRedux from 'components/DialogReduxConnect';
import { compose, saveInvoke } from 'utils';
const CreditNoteNumberDialogContent = React.lazy(() =>
import('./CreditNoteNumberDialogContent'),
);
/**
* Credit note number dialog.
*/
function CreditNoteNumberDialog({
dialogName,
payload: { initialFormValues },
isOpen,
onConfirm,
}) {
const handleConfirm = (values) => {
saveInvoke(onConfirm, values);
};
return (
<Dialog
title={<T id={'credit_note_number_settings'} />}
name={dialogName}
autoFocus={true}
canEscapeKeyClose={true}
isOpen={isOpen}
>
<DialogSuspense>
<CreditNoteNumberDialogContent
initialValues={{ ...initialFormValues }}
onConfirm={handleConfirm}
/>
</DialogSuspense>
</Dialog>
);
}
export default compose(withDialogRedux())(CreditNoteNumberDialog);

View File

@@ -15,6 +15,7 @@ import CreditNoteFormHeader from './CreditNoteFormHeader';
import CreditNoteItemsEntriesEditorField from './CreditNoteItemsEntriesEditorField';
import CreditNoteFormFooter from './CreditNoteFormFooter';
import CreditNoteFloatingActions from './CreditNoteFloatingActions';
import CreditNoteFormDialogs from './CreditNoteFormDialogs';
import { AppToaster } from 'components';
@@ -41,6 +42,9 @@ import withCurrentOrganization from 'containers/Organization/withCurrentOrganiza
*/
function CreditNoteForm({
// #withSettings
creditAutoIncrement,
creditNumberPrefix,
creditNextNumber,
// #withCurrentOrganization
organization: { base_currency },
@@ -56,6 +60,9 @@ function CreditNoteForm({
editCreditNoteMutate,
} = useCreditNoteFormContext();
// Credit number.
const creditNumber = transactionNumber(creditNumberPrefix, creditNextNumber);
// Initial values.
const initialValues = React.useMemo(
() => ({
@@ -63,6 +70,9 @@ function CreditNoteForm({
? { ...transformToEditForm(creditNote), currency_code: base_currency }
: {
...defaultCreditNote,
...(creditAutoIncrement && {
credit_note_number: creditNumber,
}),
entries: orderingLinesIndexes(defaultCreditNote.entries),
}),
}),
@@ -144,10 +154,17 @@ function CreditNoteForm({
<CreditNoteItemsEntriesEditorField />
<CreditNoteFormFooter />
<CreditNoteFloatingActions />
<CreditNoteFormDialogs />
</Form>
</Formik>
</div>
);
}
export default compose(withCurrentOrganization())(CreditNoteForm);
export default compose(
withSettings(({ creditNoteSettings }) => ({
creditAutoIncrement: creditNoteSettings?.autoIncrement,
creditNextNumber: creditNoteSettings?.nextNumber,
creditNumberPrefix: creditNoteSettings?.numberPrefix,
})),
withCurrentOrganization(),
)(CreditNoteForm);

View File

@@ -0,0 +1,24 @@
import React from 'react';
import CreditNoteNumberDialog from '../../../Dialogs/CreditNoteNumberDialog';
import { useFormikContext } from 'formik';
/**
* Credit note form dialogs.
*/
export default function CreditNoteFormDialogs() {
// Update the form once the credit number form submit confirm.
const handleCreditNumberFormConfirm = ({ incrementNumber, manually }) => {
setFieldValue('credit_note_number', incrementNumber || '');
setFieldValue('credit_note_no_manually', manually);
};
const { setFieldValue } = useFormikContext();
return (
<React.Fragment>
<CreditNoteNumberDialog
dialogName={'credit-number-form'}
onConfirm={handleCreditNumberFormConfirm}
/>
</React.Fragment>
);
}

View File

@@ -1,5 +1,10 @@
import React from 'react';
import { FormGroup, InputGroup, Position } from '@blueprintjs/core';
import {
FormGroup,
InputGroup,
Position,
ControlGroup,
} from '@blueprintjs/core';
import { DateInput } from '@blueprintjs/datetime';
import { FastField, Field, ErrorMessage } from 'formik';
import { CLASSES } from 'common/classes';
@@ -7,10 +12,14 @@ import classNames from 'classnames';
import {
ContactSelecetList,
FieldRequiredHint,
InputPrependButton,
Icon,
FormattedMessage as T,
} from 'components';
import { customerNameFieldShouldUpdate } from './utils';
import {
customerNameFieldShouldUpdate,
useObserveCreditNoSettings,
} from './utils';
import { useCreditNoteFormContext } from './CreditNoteFormProvider';
import withSettings from 'containers/Settings/withSettings';
@@ -27,10 +36,40 @@ import {
/**
* Credit note form header fields.
*/
function CreditNoteFormHeaderFields() {
function CreditNoteFormHeaderFields({
// #withDialogActions
openDialog,
// #withSettings
creditAutoIncrement,
creditNumberPrefix,
creditNextNumber,
}) {
// Credit note form context.
const { customers } = useCreditNoteFormContext();
// Handle credit number changing.
const handleCreditNumberChange = () => {
openDialog('credit-number-form');
};
// Handle credit no. field blur.
const handleCreditNoBlur = (form, field) => (event) => {
const newValue = event.target.value;
if (field.value !== newValue && creditAutoIncrement) {
openDialog('credit-number-form', {
initialFormValues: {
manualTransactionNo: newValue,
incrementMode: 'manual-transaction',
},
});
}
};
// Syncs credit number settings with form.
useObserveCreditNoSettings(creditNumberPrefix, creditNextNumber);
return (
<div className={classNames(CLASSES.PAGE_FORM_HEADER_FIELDS)}>
{/* ----------- Customer name ----------- */}
@@ -96,11 +135,34 @@ function CreditNoteFormHeaderFields() {
label={<T id={'credit_note.label_credit_note'} />}
labelInfo={<FieldRequiredHint />}
inline={true}
className={classNames('form-group--credit_note_number', CLASSES.FILL)}
className={classNames(
'form-group--credit_note_number',
CLASSES.FILL,
)}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="credit_note_number" />}
>
<InputGroup minimal={true} {...field} />
<ControlGroup fill={true}>
<InputGroup
minimal={true}
value={field.value}
asyncControl={true}
onBlur={handleCreditNoBlur(form, field)}
/>
<InputPrependButton
buttonProps={{
onClick: handleCreditNumberChange,
icon: <Icon icon={'settings-18'} />,
}}
tooltip={true}
tooltipProps={{
content: (
<T id={'setting_your_auto_generated_credit_note_number'} />
),
position: Position.BOTTOM_LEFT,
}}
/>
</ControlGroup>
</FormGroup>
)}
</Field>
@@ -121,5 +183,11 @@ function CreditNoteFormHeaderFields() {
</div>
);
}
export default CreditNoteFormHeaderFields;
export default compose(
withDialogActions,
withSettings(({ creditNoteSettings }) => ({
creditAutoIncrement: creditNoteSettings?.autoIncrement,
creditNextNumber: creditNoteSettings?.nextNumber,
creditNumberPrefix: creditNoteSettings?.numberPrefix,
})),
)(CreditNoteFormHeaderFields);

View File

@@ -10,6 +10,7 @@ import {
useEditCreditNote,
useItems,
useCustomers,
useSettingsCreditNotes,
} from 'hooks/query';
const CreditNoteFormContext = React.createContext();
@@ -40,6 +41,9 @@ function CreditNoteFormProvider({ creditNoteId, ...props }) {
},
);
// Handle fetching settings.
useSettingsCreditNotes();
// Create and edit credit note mutations.
const { mutateAsync: createCreditNoteMutate } = useCreateCreditNote();
const { mutateAsync: editCreditNoteMutate } = useEditCreditNote();

View File

@@ -6,8 +6,10 @@ import {
defaultFastFieldShouldUpdate,
transformToForm,
repeatValue,
transactionNumber,
orderingLinesIndexes,
} from 'utils';
import { useFormikContext } from 'formik';
import {
updateItemsEntriesTotal,
@@ -115,3 +117,15 @@ export const entriesFieldShouldUpdate = (newProps, oldProps) => {
defaultFastFieldShouldUpdate(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]);
};

View File

@@ -65,7 +65,7 @@ function CreditNotesActionsBar({
// Handle table row size change.
const handleTableRowSizeChange = (size) => {
addSetting('creditNotes', 'tableSize', size);
addSetting('creditNote', 'tableSize', size);
};
return (