mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-19 14:20:31 +00:00
feat: add Auto increment in credit note number.
This commit is contained in:
@@ -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);
|
||||
@@ -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 };
|
||||
40
src/containers/Dialogs/CreditNoteNumberDialog/index.js
Normal file
40
src/containers/Dialogs/CreditNoteNumberDialog/index.js
Normal 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);
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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]);
|
||||
};
|
||||
|
||||
@@ -65,7 +65,7 @@ function CreditNotesActionsBar({
|
||||
|
||||
// Handle table row size change.
|
||||
const handleTableRowSizeChange = (size) => {
|
||||
addSetting('creditNotes', 'tableSize', size);
|
||||
addSetting('creditNote', 'tableSize', size);
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user