feat : inventory adjustments.

This commit is contained in:
elforjani3
2021-01-11 09:42:01 +02:00
parent 097b9fdb3a
commit 9c00da3613
23 changed files with 1031 additions and 20 deletions

View File

@@ -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 (
<Row>
{/*------------ Quantity on hand -----------*/}
<Col sm={3}>
<FastField name={'quantity'}>
{({ field, meta: { error, touched } }) => (
<FormGroup
label={<T id={'qty_on_hand'} />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="quantity" />}
>
<InputGroup disabled={true} medium={'true'} {...field} />
</FormGroup>
)}
</FastField>
</Col>
{/*------------ Decrement -----------*/}
<Col sm={2}>
<FastField name={'decrement'}>
{({ field, meta: { error, touched } }) => (
<FormGroup
label={<T id={'decrement'} />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="decrement" />}
fill={true}
>
<InputGroup medium={'true'} {...field} />
</FormGroup>
)}
</FastField>
</Col>
{/*------------ New quantity -----------*/}
<Col sm={4}>
<FastField name={'new_quantity'}>
{({ field, meta: { error, touched } }) => (
<FormGroup
label={<T id={'new_quantity'} />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="new_quantity" />}
>
<InputGroup medium={'true'} {...field} />
</FormGroup>
)}
</FastField>
</Col>
</Row>
);
}
export default DecrementAdjustmentFields;

View File

@@ -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 (
<Row>
{/*------------ Quantity on hand -----------*/}
<Col sm={3}>
<FastField name={'quantity'}>
{({ field, meta: { error, touched } }) => (
<FormGroup
label={<T id={'qty_on_hand'} />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="quantity" />}
>
<InputGroup disabled={true} medium={'true'} {...field} />
</FormGroup>
)}
</FastField>
</Col>
{/*------------ Increment -----------*/}
<Col sm={2}>
<FastField name={'increment'}>
{({ field, meta: { error, touched } }) => (
<FormGroup
label={<T id={'increment'} />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="increment" />}
fill={true}
>
<InputGroup medium={'true'} {...field} />
</FormGroup>
)}
</FastField>
</Col>
{/*------------ Cost -----------*/}
<Col sm={2}>
<FastField name={'cost'}>
{({ field, meta: { error, touched } }) => (
<FormGroup
label={<T id={'cost'} />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="cost" />}
>
<InputGroup medium={'true'} {...field} />
</FormGroup>
)}
</FastField>
</Col>
{/*------------ New quantity -----------*/}
<Col sm={4}>
<FastField name={'new_quantity'}>
{({ field, meta: { error, touched } }) => (
<FormGroup
label={<T id={'new_quantity'} />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="new_quantity" />}
>
<InputGroup medium={'true'} {...field} />
</FormGroup>
)}
</FastField>
</Col>
</Row>
);
}
export default IncrementAdjustmentFields;

View File

@@ -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;

View File

@@ -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 (
<DialogContent>
<Formik
validationSchema={CreateInventoryAdjustmentFormSchema}
initialValues={initialValues}
onSubmit={handleFormSubmit}
>
<InventoryAdjustmentFormDialogFields
dialogName={dialogName}
onClose={handleClose}
/>
</Formik>
</DialogContent>
);
}
export default compose(withDialogActions)(InventoryAdjustmentFormDialogContent);

View File

