diff --git a/src/containers/Dialogs/VendorCreditNumberDialog/VendorCreditNumberDialogContent.js b/src/containers/Dialogs/VendorCreditNumberDialog/VendorCreditNumberDialogContent.js new file mode 100644 index 000000000..b9dcecc61 --- /dev/null +++ b/src/containers/Dialogs/VendorCreditNumberDialog/VendorCreditNumberDialogContent.js @@ -0,0 +1,102 @@ +import React from 'react'; +import intl from 'react-intl-universal'; +import { useSaveSettings } from 'hooks/query'; + +import { VendorCreditNumberDilaogProvider } from './VendorCreditNumberDilaogProvider'; +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'; + +/** + * Vendor credit number dialog + */ +function VendorCreditNumberDialogContent({ + // #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('vendor-credit-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, 'vendor_credit'); + + // Save the settings. + saveSettings({ options }).then(handleSuccess).catch(handleErrors); + }; + + // Handle the dialog close. + const handleClose = () => { + closeDialog('vendor-credit-form'); + }; + // Handle form change. + const handleChange = (values) => { + setReferenceFormValues(values); + }; + + // Description. + const description = + referenceFormValues?.incrementMode === 'auto' + ? intl.get('vendor_credit.auto_increment.auto') + : intl.get('vendor_credit.auto_increment.manually'); + + return ( + + + + ); +} + +export default compose( + withDialogActions, + withSettingsActions, + withSettings(({ vendorsCreditNoteSetting }) => ({ + autoIncrement: vendorsCreditNoteSetting?.autoIncrement, + nextNumber: vendorsCreditNoteSetting?.nextNumber, + numberPrefix: vendorsCreditNoteSetting?.numberPrefix, + })), +)(VendorCreditNumberDialogContent); diff --git a/src/containers/Dialogs/VendorCreditNumberDialog/VendorCreditNumberDilaogProvider.js b/src/containers/Dialogs/VendorCreditNumberDialog/VendorCreditNumberDilaogProvider.js new file mode 100644 index 000000000..0d285b6fc --- /dev/null +++ b/src/containers/Dialogs/VendorCreditNumberDialog/VendorCreditNumberDilaogProvider.js @@ -0,0 +1,28 @@ +import React from 'react'; +import { DialogContent } from 'components'; +import { useSettingsVendorCredits } from 'hooks/query'; + +const VendorCreditNumberDialogContext = React.createContext(); + +/** + * Vendor credit number dialog provider + */ +function VendorCreditNumberDilaogProvider({ query, ...props }) { + const { isLoading: isSettingsLoading } = useSettingsVendorCredits(); + + // Provider payload. + const provider = { + isSettingsLoading, + }; + + return ( + + + + ); +} + +const useVendorCreditNumberDialogContext = () => + React.useContext(VendorCreditNumberDialogContext); + +export { VendorCreditNumberDilaogProvider, useVendorCreditNumberDialogContext }; diff --git a/src/containers/Dialogs/VendorCreditNumberDialog/index.js b/src/containers/Dialogs/VendorCreditNumberDialog/index.js new file mode 100644 index 000000000..e92fdf702 --- /dev/null +++ b/src/containers/Dialogs/VendorCreditNumberDialog/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 VendorCreditNumberDialogContent = React.lazy(() => + import('./VendorCreditNumberDialogContent'), +); + +/** + * Vendor Credit number dialog. + */ +function VendorCreditNumberDialog({ + dialogName, + payload: { initialFormValues }, + isOpen, + onConfirm, +}) { + const handleConfirm = (values) => { + saveInvoke(onConfirm, values); + }; + + return ( + } + name={dialogName} + autoFocus={true} + canEscapeKeyClose={true} + isOpen={isOpen} + > + + + + + ); +} +export default compose(withDialogRedux())(VendorCreditNumberDialog); diff --git a/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteForm.js b/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteForm.js index e48b31edf..05fed2f74 100644 --- a/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteForm.js +++ b/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteForm.js @@ -15,23 +15,31 @@ import VendorCreditNoteFormHeader from './VendorCreditNoteFormHeader'; import VendorCreditNoteItemsEntriesEditor from './VendorCreditNoteItemsEntriesEditor'; import VendorCreditNoteFormFooter from './VendorCreditNoteFormFooter'; import VendorCreditNoteFloatingActions from './VendorCreditNoteFloatingActions'; +import VendorCreditNoteFormDialogs from './VendorCreditNoteFormDialogs'; + import { useVendorCreditNoteFormContext } from './VendorCreditNoteFormProvider'; import { AppToaster } from 'components'; - -import { compose, safeSumBy } from 'utils'; +import { compose, safeSumBy, transactionNumber } from 'utils'; import { defaultVendorsCreditNote, filterNonZeroEntries, transformToEditForm, transformFormValuesToRequest, } from './utils'; + +import withSettings from 'containers/Settings/withSettings'; import withCurrentOrganization from 'containers/Organization/withCurrentOrganization'; /** * Vendor Credit note form. */ function VendorCreditNoteForm({ + // #withSettings + vendorcreditAutoIncrement, + vendorcreditNumberPrefix, + vendorcreditNextNumber, + // #withCurrentOrganization organization: { base_currency }, }) { @@ -46,6 +54,12 @@ function VendorCreditNoteForm({ editVendorCreditMutate, } = useVendorCreditNoteFormContext(); + // Credit number. + const vendorCreditNumber = transactionNumber( + vendorcreditNumberPrefix, + vendorcreditNextNumber, + ); + // Initial values. const initialValues = React.useMemo( () => ({ @@ -55,6 +69,9 @@ function VendorCreditNoteForm({ } : { ...defaultVendorsCreditNote, + ...(vendorcreditAutoIncrement && { + vendor_credit_number: vendorCreditNumber, + }), }), }), [vendorCredit, base_currency], @@ -134,12 +151,19 @@ function VendorCreditNoteForm({ - + ); } -export default compose(withCurrentOrganization())(VendorCreditNoteForm); +export default compose( + withSettings(({ vendorsCreditNoteSetting }) => ({ + vendorcreditAutoIncrement: vendorsCreditNoteSetting?.autoIncrement, + vendorcreditNextNumber: vendorsCreditNoteSetting?.nextNumber, + vendorcreditNumberPrefix: vendorsCreditNoteSetting?.numberPrefix, + })), + withCurrentOrganization(), +)(VendorCreditNoteForm); diff --git a/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFormDialogs.js b/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFormDialogs.js new file mode 100644 index 000000000..5d5d69df2 --- /dev/null +++ b/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFormDialogs.js @@ -0,0 +1,27 @@ +import React from 'react'; +import VendorCreditNumberDialog from '../../../Dialogs/VendorCreditNumberDialog'; +import { useFormikContext } from 'formik'; + +/** + * Vendor credit form dialog. + */ +export default function VendorCreditNoteFormDialogs() { + // Update the form once the vendor credit number form submit confirm. + const handleVendorCreditNumberFormConfirm = ({ + incrementNumber, + manually, + }) => { + setFieldValue('vendor_credit_number', incrementNumber || ''); + setFieldValue('vendor_credit_no_manually', manually); + }; + const { setFieldValue } = useFormikContext(); + + return ( + + + + ); +} diff --git a/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFormHeaderFields.js b/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFormHeaderFields.js index 120d59b5d..e93db9c63 100644 --- a/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFormHeaderFields.js +++ b/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFormHeaderFields.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 { vendorsFieldShouldUpdate } from './utils'; +import { + vendorsFieldShouldUpdate, + useObserveVendorCreditNoSettings, +} from './utils'; import { useVendorCreditNoteFormContext } from './VendorCreditNoteFormProvider'; @@ -22,13 +31,48 @@ import { handleDateChange, } from 'utils'; +import withSettings from 'containers/Settings/withSettings'; +import withDialogActions from 'containers/Dialog/withDialogActions'; + /** * Vendor Credit note form header fields. */ +function VendorCreditNoteFormHeaderFields({ + // #withDialogActions + openDialog, -function VendorCreditNoteFormHeaderFields() { - // Credit note form context. + // #withSettings + vendorcreditAutoIncrement, + vendorcreditNumberPrefix, + vendorcreditNextNumber, +}) { + // Vendor Credit form context. const { vendors } = useVendorCreditNoteFormContext(); + + // Handle vendor credit number changing. + const handleVendorCreditNumberChange = () => { + openDialog('vendor-credit-form'); + }; + + // Handle vendor credit no. field blur. + const handleVendorCreditNoBlur = (form, field) => (event) => { + const newValue = event.target.value; + + if (field.value !== newValue && vendorcreditAutoIncrement) { + openDialog('vendor-credit-form', { + initialFormValues: { + manualTransactionNo: newValue, + incrementMode: 'manual-transaction', + }, + }); + } + }; + // Syncs vendor credit number settings with form. + useObserveVendorCreditNoSettings( + vendorcreditNumberPrefix, + vendorcreditNextNumber, + ); + return (
{/* ----------- Vendor name ----------- */} @@ -94,7 +138,7 @@ function VendorCreditNoteFormHeaderFields() { {/* ----------- Vendor Credit No # ----------- */} - {({ field, meta: { error, touched } }) => ( + {({ form, field, meta: { error, touched } }) => ( } inline={true} @@ -102,12 +146,34 @@ function VendorCreditNoteFormHeaderFields() { intent={inputIntent({ error, touched })} helperText={} > - + + + , + }} + tooltip={true} + tooltipProps={{ + content: ( + + ), + position: Position.BOTTOM_LEFT, + }} + /> + )} {/* ----------- Reference ----------- */} - {/* + {({ field, meta: { error, touched } }) => ( } @@ -119,9 +185,16 @@ function VendorCreditNoteFormHeaderFields() { )} - */} +
); } -export default VendorCreditNoteFormHeaderFields; +export default compose( + withDialogActions, + withSettings(({ vendorsCreditNoteSetting }) => ({ + vendorcreditAutoIncrement: vendorsCreditNoteSetting?.autoIncrement, + vendorcreditNextNumber: vendorsCreditNoteSetting?.nextNumber, + vendorcreditNumberPrefix: vendorsCreditNoteSetting?.numberPrefix, + })), +)(VendorCreditNoteFormHeaderFields); diff --git a/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFormProvider.js b/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFormProvider.js index b3e74703b..184c68772 100644 --- a/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFormProvider.js +++ b/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFormProvider.js @@ -7,6 +7,7 @@ import { useVendorCredit, useItems, useVendors, + useSettingsVendorCredits, } from 'hooks/query'; const VendorCreditNoteFormContext = React.createContext(); @@ -23,6 +24,9 @@ function VendorCreditNoteFormProvider({ vendorCreditId, ...props }) { page_size: 10000, }); + // Handle fetching settings. + useSettingsVendorCredits(); + // Handle fetch vendors data table or list const { data: { vendors }, diff --git a/src/containers/Purchases/CreditNotes/CreditNoteForm/utils.js b/src/containers/Purchases/CreditNotes/CreditNoteForm/utils.js index 114dc1580..4e2232e70 100644 --- a/src/containers/Purchases/CreditNotes/CreditNoteForm/utils.js +++ b/src/containers/Purchases/CreditNotes/CreditNoteForm/utils.js @@ -6,12 +6,14 @@ import { defaultFastFieldShouldUpdate, transformToForm, repeatValue, + transactionNumber, orderingLinesIndexes, } from 'utils'; import { updateItemsEntriesTotal, ensureEntriesHaveEmptyLine, } from 'containers/Entries/utils'; +import { useFormikContext } from 'formik'; export const MIN_LINES_NUMBER = 4; @@ -30,6 +32,7 @@ export const defaultCreditNoteEntry = { export const defaultVendorsCreditNote = { vendor_id: '', vendor_credit_number: '', + vendor_credit_no_manually: false, vendor_credit_date: moment(new Date()).format('YYYY-MM-DD'), // reference_no: '', note: '', @@ -112,3 +115,15 @@ export const entriesFieldShouldUpdate = (newProps, oldProps) => { defaultFastFieldShouldUpdate(newProps, oldProps) ); }; + +/** + * Syncs invoice no. settings with form. + */ + export const useObserveVendorCreditNoSettings = (prefix, nextNumber) => { + const { setFieldValue } = useFormikContext(); + + React.useEffect(() => { + const creditNo = transactionNumber(prefix, nextNumber); + setFieldValue('vendor_credit_number', creditNo); + }, [setFieldValue, prefix, nextNumber]); +}; diff --git a/src/containers/Purchases/CreditNotes/CreditNotesLanding/VendorsCreditNoteActionsBar.js b/src/containers/Purchases/CreditNotes/CreditNotesLanding/VendorsCreditNoteActionsBar.js index e52077150..681b5da68 100644 --- a/src/containers/Purchases/CreditNotes/CreditNotesLanding/VendorsCreditNoteActionsBar.js +++ b/src/containers/Purchases/CreditNotes/CreditNotesLanding/VendorsCreditNoteActionsBar.js @@ -66,7 +66,7 @@ function VendorsCreditNoteActionsBar({ // Handle table row size change. const handleTableRowSizeChange = (size) => { - addSetting('vendorCredits', 'tableSize', size); + addSetting('vendorCredit', 'tableSize', size); }; return ( diff --git a/src/containers/Settings/withSettings.js b/src/containers/Settings/withSettings.js index 6acdcb53b..867e56dc7 100644 --- a/src/containers/Settings/withSettings.js +++ b/src/containers/Settings/withSettings.js @@ -19,8 +19,8 @@ export default (mapState) => { cashflowSettings: state.settings.data.cashflowAccounts, cashflowTransactionsSettings: state.settings.data.cashflowTransactions, cashflowSetting: state.settings.data.cashflow, - creditNoteSettings: state.settings.data.creditNotes, - vendorsCreditNoteSetting: state.settings.data.vendorCredits, + creditNoteSettings: state.settings.data.creditNote, + vendorsCreditNoteSetting: state.settings.data.vendorCredit, }; return mapState ? mapState(mapped, state, props) : mapped; }; diff --git a/src/hooks/query/settings.js b/src/hooks/query/settings.js index b7c70b335..4575307aa 100644 --- a/src/hooks/query/settings.js +++ b/src/hooks/query/settings.js @@ -123,6 +123,27 @@ export function useSettingCashFlow(props) { ); } +/** + * Retrieve credit notes settings. + */ +export function useSettingsCreditNotes(props) { + return useSettingsQuery( + [t.SETTING, t.SETTING_CREDIT_NOTES], + { group: 'credit_note' }, + props, + ); +} +/** + * Retrieve vendor credit settings. + */ +export function useSettingsVendorCredits(props) { + return useSettingsQuery( + [t.SETTING, t.SETTING_VENDOR_CREDITS], + { group: 'vendor_credit' }, + props, + ); +} + /** * Retrieve SMS Notifications settings. */ diff --git a/src/hooks/query/types.js b/src/hooks/query/types.js index a32093703..374c6540c 100644 --- a/src/hooks/query/types.js +++ b/src/hooks/query/types.js @@ -130,6 +130,8 @@ const SETTING = { SETTING_SMS_NOTIFICATION: 'SETTING_SMS_NOTIFICATION', SETTING_SMS_NOTIFICATIONS: 'SETTING_SMS_NOTIFICATIONS', SETTING_EDIT_SMS_NOTIFICATION: 'SETTING_EDIT_SMS_NOTIFICATION', + SETTING_CREDIT_NOTES: 'SETTING_CREDIT_NOTES', + SETTING_VENDOR_CREDITS: 'SETTING_VENDOR_CREDITS', }; const ORGANIZATIONS = { diff --git a/src/hooks/query/vendorCredit.js b/src/hooks/query/vendorCredit.js index f4867aceb..272d30ab7 100644 --- a/src/hooks/query/vendorCredit.js +++ b/src/hooks/query/vendorCredit.js @@ -21,6 +21,9 @@ const commonInvalidateQueries = (queryClient) => { queryClient.invalidateQueries(t.ACCOUNTS); queryClient.invalidateQueries(t.ACCOUNT); + // Invalidate settings. + queryClient.invalidateQueries([t.SETTING, t.SETTING_VENDOR_CREDITS]); + // Invalidate financial reports. queryClient.invalidateQueries(t.FINANCIAL_REPORT); }; diff --git a/src/lang/en/index.json b/src/lang/en/index.json index 17677d624..6c2ef8dcd 100644 --- a/src/lang/en/index.json +++ b/src/lang/en/index.json @@ -1516,5 +1516,13 @@ "vendor_credits.success_message": "The vendor credit has been created successfully", "vendor_credits.edit_success_message": "The vendor credit has been edited successfully.", "vendor_credits.alert.success_message": "The given vendor credit has been deleted successfully.", - "vendor_credits.note.once_delete_this_vendor_credit_note": "Once you delete this vendor credit , you won't be able to restore it later. Are you sure you want to delete this vendor credit ?" + "vendor_credits.note.once_delete_this_vendor_credit_note": "Once you delete this vendor credit , you won't be able to restore it later. Are you sure you want to delete this vendor credit ?", + "credit_note_number_settings": "Credit Note Number Settings", + "credit_note.auto_increment.auto": "Your credit note numbers are set on auto-increment mode. Are you sure changing this setting?", + "credit_note.auto_increment.manually": "Your credit note numbers are set on manual mode. Are you sure chaning this settings?", + "setting_your_auto_generated_credit_note_number": "Setting your auto-generated credit note number", + "vendor_credit_number_settings": "Vendor Credit Number Settings", + "vendor_credit.auto_increment.auto": "Your vendor credit numbers are set on auto-increment mode. Are you sure changing this setting?", + "vendor_credit.auto_increment.manually": "Your vendor credit numbers are set on manual mode. Are you sure chaning this settings?", + "setting_your_auto_generated_vendor_credit_number": "Setting your auto-generated vendor credit number" } \ No newline at end of file diff --git a/src/store/settings/settings.reducer.js b/src/store/settings/settings.reducer.js index 2498a04bd..853ab0589 100644 --- a/src/store/settings/settings.reducer.js +++ b/src/store/settings/settings.reducer.js @@ -52,10 +52,10 @@ const initialState = { cashflowTransactions: { tableSize: 'medium', }, - creditNotes: { + creditNote: { tableSize: 'medium', }, - vendorCredits: { + vendorCredit: { tableSize: 'medium', }, },