mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-19 22:30:31 +00:00
Merge branch 'master' of https://github.com/abouolia/Ratteb
This commit is contained in:
4
client/src/common/adjustmentType.js
Normal file
4
client/src/common/adjustmentType.js
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export default [
|
||||||
|
{ name: 'Decrement', value: 'decrement' },
|
||||||
|
{ name: 'Increment', value: 'increment' },
|
||||||
|
]
|
||||||
@@ -12,6 +12,7 @@ import PaymentReceiveNumberDialog from 'containers/Dialogs/PaymentReceiveNumberD
|
|||||||
import EstimateNumberDialog from 'containers/Dialogs/EstimateNumberDialog';
|
import EstimateNumberDialog from 'containers/Dialogs/EstimateNumberDialog';
|
||||||
import ReceiptNumberDialog from 'containers/Dialogs/ReceiptNumberDialog';
|
import ReceiptNumberDialog from 'containers/Dialogs/ReceiptNumberDialog';
|
||||||
import InvoiceNumberDialog from 'containers/Dialogs/InvoiceNumberDialog';
|
import InvoiceNumberDialog from 'containers/Dialogs/InvoiceNumberDialog';
|
||||||
|
import InventoryAdjustmentDialog from 'containers/Dialogs/InventoryAdjustmentFormDialog';
|
||||||
|
|
||||||
export default function DialogsContainer() {
|
export default function DialogsContainer() {
|
||||||
return (
|
return (
|
||||||
@@ -27,6 +28,7 @@ export default function DialogsContainer() {
|
|||||||
<InviteUserDialog dialogName={'invite-user'} />
|
<InviteUserDialog dialogName={'invite-user'} />
|
||||||
<ExchangeRateFormDialog dialogName={'exchangeRate-form'} />
|
<ExchangeRateFormDialog dialogName={'exchangeRate-form'} />
|
||||||
<ItemCategoryDialog dialogName={'item-category-form'} />
|
<ItemCategoryDialog dialogName={'item-category-form'} />
|
||||||
|
<InventoryAdjustmentDialog dialogName={'inventory-adjustment-form'} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ export default [
|
|||||||
href: '/items',
|
href: '/items',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: <T id={'new_item'} />,
|
text: <T id={'inventory_adjustments'} />,
|
||||||
href: '/items/new',
|
href: '/inventory-adjustments',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: <T id={'category_list'} />,
|
text: <T id={'category_list'} />,
|
||||||
|
|||||||
@@ -54,21 +54,21 @@ function ManualJournalActionsBar({
|
|||||||
history.push('/make-journal-entry');
|
history.push('/make-journal-entry');
|
||||||
}, [history]);
|
}, [history]);
|
||||||
|
|
||||||
const filterDropdown = FilterDropdown({
|
// const filterDropdown = FilterDropdown({
|
||||||
fields: resourceFields,
|
// fields: resourceFields,
|
||||||
initialCondition: {
|
// initialCondition: {
|
||||||
fieldKey: 'journal_number',
|
// fieldKey: 'journal_number',
|
||||||
compatator: 'contains',
|
// compatator: 'contains',
|
||||||
value: '',
|
// value: '',
|
||||||
},
|
// },
|
||||||
onFilterChange: (filterConditions) => {
|
// onFilterChange: (filterConditions) => {
|
||||||
setFilterCount(filterConditions.length || 0);
|
// setFilterCount(filterConditions.length || 0);
|
||||||
addManualJournalsTableQueries({
|
// addManualJournalsTableQueries({
|
||||||
filter_roles: filterConditions || '',
|
// filter_roles: filterConditions || '',
|
||||||
});
|
// });
|
||||||
onFilterChanged && onFilterChanged(filterConditions);
|
// onFilterChanged && onFilterChanged(filterConditions);
|
||||||
},
|
// },
|
||||||
});
|
// });
|
||||||
const hasSelectedRows = useMemo(() => selectedRows.length > 0, [
|
const hasSelectedRows = useMemo(() => selectedRows.length > 0, [
|
||||||
selectedRows,
|
selectedRows,
|
||||||
]);
|
]);
|
||||||
@@ -103,7 +103,7 @@ function ManualJournalActionsBar({
|
|||||||
/>
|
/>
|
||||||
<Popover
|
<Popover
|
||||||
minimal={true}
|
minimal={true}
|
||||||
content={filterDropdown}
|
// content={filterDropdown}
|
||||||
interactionKind={PopoverInteractionKind.CLICK}
|
interactionKind={PopoverInteractionKind.CLICK}
|
||||||
position={Position.BOTTOM_LEFT}
|
position={Position.BOTTOM_LEFT}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -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;
|
||||||
@@ -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;
|
||||||
@@ -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);
|
||||||
@@ -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);
|
||||||
@@ -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);
|
||||||
176
client/src/containers/Items/InventoryAdjustmentDataTable.js
Normal file
176
client/src/containers/Items/InventoryAdjustmentDataTable.js
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
import React, { useCallback, useMemo } from 'react';
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Popover,
|
||||||
|
Menu,
|
||||||
|
Intent,
|
||||||
|
MenuItem,
|
||||||
|
MenuDivider,
|
||||||
|
Position,
|
||||||
|
} from '@blueprintjs/core';
|
||||||
|
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||||
|
import moment from 'moment';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import {
|
||||||
|
DataTable,
|
||||||
|
If,
|
||||||
|
Money,
|
||||||
|
Choose,
|
||||||
|
Icon,
|
||||||
|
LoadingIndicator,
|
||||||
|
} from 'components';
|
||||||
|
import { CLASSES } from 'common/classes';
|
||||||
|
import { useIsValuePassed } from 'hooks';
|
||||||
|
|
||||||
|
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||||
|
// withInventoryAdjustments
|
||||||
|
// withInventoryAdjustmentsActions
|
||||||
|
|
||||||
|
import { compose, saveInvoke } from 'utils';
|
||||||
|
import { withRouter } from 'react-router-dom';
|
||||||
|
|
||||||
|
function InventoryAdjustmentDataTable({
|
||||||
|
// #ownProps
|
||||||
|
onDeleteInventoryAdjustment,
|
||||||
|
onSelectedRowsChange,
|
||||||
|
}) {
|
||||||
|
const { formatMessage } = useIntl();
|
||||||
|
|
||||||
|
const handleDeleteInventoryAdjustment = useCallback(
|
||||||
|
(_inventory) => {
|
||||||
|
saveInvoke(onDeleteInventoryAdjustment, _inventory);
|
||||||
|
},
|
||||||
|
[onDeleteInventoryAdjustment],
|
||||||
|
);
|
||||||
|
|
||||||
|
const actionMenuList = useCallback(
|
||||||
|
(adjustment) => (
|
||||||
|
<Menu>
|
||||||
|
<MenuItem
|
||||||
|
icon={<Icon icon="reader-18" />}
|
||||||
|
text={formatMessage({ id: 'view_details' })}
|
||||||
|
/>
|
||||||
|
<MenuDivider />
|
||||||
|
<MenuItem
|
||||||
|
text={formatMessage({ id: 'delete_adjustment' })}
|
||||||
|
icon={<Icon icon="trash-16" iconSize={16} />}
|
||||||
|
intent={Intent.DANGER}
|
||||||
|
onClick={handleDeleteInventoryAdjustment(adjustment)}
|
||||||
|
/>
|
||||||
|
</Menu>
|
||||||
|
),
|
||||||
|
[handleDeleteInventoryAdjustment, formatMessage],
|
||||||
|
);
|
||||||
|
|
||||||
|
const onRowContextMenu = useCallback(
|
||||||
|
(cell) => actionMenuList(cell.row.original),
|
||||||
|
[actionMenuList],
|
||||||
|
);
|
||||||
|
|
||||||
|
const columns = useMemo(
|
||||||
|
() => [
|
||||||
|
{
|
||||||
|
id: 'date',
|
||||||
|
Header: formatMessage({ id: 'date' }),
|
||||||
|
accessor: (r) => moment(r.date).format('YYYY MMM DD'),
|
||||||
|
width: 115,
|
||||||
|
className: 'date',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'type',
|
||||||
|
Header: formatMessage({ id: 'type' }),
|
||||||
|
accessor: 'type',
|
||||||
|
className: 'type',
|
||||||
|
width: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'reason',
|
||||||
|
Header: formatMessage({ id: 'reason' }),
|
||||||
|
// accessor: (r) => (
|
||||||
|
// <Tooltip
|
||||||
|
// content={}
|
||||||
|
// position={Position.RIGHT_BOTTOM}
|
||||||
|
// >
|
||||||
|
// </Tooltip>
|
||||||
|
// ),
|
||||||
|
className: 'reason',
|
||||||
|
width: 115,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'reference',
|
||||||
|
Header: formatMessage({ id: 'reference' }),
|
||||||
|
accessor: (row) => `#${row.reference}`,
|
||||||
|
className: 'reference',
|
||||||
|
width: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'status',
|
||||||
|
Header: formatMessage({ id: 'status' }),
|
||||||
|
accessor: 'status',
|
||||||
|
width: 95,
|
||||||
|
className: 'status',
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
id: 'description',
|
||||||
|
Header: formatMessage({ id: 'description' }),
|
||||||
|
disableSorting: true,
|
||||||
|
width: 85,
|
||||||
|
className: 'description',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'created_at',
|
||||||
|
Header: formatMessage({ id: 'created_at' }),
|
||||||
|
accessor: (r) => moment(r.created_at).format('YYYY MMM DD'),
|
||||||
|
width: 125,
|
||||||
|
className: 'created_at',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'actions',
|
||||||
|
Header: '',
|
||||||
|
Cell: ({ cell }) => (
|
||||||
|
<Popover
|
||||||
|
content={actionMenuList(cell.row.original)}
|
||||||
|
position={Position.RIGHT_BOTTOM}
|
||||||
|
>
|
||||||
|
<Button icon={<Icon icon="more-h-16" iconSize={16} />} />
|
||||||
|
</Popover>
|
||||||
|
),
|
||||||
|
className: 'actions',
|
||||||
|
width: 50,
|
||||||
|
disableResizing: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[actionMenuList, formatMessage],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleSelectedRowsChange = useCallback(
|
||||||
|
(selectedRows) => {
|
||||||
|
saveInvoke(
|
||||||
|
onSelectedRowsChange,
|
||||||
|
selectedRows.map((s) => s.original),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[onSelectedRowsChange],
|
||||||
|
);
|
||||||
|
|
||||||
|
// const showEmptyStatus = [
|
||||||
|
|
||||||
|
// ].every((condition) => condition === true);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classNames(CLASSES.DASHBOARD_DATATABLE)}>
|
||||||
|
<LoadingIndicator
|
||||||
|
|
||||||
|
// loading={}
|
||||||
|
>
|
||||||
|
<DataTable noInitialFetch={true} columns={columns} data={[]} />
|
||||||
|
</LoadingIndicator>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default compose(
|
||||||
|
withRouter,
|
||||||
|
withDialogActions,
|
||||||
|
)(InventoryAdjustmentDataTable);
|
||||||
81
client/src/containers/Items/InventoryAdjustmentList.js
Normal file
81
client/src/containers/Items/InventoryAdjustmentList.js
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
import React, { useEffect, useState, useCallback, useMemo } from 'react';
|
||||||
|
import { useQuery } from 'react-query';
|
||||||
|
import { Alert, Intent } from '@blueprintjs/core';
|
||||||
|
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||||
|
|
||||||
|
import DashboardPageContent from 'components/Dashboard/DashboardPageContent';
|
||||||
|
import DashboardInsider from 'components/Dashboard/DashboardInsider';
|
||||||
|
|
||||||
|
import InventoryAdjustmentDataTable from './InventoryAdjustmentDataTable';
|
||||||
|
|
||||||
|
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
|
||||||
|
//withInventoryAdjustmentsActions
|
||||||
|
import { compose } from 'utils';
|
||||||
|
import { Route, Switch } from 'react-router-dom';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inventory Adjustment List.
|
||||||
|
*/
|
||||||
|
function InventoryAdjustmentList({
|
||||||
|
// #withDashboardActions
|
||||||
|
changePageTitle,
|
||||||
|
// #withInventoryAdjustmentsActions
|
||||||
|
}) {
|
||||||
|
const { formatMessage } = useIntl();
|
||||||
|
const [selectedRows, setSelectedRows] = useState([]);
|
||||||
|
const [deleteInventoryAdjustment, setDeleteInventoryAdjustment] = useState(
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
changePageTitle(formatMessage({ id: 'inventory_adjustment_list' }));
|
||||||
|
}, [changePageTitle, formatMessage]);
|
||||||
|
|
||||||
|
const fetchInventoryAdjustments = useQuery(
|
||||||
|
['inventory-adjustment-list'],
|
||||||
|
() => {},
|
||||||
|
);
|
||||||
|
|
||||||
|
// Handle selected rows change.
|
||||||
|
const handleSelectedRowsChange = useCallback(
|
||||||
|
(inventory) => {
|
||||||
|
setSelectedRows(inventory);
|
||||||
|
},
|
||||||
|
[setSelectedRows],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleDeleteInventoryAdjustment = useCallback(
|
||||||
|
(adjustment) => {
|
||||||
|
setDeleteInventoryAdjustment(adjustment);
|
||||||
|
},
|
||||||
|
[setDeleteInventoryAdjustment],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleCancelInventoryAdjustmentDelete = useCallback(() => {
|
||||||
|
setDeleteInventoryAdjustment(false);
|
||||||
|
}, [setDeleteInventoryAdjustment]);
|
||||||
|
|
||||||
|
const handleConfirmInventoryAdjustmentDelete = useCallback(() => {}, []);
|
||||||
|
|
||||||
|
// Calculates the data table selected rows count.
|
||||||
|
const selectedRowsCount = useMemo(() => Object.values(selectedRows).length, [
|
||||||
|
selectedRows,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DashboardInsider>
|
||||||
|
<DashboardPageContent>
|
||||||
|
<Switch>
|
||||||
|
<Route exact={true}>
|
||||||
|
<InventoryAdjustmentDataTable
|
||||||
|
onDeleteInventoryAdjustment={handleDeleteInventoryAdjustment}
|
||||||
|
onSelectedRowsChange={handleSelectedRowsChange}
|
||||||
|
/>
|
||||||
|
</Route>
|
||||||
|
</Switch>
|
||||||
|
</DashboardPageContent>
|
||||||
|
</DashboardInsider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default compose(withDashboardActions)(InventoryAdjustmentList);
|
||||||
@@ -27,6 +27,7 @@ import { CLASSES } from 'common/classes';
|
|||||||
import withItems from 'containers/Items/withItems';
|
import withItems from 'containers/Items/withItems';
|
||||||
import withItemsActions from 'containers/Items/withItemsActions';
|
import withItemsActions from 'containers/Items/withItemsActions';
|
||||||
import withSettings from 'containers/Settings/withSettings';
|
import withSettings from 'containers/Settings/withSettings';
|
||||||
|
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||||
import { compose, saveInvoke, isBlank, defaultToTransform } from 'utils';
|
import { compose, saveInvoke, isBlank, defaultToTransform } from 'utils';
|
||||||
|
|
||||||
// Items datatable.
|
// Items datatable.
|
||||||
@@ -38,6 +39,9 @@ function ItemsDataTable({
|
|||||||
itemsCurrentViewId,
|
itemsCurrentViewId,
|
||||||
itemsPagination,
|
itemsPagination,
|
||||||
|
|
||||||
|
// #withDialogActions
|
||||||
|
openDialog,
|
||||||
|
|
||||||
// #withItemsActions
|
// #withItemsActions
|
||||||
addItemsTableQueries,
|
addItemsTableQueries,
|
||||||
|
|
||||||
@@ -84,6 +88,11 @@ function ItemsDataTable({
|
|||||||
},
|
},
|
||||||
[onDeleteItem],
|
[onDeleteItem],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleMakeAdjustment = useCallback(() => {
|
||||||
|
openDialog('inventory-adjustment-form', {});
|
||||||
|
}, [openDialog]);
|
||||||
|
|
||||||
const actionMenuList = useCallback(
|
const actionMenuList = useCallback(
|
||||||
(item) => (
|
(item) => (
|
||||||
<Menu>
|
<Menu>
|
||||||
@@ -111,6 +120,13 @@ function ItemsDataTable({
|
|||||||
onClick={() => onActivateItem(item)}
|
onClick={() => onActivateItem(item)}
|
||||||
/>
|
/>
|
||||||
</If>
|
</If>
|
||||||
|
|
||||||
|
<If condition={item.type === 'inventory'}>
|
||||||
|
<MenuItem
|
||||||
|
text={formatMessage({ id: 'make_adjustment' })}
|
||||||
|
onClick={handleMakeAdjustment}
|
||||||
|
/>
|
||||||
|
</If>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
text={formatMessage({ id: 'delete_item' })}
|
text={formatMessage({ id: 'delete_item' })}
|
||||||
icon={<Icon icon="trash-16" iconSize={16} />}
|
icon={<Icon icon="trash-16" iconSize={16} />}
|
||||||
@@ -300,4 +316,5 @@ export default compose(
|
|||||||
baseCurrency: organizationSettings?.baseCurrency,
|
baseCurrency: organizationSettings?.baseCurrency,
|
||||||
})),
|
})),
|
||||||
withItemsActions,
|
withItemsActions,
|
||||||
|
withDialogActions,
|
||||||
)(ItemsDataTable);
|
)(ItemsDataTable);
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import { connect } from 'react-redux';
|
||||||
|
import {
|
||||||
|
submitInventoryAdjustment,
|
||||||
|
deleteInventoryAdjustment,
|
||||||
|
fetchInventoryAdjustmentsTable,
|
||||||
|
} from 'store/inventoryAdjustments/inventoryAdjustment.actions';
|
||||||
|
import t from 'store/types';
|
||||||
|
|
||||||
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
|
requestSubmitInventoryAdjustment: (form) =>
|
||||||
|
dispatch(submitInventoryAdjustment({ form })),
|
||||||
|
requestFetchInventoryAdjustmentTable: (query = {}) =>
|
||||||
|
dispatch(fetchInventoryAdjustmentsTable({ query: { ...query } })),
|
||||||
|
requestDeleteInventoryAdjustment: (id) =>
|
||||||
|
dispatch(deleteInventoryAdjustment({ id })),
|
||||||
|
|
||||||
|
addInventoryAdjustmentTableQueries: (queries) =>
|
||||||
|
dispatch({
|
||||||
|
type: t.INVENTORY_ADJUSTMENTS_TABLE_QUERIES_ADD,
|
||||||
|
payload: { queries },
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(null, mapDispatchToProps);
|
||||||
4
client/src/containers/Items/withInventoryAdjustments.js
Normal file
4
client/src/containers/Items/withInventoryAdjustments.js
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -940,4 +940,18 @@ export default {
|
|||||||
'The invoice cannot be deleted cause has associated payment transactions',
|
'The invoice cannot be deleted cause has associated payment transactions',
|
||||||
category_name_exists: 'Category name exists',
|
category_name_exists: 'Category name exists',
|
||||||
some_customers_have_sales_invoices: 'Some customers have sales invoices',
|
some_customers_have_sales_invoices: 'Some customers have sales invoices',
|
||||||
|
inventory_adjustments: 'Inventory adjustments',
|
||||||
|
make_adjustment: 'Make a adjustment',
|
||||||
|
adjustment_type: 'Adjustment type',
|
||||||
|
decrement: 'Decrement',
|
||||||
|
new_quantity: 'New quantity',
|
||||||
|
reason: 'Reason',
|
||||||
|
increment: 'Increment',
|
||||||
|
cost: 'Cost',
|
||||||
|
qty_on_hand: 'Qty on hand',
|
||||||
|
adjustment_account: 'Adjustment account',
|
||||||
|
inventory_adjustment_list:'Inventory Adjustment List',
|
||||||
|
delete_adjustment:'Delete Adjustment',
|
||||||
|
the_make_adjustment_has_been_successfully_created:
|
||||||
|
'The make adjustment has been successfully created.',
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -89,6 +89,14 @@ export default [
|
|||||||
}),
|
}),
|
||||||
breadcrumb: 'Items',
|
breadcrumb: 'Items',
|
||||||
},
|
},
|
||||||
|
// Inventory adjustments
|
||||||
|
{
|
||||||
|
path: `/inventory-adjustments`,
|
||||||
|
component: LazyLoader({
|
||||||
|
loader: () => import('containers/Items/InventoryAdjustmentList'),
|
||||||
|
}),
|
||||||
|
breadcrumb: 'Inventory a adjustments',
|
||||||
|
},
|
||||||
|
|
||||||
// Financial Reports.
|
// Financial Reports.
|
||||||
{
|
{
|
||||||
@@ -112,7 +120,7 @@ export default [
|
|||||||
component: LazyLoader({
|
component: LazyLoader({
|
||||||
loader: () =>
|
loader: () =>
|
||||||
import(
|
import(
|
||||||
'containers/FinancialStatements/TrialBalanceSheet/TrialBalanceSheet'
|
'containers/FinancialStatements/TrialBalanceSheet/TrialBalanceSheet'
|
||||||
),
|
),
|
||||||
}),
|
}),
|
||||||
breadcrumb: 'Trial Balance Sheet',
|
breadcrumb: 'Trial Balance Sheet',
|
||||||
@@ -252,7 +260,7 @@ export default [
|
|||||||
},
|
},
|
||||||
|
|
||||||
// Invoices.
|
// Invoices.
|
||||||
{
|
{
|
||||||
path: `/invoices/:id/edit`,
|
path: `/invoices/:id/edit`,
|
||||||
component: LazyLoader({
|
component: LazyLoader({
|
||||||
loader: () => import('containers/Sales/Invoice/Invoices'),
|
loader: () => import('containers/Sales/Invoice/Invoices'),
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
import ApiService from 'services/ApiService';
|
||||||
|
import t from 'store/types';
|
||||||
|
|
||||||
|
export const submitInventoryAdjustment = ({ form }) => {
|
||||||
|
return (dispatch) =>
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
ApiService.post('inventory_adjustments', form).then((response) => {
|
||||||
|
resolve(response);
|
||||||
|
}),
|
||||||
|
caches((error) => {
|
||||||
|
const { response } = error;
|
||||||
|
const { data } = response;
|
||||||
|
|
||||||
|
reject(data?.errors);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const deleteInventoryAdjustment = ({ id }) => {
|
||||||
|
return (dispatch) =>
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
ApiService.delete(`inventory_adjustments/${id}`)
|
||||||
|
.then((response) => {
|
||||||
|
dispatch({
|
||||||
|
type: t.INVENTORY_ADJUSTMENT_DELETE,
|
||||||
|
payload: { id },
|
||||||
|
});
|
||||||
|
resolve(response);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
reject(error.response.data.errors || []);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const fetchInventoryAdjustmentsTable = ({ query } = {}) => {
|
||||||
|
return (dispatch, getState) =>
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
const pageQuery = getState().inventoryAdjustments.tableQuery;
|
||||||
|
dispatch({
|
||||||
|
type: t.INVENTORY_ADJUSTMENTS_LOADING,
|
||||||
|
payload: {
|
||||||
|
loading: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
ApiService.get('inventory_adjustments', {
|
||||||
|
params: { ...pageQuery, ...query },
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
dispatch({
|
||||||
|
type: t.INVENTORY_ADJUSTMENTS_PAGE_SET,
|
||||||
|
payload: {
|
||||||
|
inventory_adjustments: response.data,
|
||||||
|
pagination: response.data.pagination,
|
||||||
|
customViewId:
|
||||||
|
response.data?.filter_meta?.view?.custom_view_id || -1,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
dispatch({
|
||||||
|
type: t.INVENTORY_ADJUSTMENT_ITEMS_SET,
|
||||||
|
payload: {
|
||||||
|
inventory_adjustment: response.data,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
dispatch({
|
||||||
|
type: t.INVENTORY_ADJUSTMENTS_PAGINATION_SET,
|
||||||
|
payload: {
|
||||||
|
pagination: response.data.pagination,
|
||||||
|
customViewId:
|
||||||
|
response.data?.filter_meta?.view?.custom_view_id || -1,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
dispatch({
|
||||||
|
type: t.INVENTORY_ADJUSTMENTS_LOADING,
|
||||||
|
payload: {
|
||||||
|
loading: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
resolve(response);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
reject(error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
import { createReducer } from '@reduxjs/toolkit';
|
||||||
|
import {
|
||||||
|
viewPaginationSetReducer,
|
||||||
|
createTableQueryReducers,
|
||||||
|
} from 'store/journalNumber.reducer';
|
||||||
|
import t from 'store/types';
|
||||||
|
|
||||||
|
const initialState = {
|
||||||
|
items: {},
|
||||||
|
views: {},
|
||||||
|
loading: false,
|
||||||
|
currentViewId: -1,
|
||||||
|
tableQuery: {
|
||||||
|
page_size: 12,
|
||||||
|
page: 1,
|
||||||
|
},
|
||||||
|
paginationMeta: {
|
||||||
|
total: 0,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default createReducer(initialState, {
|
||||||
|
[t.INVENTORY_ADJUSTMENTS_LOADING]: (state, action) => {
|
||||||
|
const { loading } = action.payload;
|
||||||
|
state.loading = loading;
|
||||||
|
},
|
||||||
|
|
||||||
|
[t.INVENTORY_ADJUSTMENT_DELETE]: (state, action) => {
|
||||||
|
const { id } = action.payload;
|
||||||
|
if (typeof state.items[id] !== 'undefined') {
|
||||||
|
delete state.items[id];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
[t.INVENTORY_ADJUSTMENTS_PAGE_SET]: (state, action) => {
|
||||||
|
const { customViewId, inventory_adjustments, pagination } = action.payload;
|
||||||
|
|
||||||
|
const viewId = customViewId || -1;
|
||||||
|
const view = state.views[viewId] || {};
|
||||||
|
|
||||||
|
state.views[viewId] = {
|
||||||
|
...view,
|
||||||
|
pages: {
|
||||||
|
...(state.views?.[viewId]?.pages || {}),
|
||||||
|
[pagination.page]: {
|
||||||
|
ids: inventory_adjustments.map((i) => i.id),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
//useless
|
||||||
|
[t.INVENTORY_ADJUSTMENT_ITEMS_SET]: (state, action) => {
|
||||||
|
const { inventory_adjustment } = action.payload;
|
||||||
|
const _inventory_adjustment = {};
|
||||||
|
|
||||||
|
inventory_adjustment.forEach((_inventory) => {
|
||||||
|
_inventory_adjustment[_inventory.id] = {
|
||||||
|
..._inventory,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
state.items = {
|
||||||
|
...state.items,
|
||||||
|
..._inventory_adjustment,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
[t.INVENTORY_ADJUSTMENTS_SET_CURRENT_VIEW]: (state, action) => {
|
||||||
|
state.currentViewId = action.currentViewId;
|
||||||
|
},
|
||||||
|
|
||||||
|
...viewPaginationSetReducer(t.INVENTORY_ADJUSTMENTS_PAGINATION_SET),
|
||||||
|
...createTableQueryReducers('INVENTORY_ADJUSTMENTS'),
|
||||||
|
});
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
|
import {
|
||||||
|
pickItemsFromIds,
|
||||||
|
paginationLocationQuery,
|
||||||
|
defaultPaginationMeta,
|
||||||
|
} from 'store/selectors';
|
||||||
|
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
export default {
|
||||||
|
INVENTORY_ADJUSTMENT_ITEMS_SET: 'INVENTORY_ADJUSTMENT_ITEMS_SET',
|
||||||
|
INVENTORY_ADJUSTMENT_DELETE: 'INVENTORY_ADJUSTMENT_DELETE',
|
||||||
|
INVENTORY_ADJUSTMENTS_LOADING: 'INVENTORY_ADJUSTMENTS_LOADING',
|
||||||
|
INVENTORY_ADJUSTMENTS_PAGE_SET: 'INVENTORY_ADJUSTMENTS_PAGE_SET',
|
||||||
|
|
||||||
|
INVENTORY_ADJUSTMENTS_PAGINATION_SET: 'INVENTORY_ADJUSTMENTS_PAGINATION_SET',
|
||||||
|
|
||||||
|
|
||||||
|
INVENTORY_ADJUSTMENTS_TABLE_QUERIES_ADD:
|
||||||
|
'INVENTORY_ADJUSTMENTS_TABLE_QUERIES_ADD',
|
||||||
|
INVENTORY_ADJUSTMENTS_SET_CURRENT_VIEW:
|
||||||
|
'INVENTORY_ADJUSTMENTS_SET_CURRENT_VIEW',
|
||||||
|
};
|
||||||
@@ -27,6 +27,7 @@ import paymentReceives from './PaymentReceive/paymentReceive.reducer';
|
|||||||
import paymentMades from './PaymentMades/paymentMade.reducer';
|
import paymentMades from './PaymentMades/paymentMade.reducer';
|
||||||
import organizations from './organizations/organizations.reducers';
|
import organizations from './organizations/organizations.reducers';
|
||||||
import subscriptions from './subscription/subscription.reducer';
|
import subscriptions from './subscription/subscription.reducer';
|
||||||
|
import inventoryAdjustments from './inventoryAdjustments/inventoryAdjustment.reducer';
|
||||||
|
|
||||||
export default combineReducers({
|
export default combineReducers({
|
||||||
authentication,
|
authentication,
|
||||||
@@ -56,4 +57,5 @@ export default combineReducers({
|
|||||||
vendors,
|
vendors,
|
||||||
paymentReceives,
|
paymentReceives,
|
||||||
paymentMades,
|
paymentMades,
|
||||||
|
inventoryAdjustments,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import paymentReceives from './PaymentReceive/paymentReceive.type';
|
|||||||
import paymentMades from './PaymentMades/paymentMade.type';
|
import paymentMades from './PaymentMades/paymentMade.type';
|
||||||
import organizations from './organizations/organizations.types';
|
import organizations from './organizations/organizations.types';
|
||||||
import subscription from './subscription/subscription.types';
|
import subscription from './subscription/subscription.types';
|
||||||
|
import inventoryAdjustments from './inventoryAdjustments/inventoryAdjustment.type';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
...authentication,
|
...authentication,
|
||||||
@@ -56,4 +57,5 @@ export default {
|
|||||||
...paymentMades,
|
...paymentMades,
|
||||||
...organizations,
|
...organizations,
|
||||||
...subscription,
|
...subscription,
|
||||||
|
...inventoryAdjustments
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user