@@ -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 (
<Form>
<div className={Classes.DIALOG_BODY}>
{/*------------ Date -----------*/}
<FastField name={'date'}>
{({ form, field: { value }, meta: { error, touched } }) => (
<FormGroup
label={<T id={'date'} />}
labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="date" />}
minimal={true}
className={classNames(CLASSES.FILL)}
>
<DateInput
{...momentFormatter('YYYY/MM/DD')}
onChange={handleDateChange((formattedDate) => {
form.setFieldValue('date', formattedDate);
})}
value={tansformDateValue(value)}
popoverProps={{
position: Position.BOTTOM,
minimal: true,
}}
/>
</FormGroup>
)}
</FastField>
{/*------------ Adjustment type -----------*/}
<FastField name={'type'}>
{({ form, field: { value }, meta: { error, touched } }) => (
<FormGroup
label={<T id={'adjustment_type'} />}
labelInfo={<FieldRequiredHint />}
helperText={<ErrorMessage name="type" />}
intent={inputIntent({ error, touched })}
className={classNames(CLASSES.FILL)}
>
<ListSelect
items={adjustmentType}
onItemSelect={(type) => {
console.log(type.value, 'EE');
form.setFieldValue('type', type.value);
}}
selectedItem={value}
selectedItemProp={'value'}
labelProp={'name'}
popoverProps={{ minimal: true }}
/>
</FormGroup>
)}
</FastField>
<Choose>
<Choose.When condition={values.type === 'decrement'}>
<DecrementAdjustmentFields />
</Choose.When>
<Choose.When condition={values.type === 'increment'}>
<IncrementAdjustmentFields />
</Choose.When>
</Choose>
{/*------------ Reason -----------*/}
<FastField name={'reason'}>
{({ form, field, meta: { error, touched } }) => (
<FormGroup
label={<T id={'reason'} />}
labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="reason" />}
>
<InputGroup fill={true} {...field} />
</FormGroup>
)}
</FastField>
{/*------------ Adjustment account -----------*/}
<FastField name={'adjustment_account_id'}>
{({ form, field, meta: { error, touched } }) => (
<FormGroup
label={<T id={'adjustment_account'} />}
labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="reason" />}
>
<AccountsSuggestField
accounts={accountsList}
onAccountSelected={(item) =>
form.setFieldValue('adjustment_account_id', item)
}
/>
</FormGroup>
)}
</FastField>
{/*------------ Reference -----------*/}
<FastField name={'reference_no'}>
{({ form, field, meta: { error, touched } }) => (
<FormGroup
label={<T id={'reference_no'} />}
className={classNames(CLASSES.FILL)}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="reference_no" />}
>
<InputGroup {...field} />
</FormGroup>
)}
</FastField>
{/*------------ description -----------*/}
<FastField name={'description'}>
{({ field, meta: { error, touched } }) => (
<FormGroup
label={<T id={'description'} />}
className={'form-group--description'}
intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name={'description'} />}
>
<TextArea growVertically={true} large={true} {...field} />
</FormGroup>
)}
</FastField>
</div>
<div className={Classes.DIALOG_FOOTER}>
<div className={Classes.DIALOG_FOOTER_ACTIONS}>
<Button onClick={onClose} style={{ minWidth: '75px' }}>
<T id={'close'} />
</Button>
<Button
disabled={isSubmitting}
style={{ minWidth: '75px' }}
type="submit"
>
{<T id={'save_as_draft'} />}
</Button>
<Button
intent={Intent.PRIMARY}
disabled={isSubmitting}
style={{ minWidth: '75px' }}
type="submit"
>
{<T id={'make_adjustment'} />}
</Button>
</div>
</div>
</Form>
);
}
export default compose(
withAccounts(({ accountsList }) => ({
accountsList,
})),
)(InventoryAdjustmentFormDialogFields);

View File

@@ -0,0 +1,37 @@
import React, { lazy } from 'react';
import { FormattedMessage as T } from 'react-intl';
import { Dialog, DialogSuspense } from 'components';
import withDialogRedux from 'components/DialogReduxConnect';
import { compose } from 'redux';
const InventoryAdjustmentFormDialogContent = lazy(() =>
import('./InventoryAdjustmentFormDialogContent'),
);
/**
* Inventory adjustments form dialog.
*/
function InventoryAdjustmentFormDialog({
dialogName,
payload = { action: '', id: null },
isOpen,
}) {
return (
<Dialog
name={dialogName}
title={<T id={'make_adjustment'} />}
isOpen={isOpen}
canEscapeJeyClose={true}
autoFocus={true}
>
<DialogSuspense>
<InventoryAdjustmentFormDialogContent
dialogName={dialogName}
action={payload.action}
/>
</DialogSuspense>
</Dialog>
);
}
export default compose(withDialogRedux())(InventoryAdjustmentFormDialog);