diff --git a/src/containers/Dialogs/CreditNoteNumberDialog/CreditNoteNumberDialogContent.js b/src/containers/Dialogs/CreditNoteNumberDialog/CreditNoteNumberDialogContent.js
new file mode 100644
index 000000000..ff1d56f16
--- /dev/null
+++ b/src/containers/Dialogs/CreditNoteNumberDialog/CreditNoteNumberDialogContent.js
@@ -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 (
+
+
+
+ );
+}
+
+export default compose(
+ withDialogActions,
+ withSettingsActions,
+ withSettings(({ creditNoteSettings }) => ({
+ autoIncrement: creditNoteSettings?.autoIncrement,
+ nextNumber: creditNoteSettings?.nextNumber,
+ numberPrefix: creditNoteSettings?.numberPrefix,
+ })),
+)(CreditNoteNumberDialogContent);
diff --git a/src/containers/Dialogs/CreditNoteNumberDialog/CreditNoteNumberDialogProvider.js b/src/containers/Dialogs/CreditNoteNumberDialog/CreditNoteNumberDialogProvider.js
new file mode 100644
index 000000000..94daf467f
--- /dev/null
+++ b/src/containers/Dialogs/CreditNoteNumberDialog/CreditNoteNumberDialogProvider.js
@@ -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 (
+
+
+
+ );
+}
+
+const useCreditNoteNumberDialogContext = () =>
+ React.useContext(CreditNoteNumberDialogContext);
+
+export { CreditNoteNumberDialogProvider, useCreditNoteNumberDialogContext };
diff --git a/src/containers/Dialogs/CreditNoteNumberDialog/index.js b/src/containers/Dialogs/CreditNoteNumberDialog/index.js
new file mode 100644
index 000000000..c1786c324
--- /dev/null
+++ b/src/containers/Dialogs/CreditNoteNumberDialog/index.js
@@ -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 (
+ }
+ name={dialogName}
+ autoFocus={true}
+ canEscapeKeyClose={true}
+ isOpen={isOpen}
+ >
+
+
+
+
+ );
+}
+export default compose(withDialogRedux())(CreditNoteNumberDialog);
diff --git a/src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteForm.js b/src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteForm.js
index 9fe97db87..b75e6130d 100644
--- a/src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteForm.js
+++ b/src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteForm.js
@@ -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({
+
);
}
-
-export default compose(withCurrentOrganization())(CreditNoteForm);
+export default compose(
+ withSettings(({ creditNoteSettings }) => ({
+ creditAutoIncrement: creditNoteSettings?.autoIncrement,
+ creditNextNumber: creditNoteSettings?.nextNumber,
+ creditNumberPrefix: creditNoteSettings?.numberPrefix,
+ })),
+ withCurrentOrganization(),
+)(CreditNoteForm);
diff --git a/src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteFormDialogs.js b/src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteFormDialogs.js
new file mode 100644
index 000000000..bfb2d99c7
--- /dev/null
+++ b/src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteFormDialogs.js
@@ -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 (
+
+
+
+ );
+}
diff --git a/src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteFormHeaderFields.js b/src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteFormHeaderFields.js
index d17d28e8c..00ac441d2 100644
--- a/src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteFormHeaderFields.js
+++ b/src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteFormHeaderFields.js
@@ -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 (
{/* ----------- Customer name ----------- */}
@@ -96,11 +135,34 @@ function CreditNoteFormHeaderFields() {
label={}
labelInfo={}
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={}
>
-
+
+
+ ,
+ }}
+ tooltip={true}
+ tooltipProps={{
+ content: (
+
+ ),
+ position: Position.BOTTOM_LEFT,
+ }}
+ />
+
)}
@@ -121,5 +183,11 @@ function CreditNoteFormHeaderFields() {
);
}
-
-export default CreditNoteFormHeaderFields;
+export default compose(
+ withDialogActions,
+ withSettings(({ creditNoteSettings }) => ({
+ creditAutoIncrement: creditNoteSettings?.autoIncrement,
+ creditNextNumber: creditNoteSettings?.nextNumber,
+ creditNumberPrefix: creditNoteSettings?.numberPrefix,
+ })),
+)(CreditNoteFormHeaderFields);
diff --git a/src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteFormProvider.js b/src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteFormProvider.js
index 0c33c8868..210875d51 100644
--- a/src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteFormProvider.js
+++ b/src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteFormProvider.js
@@ -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();
diff --git a/src/containers/Sales/CreditNotes/CreditNoteForm/utils.js b/src/containers/Sales/CreditNotes/CreditNoteForm/utils.js
index d2992cf9d..807029d9f 100644
--- a/src/containers/Sales/CreditNotes/CreditNoteForm/utils.js
+++ b/src/containers/Sales/CreditNotes/CreditNoteForm/utils.js
@@ -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]);
+};
diff --git a/src/containers/Sales/CreditNotes/CreditNotesLanding/CreditNotesActionsBar.js b/src/containers/Sales/CreditNotes/CreditNotesLanding/CreditNotesActionsBar.js
index be363cfc4..cb1b864c6 100644
--- a/src/containers/Sales/CreditNotes/CreditNotesLanding/CreditNotesActionsBar.js
+++ b/src/containers/Sales/CreditNotes/CreditNotesLanding/CreditNotesActionsBar.js
@@ -65,7 +65,7 @@ function CreditNotesActionsBar({
// Handle table row size change.
const handleTableRowSizeChange = (size) => {
- addSetting('creditNotes', 'tableSize', size);
+ addSetting('creditNote', 'tableSize', size);
};
return (
diff --git a/src/hooks/query/creditNote.js b/src/hooks/query/creditNote.js
index e107005fd..3095f53c7 100644
--- a/src/hooks/query/creditNote.js
+++ b/src/hooks/query/creditNote.js
@@ -21,6 +21,9 @@ const commonInvalidateQueries = (queryClient) => {
queryClient.invalidateQueries(t.ACCOUNTS);
queryClient.invalidateQueries(t.ACCOUNT);
+ // Invalidate settings.
+ queryClient.invalidateQueries([t.SETTING, t.SETTING_CREDIT_NOTES]);
+
// Invalidate financial reports.
queryClient.invalidateQueries(t.FINANCIAL_REPORT);
};
@@ -95,8 +98,6 @@ const transformInvoices = (res) => ({
* Retrieve credit notes list with pagination meta.
*/
export function useCreditNotes(query, props) {
-
-
return useRequestQuery(
[t.CREDIT_NOTES, query],
{ method: 'get', url: 'sales/credit_notes', params: query },