From 9c00da3613022993afd13a3421f770943587fff3 Mon Sep 17 00:00:00 2001 From: elforjani3 Date: Mon, 11 Jan 2021 09:42:01 +0200 Subject: [PATCH] feat : inventory adjustments. --- client/src/common/adjustmentType.js | 4 + client/src/components/DialogsContainer.js | 2 + client/src/config/sidebarMenu.js | 4 +- .../Accounting/ManualJournalActionsBar.js | 32 +-- .../DecrementAdjustmentFields.js | 58 +++++ .../IncrementAdjustmentFields.js | 72 +++++++ .../InventoryAdjustmentForm.schema.js | 27 +++ .../InventoryAdjustmentFormDialogContent.js | 103 +++++++++ .../InventoryAdjustmentFormDialogFields.js | 200 ++++++++++++++++++ .../InventoryAdjustmentFormDialog/index.js | 37 ++++ .../Items/InventoryAdjustmentDataTable.js | 176 +++++++++++++++ .../Items/InventoryAdjustmentList.js | 81 +++++++ client/src/containers/Items/ItemsDataTable.js | 17 ++ .../Items/withInventoryAdjustmentActions.js | 24 +++ .../Items/withInventoryAdjustments.js | 4 + client/src/lang/en/index.js | 14 ++ client/src/routes/dashboard.js | 12 +- .../inventoryAdjustment.actions.js | 86 ++++++++ .../inventoryAdjustment.reducer.js | 73 +++++++ .../inventoryAdjustment.selector.js | 7 + .../inventoryAdjustment.type.js | 14 ++ client/src/store/reducers.js | 2 + client/src/store/types.js | 2 + 23 files changed, 1031 insertions(+), 20 deletions(-) create mode 100644 client/src/common/adjustmentType.js create mode 100644 client/src/containers/Dialogs/InventoryAdjustmentFormDialog/DecrementAdjustmentFields.js create mode 100644 client/src/containers/Dialogs/InventoryAdjustmentFormDialog/IncrementAdjustmentFields.js create mode 100644 client/src/containers/Dialogs/InventoryAdjustmentFormDialog/InventoryAdjustmentForm.schema.js create mode 100644 client/src/containers/Dialogs/InventoryAdjustmentFormDialog/InventoryAdjustmentFormDialogContent.js create mode 100644 client/src/containers/Dialogs/InventoryAdjustmentFormDialog/InventoryAdjustmentFormDialogFields.js create mode 100644 client/src/containers/Dialogs/InventoryAdjustmentFormDialog/index.js create mode 100644 client/src/containers/Items/InventoryAdjustmentDataTable.js create mode 100644 client/src/containers/Items/InventoryAdjustmentList.js create mode 100644 client/src/containers/Items/withInventoryAdjustmentActions.js create mode 100644 client/src/containers/Items/withInventoryAdjustments.js create mode 100644 client/src/store/inventoryAdjustments/inventoryAdjustment.actions.js create mode 100644 client/src/store/inventoryAdjustments/inventoryAdjustment.reducer.js create mode 100644 client/src/store/inventoryAdjustments/inventoryAdjustment.selector.js create mode 100644 client/src/store/inventoryAdjustments/inventoryAdjustment.type.js diff --git a/client/src/common/adjustmentType.js b/client/src/common/adjustmentType.js new file mode 100644 index 000000000..f2239f6f8 --- /dev/null +++ b/client/src/common/adjustmentType.js @@ -0,0 +1,4 @@ +export default [ + { name: 'Decrement', value: 'decrement' }, + { name: 'Increment', value: 'increment' }, +] \ No newline at end of file diff --git a/client/src/components/DialogsContainer.js b/client/src/components/DialogsContainer.js index de3b62a59..6277ace96 100644 --- a/client/src/components/DialogsContainer.js +++ b/client/src/components/DialogsContainer.js @@ -12,6 +12,7 @@ import PaymentReceiveNumberDialog from 'containers/Dialogs/PaymentReceiveNumberD import EstimateNumberDialog from 'containers/Dialogs/EstimateNumberDialog'; import ReceiptNumberDialog from 'containers/Dialogs/ReceiptNumberDialog'; import InvoiceNumberDialog from 'containers/Dialogs/InvoiceNumberDialog'; +import InventoryAdjustmentDialog from 'containers/Dialogs/InventoryAdjustmentFormDialog'; export default function DialogsContainer() { return ( @@ -27,6 +28,7 @@ export default function DialogsContainer() { + ); } diff --git a/client/src/config/sidebarMenu.js b/client/src/config/sidebarMenu.js index a25c58942..d53d52394 100644 --- a/client/src/config/sidebarMenu.js +++ b/client/src/config/sidebarMenu.js @@ -25,8 +25,8 @@ export default [ href: '/items', }, { - text: , - href: '/items/new', + text: , + href: '/inventory-adjustments', }, { text: , diff --git a/client/src/containers/Accounting/ManualJournalActionsBar.js b/client/src/containers/Accounting/ManualJournalActionsBar.js index ca0070fa7..f83059928 100644 --- a/client/src/containers/Accounting/ManualJournalActionsBar.js +++ b/client/src/containers/Accounting/ManualJournalActionsBar.js @@ -54,21 +54,21 @@ function ManualJournalActionsBar({ history.push('/make-journal-entry'); }, [history]); - const filterDropdown = FilterDropdown({ - fields: resourceFields, - initialCondition: { - fieldKey: 'journal_number', - compatator: 'contains', - value: '', - }, - onFilterChange: (filterConditions) => { - setFilterCount(filterConditions.length || 0); - addManualJournalsTableQueries({ - filter_roles: filterConditions || '', - }); - onFilterChanged && onFilterChanged(filterConditions); - }, - }); + // const filterDropdown = FilterDropdown({ + // fields: resourceFields, + // initialCondition: { + // fieldKey: 'journal_number', + // compatator: 'contains', + // value: '', + // }, + // onFilterChange: (filterConditions) => { + // setFilterCount(filterConditions.length || 0); + // addManualJournalsTableQueries({ + // filter_roles: filterConditions || '', + // }); + // onFilterChanged && onFilterChanged(filterConditions); + // }, + // }); const hasSelectedRows = useMemo(() => selectedRows.length > 0, [ selectedRows, ]); @@ -103,7 +103,7 @@ function ManualJournalActionsBar({ /> diff --git a/client/src/containers/Dialogs/InventoryAdjustmentFormDialog/DecrementAdjustmentFields.js b/client/src/containers/Dialogs/InventoryAdjustmentFormDialog/DecrementAdjustmentFields.js new file mode 100644 index 000000000..85c3c0f2c --- /dev/null +++ b/client/src/containers/Dialogs/InventoryAdjustmentFormDialog/DecrementAdjustmentFields.js @@ -0,0 +1,58 @@ +import React from 'react'; +import { FastField, ErrorMessage } from 'formik'; +import { FormGroup, InputGroup } from '@blueprintjs/core'; +import { Row, Col, FieldRequiredHint } from 'components'; +import { inputIntent } from 'utils'; +import { FormattedMessage as T } from 'react-intl'; + +function DecrementAdjustmentFields() { + return ( + + {/*------------ Quantity on hand -----------*/} + + + {({ field, meta: { error, touched } }) => ( + } + intent={inputIntent({ error, touched })} + helperText={} + > + + + )} + + + {/*------------ Decrement -----------*/} + + + {({ field, meta: { error, touched } }) => ( + } + intent={inputIntent({ error, touched })} + helperText={} + fill={true} + > + + + )} + + + {/*------------ New quantity -----------*/} + + + {({ field, meta: { error, touched } }) => ( + } + intent={inputIntent({ error, touched })} + helperText={} + > + + + )} + + + + ); +} + +export default DecrementAdjustmentFields; diff --git a/client/src/containers/Dialogs/InventoryAdjustmentFormDialog/IncrementAdjustmentFields.js b/client/src/containers/Dialogs/InventoryAdjustmentFormDialog/IncrementAdjustmentFields.js new file mode 100644 index 000000000..4a667e94d --- /dev/null +++ b/client/src/containers/Dialogs/InventoryAdjustmentFormDialog/IncrementAdjustmentFields.js @@ -0,0 +1,72 @@ +import React from 'react'; +import { FastField, ErrorMessage } from 'formik'; +import { FormGroup, InputGroup, Intent } from '@blueprintjs/core'; +import { Row, Col, FieldRequiredHint } from 'components'; +import { inputIntent } from 'utils'; +import { FormattedMessage as T } from 'react-intl'; + +function IncrementAdjustmentFields() { + return ( + + {/*------------ Quantity on hand -----------*/} + + + {({ field, meta: { error, touched } }) => ( + } + intent={inputIntent({ error, touched })} + helperText={} + > + + + )} + + + {/*------------ Increment -----------*/} + + + {({ field, meta: { error, touched } }) => ( + } + intent={inputIntent({ error, touched })} + helperText={} + fill={true} + > + + + )} + + + {/*------------ Cost -----------*/} + + + {({ field, meta: { error, touched } }) => ( + } + intent={inputIntent({ error, touched })} + helperText={} + > + + + )} + + + {/*------------ New quantity -----------*/} + + + {({ field, meta: { error, touched } }) => ( + } + intent={inputIntent({ error, touched })} + helperText={} + > + + + )} + + + + ); +} + +export default IncrementAdjustmentFields; diff --git a/client/src/containers/Dialogs/InventoryAdjustmentFormDialog/InventoryAdjustmentForm.schema.js b/client/src/containers/Dialogs/InventoryAdjustmentFormDialog/InventoryAdjustmentForm.schema.js new file mode 100644 index 000000000..7b0048f2d --- /dev/null +++ b/client/src/containers/Dialogs/InventoryAdjustmentFormDialog/InventoryAdjustmentForm.schema.js @@ -0,0 +1,27 @@ +import * as Yup from 'yup'; +import { formatMessage } from 'services/intl'; +import { DATATYPES_LENGTH } from 'common/dataTypes'; + +const Schema = Yup.object().shape({ + date: Yup.date() + .required() + .label(formatMessage({ id: 'date' })), + type: Yup.number().required(), + adjustment_account_id: Yup.number().required(), + reason: Yup.string() + .required() + .label(formatMessage({ id: 'reason' })), + quantity: Yup.number().when(['type'], { + is: (type) => type, + then: Yup.number().required(), + }), + cost: Yup.number().when(['type'], { + is: (type) => type, + then: Yup.number().required(), + }), + reference_no: Yup.string(), + new_quantity: Yup.number(), + description: Yup.string().min(3).max(DATATYPES_LENGTH.TEXT).nullable().trim(), +}); + +export const CreateInventoryAdjustmentFormSchema = Schema; diff --git a/client/src/containers/Dialogs/InventoryAdjustmentFormDialog/InventoryAdjustmentFormDialogContent.js b/client/src/containers/Dialogs/InventoryAdjustmentFormDialog/InventoryAdjustmentFormDialogContent.js new file mode 100644 index 000000000..4887fbc00 --- /dev/null +++ b/client/src/containers/Dialogs/InventoryAdjustmentFormDialog/InventoryAdjustmentFormDialogContent.js @@ -0,0 +1,103 @@ +import React, { useCallback, useMemo } from 'react'; +import { Intent } from '@blueprintjs/core'; +import { Formik } from 'formik'; +import { FormattedMessage as T, useIntl } from 'react-intl'; +import { useQuery, queryCache } from 'react-query'; +import moment from 'moment'; +import { omit } from 'lodash'; + +import { + AppToaster, + DialogContent, + Row, + Col, + ListSelect, + IF, +} from 'components'; +import { CreateInventoryAdjustmentFormSchema } from './InventoryAdjustmentForm.schema'; +import InventoryAdjustmentFormDialogFields from './InventoryAdjustmentFormDialogFields'; + +import withDialogActions from 'containers/Dialog/withDialogActions'; + +import { compose } from 'utils'; + +const defaultInitialValues = { + date: moment(new Date()).format('YYYY-MM-DD'), + type: 'decrement', + adjustment_account_id: '', + reason: '', + reference_no: '', + description: '', +}; + +/** + * Inventory adjustment form dialog content. + */ +function InventoryAdjustmentFormDialogContent({ + // #withDialogActions + closeDialog, + + // #withAccountsActions + requestFetchAccounts, + + // #ownProp + dialogName, + action, +}) { + const { formatMessage } = useIntl(); + + // Fetches accounts list. + const fetchAccountsList = useQuery('accounts-list', () => + requestFetchAccounts(), + ); + + const initialValues = useMemo( + () => ({ + ...defaultInitialValues, + }), + [], + ); + + // Handles the form submit. + const handleFormSubmit = (values, { setSubmitting, setErrors }) => { + const form = { ...values }; + + const onSuccess = ({ response }) => { + closeDialog(dialogName); + queryCache.invalidateQueries('accounts-list'); + + AppToaster.show({ + message: formatMessage({ + id: 'the_make_adjustment_has_been_successfully_created', + }), + intent: Intent.SUCCESS, + }); + }; + const onError = (error) => { + setSubmitting(false); + }; + //requestInventoryAdjustment + }; + + // Handles dialog close. + const handleClose = useCallback(() => { + closeDialog(dialogName); + }, [closeDialog, dialogName]); + + return ( + + + + + + ); +} + +export default compose(withDialogActions)(InventoryAdjustmentFormDialogContent); diff --git a/client/src/containers/Dialogs/InventoryAdjustmentFormDialog/InventoryAdjustmentFormDialogFields.js b/client/src/containers/Dialogs/InventoryAdjustmentFormDialog/InventoryAdjustmentFormDialogFields.js new file mode 100644 index 000000000..fca2d3b27 --- /dev/null +++ b/client/src/containers/Dialogs/InventoryAdjustmentFormDialog/InventoryAdjustmentFormDialogFields.js @@ -0,0 +1,200 @@ +import React from 'react'; +import { + Form, + FastField, + ErrorMessage, + useFormikContext, + useField, +} from 'formik'; +import { + Button, + Classes, + FormGroup, + InputGroup, + Intent, + TextArea, + Position, +} from '@blueprintjs/core'; +import classNames from 'classnames'; +import { FormattedMessage as T } from 'react-intl'; +import { DateInput } from '@blueprintjs/datetime'; +import { ListSelect, Choose, If, FieldRequiredHint } from 'components'; +import { + inputIntent, + momentFormatter, + tansformDateValue, + handleDateChange, +} from 'utils'; +import { CLASSES } from 'common/classes'; +import adjustmentType from 'common/adjustmentType'; +import IncrementAdjustmentFields from './IncrementAdjustmentFields'; +import DecrementAdjustmentFields from './DecrementAdjustmentFields'; +import AccountsSuggestField from 'components/AccountsSuggestField'; + +import withAccounts from 'containers/Accounts/withAccounts'; +import { compose } from 'redux'; + +/** + * Inventory adjustment form dialogs fields. + */ +function InventoryAdjustmentFormDialogFields({ + // #ownProps + onClose, + + //# withAccount + accountsList, +}) { + const { values, isSubmitting } = useFormikContext(); + + return ( +
+
+ {/*------------ Date -----------*/} + + {({ form, field: { value }, meta: { error, touched } }) => ( + } + labelInfo={} + intent={inputIntent({ error, touched })} + helperText={} + minimal={true} + className={classNames(CLASSES.FILL)} + > + { + form.setFieldValue('date', formattedDate); + })} + value={tansformDateValue(value)} + popoverProps={{ + position: Position.BOTTOM, + minimal: true, + }} + /> + + )} + + + {/*------------ Adjustment type -----------*/} + + {({ form, field: { value }, meta: { error, touched } }) => ( + } + labelInfo={} + helperText={} + intent={inputIntent({ error, touched })} + className={classNames(CLASSES.FILL)} + > + { + console.log(type.value, 'EE'); + form.setFieldValue('type', type.value); + }} + selectedItem={value} + selectedItemProp={'value'} + labelProp={'name'} + popoverProps={{ minimal: true }} + /> + + )} + + + + + + + + + + + {/*------------ Reason -----------*/} + + {({ form, field, meta: { error, touched } }) => ( + } + labelInfo={} + intent={inputIntent({ error, touched })} + helperText={} + > + + + )} + + {/*------------ Adjustment account -----------*/} + + {({ form, field, meta: { error, touched } }) => ( + } + labelInfo={} + intent={inputIntent({ error, touched })} + helperText={} + > + + form.setFieldValue('adjustment_account_id', item) + } + /> + + )} + + {/*------------ Reference -----------*/} + + {({ form, field, meta: { error, touched } }) => ( + } + className={classNames(CLASSES.FILL)} + intent={inputIntent({ error, touched })} + helperText={} + > + + + )} + + {/*------------ description -----------*/} + + {({ field, meta: { error, touched } }) => ( + } + className={'form-group--description'} + intent={inputIntent({ error, touched })} + helperText={} + > +