mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-20 06:40:31 +00:00
Merge branch 'master' of https://github.com/abouolia/Ratteb
# Conflicts: # client/src/style/App.scss
This commit is contained in:
18
client/src/common/numberFormatsOptions.js
Normal file
18
client/src/common/numberFormatsOptions.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
export const moneyFormat = [
|
||||||
|
{ id: 'total', text: 'Total rows' },
|
||||||
|
{ id: 'always', text: 'Always' },
|
||||||
|
{ id: 'none', text: 'None' },
|
||||||
|
];
|
||||||
|
|
||||||
|
export const negativeFormat = [
|
||||||
|
{ id: 'parentheses', text: 'Parentheses ($1000)' },
|
||||||
|
{ id: 'mines', text: 'Minus -$1000' },
|
||||||
|
];
|
||||||
|
|
||||||
|
export const decimalPlaces = [
|
||||||
|
{ text: '1 Decimals', label: '$0.1', id: 1 },
|
||||||
|
{ text: '2 Decimals', label: '$0.01', id: 2 },
|
||||||
|
{ text: '3 Decimals', label: '$0.001', id: 3 },
|
||||||
|
{ text: '4 Decimals', label: '$0.0001', id: 4 },
|
||||||
|
{ text: '5 Decimals', label: '$0.00001', id: 5 },
|
||||||
|
];
|
||||||
@@ -39,7 +39,7 @@ export default function AccountsTypesSelect({
|
|||||||
items={items}
|
items={items}
|
||||||
selectedItemProp={'id'}
|
selectedItemProp={'id'}
|
||||||
selectedItem={selectedTypeId}
|
selectedItem={selectedTypeId}
|
||||||
labelProp={'label'}
|
textProp={'label'}
|
||||||
defaultText={defaultSelectText}
|
defaultText={defaultSelectText}
|
||||||
onItemSelect={handleItemSelected}
|
onItemSelect={handleItemSelected}
|
||||||
itemPredicate={filterAccountTypeItems}
|
itemPredicate={filterAccountTypeItems}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ export default function CategoriesSelectList({
|
|||||||
items={categoriesList}
|
items={categoriesList}
|
||||||
selectedItemProp={'id'}
|
selectedItemProp={'id'}
|
||||||
selectedItem={selecetedCategoryId}
|
selectedItem={selecetedCategoryId}
|
||||||
labelProp={'name'}
|
textProp={'name'}
|
||||||
defaultText={defaultSelectText}
|
defaultText={defaultSelectText}
|
||||||
onItemSelect={handleItemCategorySelected}
|
onItemSelect={handleItemCategorySelected}
|
||||||
itemPredicate={filterItemCategory}
|
itemPredicate={filterItemCategory}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ export default function DisplayNameList({
|
|||||||
<ListSelect
|
<ListSelect
|
||||||
items={formatOptions}
|
items={formatOptions}
|
||||||
selectedItemProp={'label'}
|
selectedItemProp={'label'}
|
||||||
labelProp={'label'}
|
textProp={'label'}
|
||||||
defaultText={'Select display name as'}
|
defaultText={'Select display name as'}
|
||||||
filterable={false}
|
filterable={false}
|
||||||
{ ...restProps }
|
{ ...restProps }
|
||||||
|
|||||||
@@ -158,7 +158,7 @@ function DynamicFilterValueField({
|
|||||||
selectedItem={value}
|
selectedItem={value}
|
||||||
selectedItemProp={optionsKey}
|
selectedItemProp={optionsKey}
|
||||||
defaultText={`Select an option`}
|
defaultText={`Select an option`}
|
||||||
labelProp={optionsLabel}
|
textProp={optionsLabel}
|
||||||
buttonProps={{
|
buttonProps={{
|
||||||
onClick: handleBtnClick
|
onClick: handleBtnClick
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ function ItemsListField({
|
|||||||
onItemSelect={onItemSelect}
|
onItemSelect={onItemSelect}
|
||||||
selectedItem={`${selectedItemId}`}
|
selectedItem={`${selectedItemId}`}
|
||||||
selectedItemProp={'id'}
|
selectedItemProp={'id'}
|
||||||
labelProp={'name'}
|
textProp={'name'}
|
||||||
defaultText={selectedItem ? selectedItem.name : defautlSelectText}
|
defaultText={selectedItem ? selectedItem.name : defautlSelectText}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ export default function ListSelect({
|
|||||||
defaultText,
|
defaultText,
|
||||||
noResultsText = <T id="no_results" />,
|
noResultsText = <T id="no_results" />,
|
||||||
isLoading = false,
|
isLoading = false,
|
||||||
|
textProp,
|
||||||
labelProp,
|
labelProp,
|
||||||
|
|
||||||
selectedItem,
|
selectedItem,
|
||||||
@@ -52,8 +53,9 @@ export default function ListSelect({
|
|||||||
const itemRenderer = (item, { handleClick, modifiers, query }) => {
|
const itemRenderer = (item, { handleClick, modifiers, query }) => {
|
||||||
return (
|
return (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
text={item[labelProp]}
|
text={item[textProp]}
|
||||||
key={item[selectedItemProp]}
|
key={item[selectedItemProp]}
|
||||||
|
label={item[labelProp]}
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@@ -77,7 +79,7 @@ export default function ListSelect({
|
|||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
text={currentItem ? currentItem[labelProp] : defaultText}
|
text={currentItem ? currentItem[textProp] : defaultText}
|
||||||
loading={isLoading}
|
loading={isLoading}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
{...buttonProps}
|
{...buttonProps}
|
||||||
|
|||||||
169
client/src/components/NumberFormats/NumberFormatFields.js
Normal file
169
client/src/components/NumberFormats/NumberFormatFields.js
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Form, FastField, ErrorMessage, useFormikContext } from 'formik';
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Classes,
|
||||||
|
FormGroup,
|
||||||
|
InputGroup,
|
||||||
|
Intent,
|
||||||
|
Checkbox,
|
||||||
|
} from '@blueprintjs/core';
|
||||||
|
import { CLASSES } from 'common/classes';
|
||||||
|
import { Row, Col, ListSelect } from 'components';
|
||||||
|
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||||
|
import { inputIntent } from 'utils';
|
||||||
|
import {
|
||||||
|
moneyFormat,
|
||||||
|
negativeFormat,
|
||||||
|
decimalPlaces,
|
||||||
|
} from 'common/numberFormatsOptions';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number Formats Fields.
|
||||||
|
*/
|
||||||
|
export default function NumberFormatFields({
|
||||||
|
// #ownProps
|
||||||
|
onCancelClick,
|
||||||
|
}) {
|
||||||
|
const { isSubmitting } = useFormikContext();
|
||||||
|
return (
|
||||||
|
<Form>
|
||||||
|
<div className={'number-format__content'}>
|
||||||
|
{/*------------ Money formats -----------*/}
|
||||||
|
<FastField name={'format_money'}>
|
||||||
|
{({ form, field: { value }, meta: { error, touched } }) => (
|
||||||
|
<FormGroup
|
||||||
|
label={<T id={'money_format'} />}
|
||||||
|
helperText={<ErrorMessage name="format_money" />}
|
||||||
|
intent={inputIntent({ error, touched })}
|
||||||
|
className={classNames(CLASSES.FILL)}
|
||||||
|
>
|
||||||
|
<ListSelect
|
||||||
|
items={moneyFormat}
|
||||||
|
onItemSelect={(format) => {
|
||||||
|
form.setFieldValue('format_money', format.name);
|
||||||
|
}}
|
||||||
|
filterable={false}
|
||||||
|
selectedItem={value}
|
||||||
|
selectedItemProp={'id'}
|
||||||
|
textProp={'text'}
|
||||||
|
popoverProps={{ minimal: true, captureDismiss: true }}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
)}
|
||||||
|
</FastField>
|
||||||
|
{/*------------ Negative formats -----------*/}
|
||||||
|
<FastField name={'negative_format'}>
|
||||||
|
{({ form, field: { value }, meta: { error, touched } }) => (
|
||||||
|
<FormGroup
|
||||||
|
label={<T id={'negative_format'} />}
|
||||||
|
helperText={<ErrorMessage name="negative_format" />}
|
||||||
|
intent={inputIntent({ error, touched })}
|
||||||
|
className={classNames(CLASSES.FILL)}
|
||||||
|
>
|
||||||
|
<ListSelect
|
||||||
|
items={negativeFormat}
|
||||||
|
onItemSelect={(format) => {
|
||||||
|
form.setFieldValue('negative_format', format.name);
|
||||||
|
}}
|
||||||
|
filterable={false}
|
||||||
|
selectedItem={value}
|
||||||
|
selectedItemProp={'id'}
|
||||||
|
textProp={'text'}
|
||||||
|
popoverProps={{ minimal: true, captureDismiss: true }}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
)}
|
||||||
|
</FastField>
|
||||||
|
|
||||||
|
{/*------------ Decimal places -----------*/}
|
||||||
|
<FastField name={'precision'}>
|
||||||
|
{({ form, field: { value }, meta: { error, touched } }) => (
|
||||||
|
<FormGroup
|
||||||
|
label={<T id={'decimal_places'} />}
|
||||||
|
helperText={<ErrorMessage name="format_money" />}
|
||||||
|
intent={inputIntent({ error, touched })}
|
||||||
|
className={classNames(CLASSES.FILL)}
|
||||||
|
>
|
||||||
|
<ListSelect
|
||||||
|
items={decimalPlaces}
|
||||||
|
onItemSelect={(format) => {
|
||||||
|
form.setFieldValue('precision', format.key);
|
||||||
|
}}
|
||||||
|
filterable={false}
|
||||||
|
selectedItem={value}
|
||||||
|
selectedItemProp={'id'}
|
||||||
|
labelProp={'label'}
|
||||||
|
textProp={'text'}
|
||||||
|
popoverProps={{ minimal: true, captureDismiss: true }}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
)}
|
||||||
|
</FastField>
|
||||||
|
|
||||||
|
{/*------------ show zero -----------*/}
|
||||||
|
<FastField name={'show_zero'} type={'checkbox'}>
|
||||||
|
{({ field }) => (
|
||||||
|
<FormGroup inline={true}>
|
||||||
|
<Checkbox
|
||||||
|
inline={true}
|
||||||
|
label={<T id={'show_zero'} />}
|
||||||
|
name={'show_zero'}
|
||||||
|
{...field}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
)}
|
||||||
|
</FastField>
|
||||||
|
{/*------------ show negative in red-----------*/}
|
||||||
|
<FastField name={'show_in_red'} type={'checkbox'}>
|
||||||
|
{({ field }) => (
|
||||||
|
<FormGroup inline={true}>
|
||||||
|
<Checkbox
|
||||||
|
inline={true}
|
||||||
|
label={<T id={'show_negative_in_red'} />}
|
||||||
|
name={'show_in_red'}
|
||||||
|
{...field}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
)}
|
||||||
|
</FastField>
|
||||||
|
{/*------------ Divide on 1000 -----------*/}
|
||||||
|
<FastField name={'divide_on_1000'} type={'checkbox'}>
|
||||||
|
{({ field }) => (
|
||||||
|
<FormGroup inline={true}>
|
||||||
|
<Checkbox
|
||||||
|
inline={true}
|
||||||
|
label={<T id={'divide_on_1000'} />}
|
||||||
|
name={'divide_on_1000'}
|
||||||
|
{...field}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
)}
|
||||||
|
</FastField>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={classNames('number-format__footer', Classes.POPOVER_DISMISS)}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
className={'mr1'}
|
||||||
|
onClick={onCancelClick}
|
||||||
|
small={true}
|
||||||
|
style={{ minWidth: '75px' }}
|
||||||
|
>
|
||||||
|
<T id={'cancel'} />
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
intent={Intent.PRIMARY}
|
||||||
|
disabled={isSubmitting}
|
||||||
|
small={true}
|
||||||
|
style={{ minWidth: '75px' }}
|
||||||
|
type="submit"
|
||||||
|
>
|
||||||
|
<T id={'run'} />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
);
|
||||||
|
}
|
||||||
15
client/src/components/NumberFormats/NumberFormats.schema.js
Normal file
15
client/src/components/NumberFormats/NumberFormats.schema.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import * as Yup from 'yup';
|
||||||
|
import { DATATYPES_LENGTH } from 'common/dataTypes';
|
||||||
|
import { defaultTo } from 'lodash';
|
||||||
|
|
||||||
|
|
||||||
|
const Schema = Yup.object().shape({
|
||||||
|
format_money: Yup.string(),
|
||||||
|
show_zero: Yup.boolean(),
|
||||||
|
show_in_red: Yup.boolean(),
|
||||||
|
divide_on_1000: Yup.boolean(),
|
||||||
|
negative_format: Yup.string(),
|
||||||
|
precision: Yup.string(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const CreateNumberFormateSchema = Schema;
|
||||||
42
client/src/components/NumberFormats/index.js
Normal file
42
client/src/components/NumberFormats/index.js
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import React, { useState, useCallback, useMemo } from 'react';
|
||||||
|
import { Classes } from '@blueprintjs/core';
|
||||||
|
import { Formik } from 'formik';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import NumberFormatFields from './NumberFormatFields';
|
||||||
|
|
||||||
|
import { compose } from 'utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number format form popover content.
|
||||||
|
*/
|
||||||
|
function NumberFormats() {
|
||||||
|
const initialValues = useMemo(
|
||||||
|
() => ({
|
||||||
|
format_money: '',
|
||||||
|
show_zero: '',
|
||||||
|
show_in_red: '',
|
||||||
|
divide_on_1000: '',
|
||||||
|
negative_format: '',
|
||||||
|
precision: '',
|
||||||
|
}),
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
// Handle cancel button click.
|
||||||
|
const handleCancelClick = useCallback(() => {}, []);
|
||||||
|
|
||||||
|
// Handle form submit.
|
||||||
|
const handleFormSubmit = (values, { setSubmitting }) => {
|
||||||
|
setSubmitting(true);
|
||||||
|
const form = { ...values };
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={'number-format'}>
|
||||||
|
<Formik initialValues={initialValues} onSubmit={handleFormSubmit}>
|
||||||
|
<NumberFormatFields onCancelClick={handleCancelClick} />
|
||||||
|
</Formik>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default NumberFormats;
|
||||||
@@ -29,7 +29,7 @@ function PaymentReceiveListField({
|
|||||||
onItemSelect={onInvoiceSelect}
|
onItemSelect={onInvoiceSelect}
|
||||||
selectedItem={`${selectedInvoiceId}`}
|
selectedItem={`${selectedInvoiceId}`}
|
||||||
selectedItemProp={'id'}
|
selectedItemProp={'id'}
|
||||||
labelProp={'name'}
|
textProp={'name'}
|
||||||
defaultText={defaultSelectText}
|
defaultText={defaultSelectText}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export default function SalutationList({
|
|||||||
<ListSelect
|
<ListSelect
|
||||||
items={items}
|
items={items}
|
||||||
selectedItemProp={'key'}
|
selectedItemProp={'key'}
|
||||||
labelProp={'label'}
|
textProp={'label'}
|
||||||
defaultText={'Salutation'}
|
defaultText={'Salutation'}
|
||||||
filterable={false}
|
filterable={false}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
|
|||||||
@@ -1,21 +1,22 @@
|
|||||||
import React from 'react';
|
import React, { useRef } from 'react';
|
||||||
import { FastField, ErrorMessage } from 'formik';
|
import { FastField, ErrorMessage, useFormikContext } from 'formik';
|
||||||
import { FormGroup, InputGroup } from '@blueprintjs/core';
|
import { FormGroup, InputGroup, Intent } from '@blueprintjs/core';
|
||||||
import { Row, Col, FieldRequiredHint } from 'components';
|
|
||||||
import { inputIntent } from 'utils';
|
import { inputIntent } from 'utils';
|
||||||
|
import { Row, Col, If, FieldRequiredHint } from 'components';
|
||||||
import { FormattedMessage as T } from 'react-intl';
|
import { FormattedMessage as T } from 'react-intl';
|
||||||
|
import { decrementCalc, dec } from './utils';
|
||||||
|
|
||||||
function DecrementAdjustmentFields() {
|
function DecrementAdjustmentFields() {
|
||||||
return (
|
return (
|
||||||
<Row>
|
<Row>
|
||||||
{/*------------ Quantity on hand -----------*/}
|
{/*------------ Quantity on hand -----------*/}
|
||||||
<Col sm={3}>
|
<Col sm={3}>
|
||||||
<FastField name={'quantity'}>
|
<FastField name={'quantity_on_hand'}>
|
||||||
{({ field, meta: { error, touched } }) => (
|
{({ field, meta: { error, touched } }) => (
|
||||||
<FormGroup
|
<FormGroup
|
||||||
label={<T id={'qty_on_hand'} />}
|
label={<T id={'qty_on_hand'} />}
|
||||||
intent={inputIntent({ error, touched })}
|
intent={inputIntent({ error, touched })}
|
||||||
helperText={<ErrorMessage name="quantity" />}
|
helperText={<ErrorMessage name="quantity_on_hand" />}
|
||||||
>
|
>
|
||||||
<InputGroup disabled={true} medium={'true'} {...field} />
|
<InputGroup disabled={true} medium={'true'} {...field} />
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
@@ -24,15 +25,24 @@ function DecrementAdjustmentFields() {
|
|||||||
</Col>
|
</Col>
|
||||||
{/*------------ Decrement -----------*/}
|
{/*------------ Decrement -----------*/}
|
||||||
<Col sm={2}>
|
<Col sm={2}>
|
||||||
<FastField name={'decrement'}>
|
<FastField name={'quantity'}>
|
||||||
{({ field, meta: { error, touched } }) => (
|
{({
|
||||||
|
form: { values, setFieldValue },
|
||||||
|
field,
|
||||||
|
meta: { error, touched },
|
||||||
|
}) => (
|
||||||
<FormGroup
|
<FormGroup
|
||||||
label={<T id={'decrement'} />}
|
label={<T id={'decrement'} />}
|
||||||
intent={inputIntent({ error, touched })}
|
intent={inputIntent({ error, touched })}
|
||||||
helperText={<ErrorMessage name="decrement" />}
|
helperText={<ErrorMessage name="quantity" />}
|
||||||
fill={true}
|
fill={true}
|
||||||
>
|
>
|
||||||
<InputGroup medium={'true'} {...field} />
|
<InputGroup
|
||||||
|
{...field}
|
||||||
|
onBlur={(event) => {
|
||||||
|
setFieldValue('new_quantity', decrementCalc(values, event));
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
)}
|
)}
|
||||||
</FastField>
|
</FastField>
|
||||||
@@ -40,13 +50,22 @@ function DecrementAdjustmentFields() {
|
|||||||
{/*------------ New quantity -----------*/}
|
{/*------------ New quantity -----------*/}
|
||||||
<Col sm={4}>
|
<Col sm={4}>
|
||||||
<FastField name={'new_quantity'}>
|
<FastField name={'new_quantity'}>
|
||||||
{({ field, meta: { error, touched } }) => (
|
{({
|
||||||
|
form: { values, setFieldValue },
|
||||||
|
field,
|
||||||
|
meta: { error, touched },
|
||||||
|
}) => (
|
||||||
<FormGroup
|
<FormGroup
|
||||||
label={<T id={'new_quantity'} />}
|
label={<T id={'new_quantity'} />}
|
||||||
intent={inputIntent({ error, touched })}
|
intent={inputIntent({ error, touched })}
|
||||||
helperText={<ErrorMessage name="new_quantity" />}
|
helperText={<ErrorMessage name="new_quantity" />}
|
||||||
>
|
>
|
||||||
<InputGroup medium={'true'} {...field} />
|
<InputGroup
|
||||||
|
{...field}
|
||||||
|
onBlur={(event) => {
|
||||||
|
setFieldValue('quantity', decrementCalc(values, event));
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
)}
|
)}
|
||||||
</FastField>
|
</FastField>
|
||||||
|
|||||||
@@ -1,21 +1,22 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { FastField, ErrorMessage } from 'formik';
|
import { FastField, ErrorMessage, useFormikContext } from 'formik';
|
||||||
import { FormGroup, InputGroup, Intent } from '@blueprintjs/core';
|
import { FormGroup, InputGroup, Intent } from '@blueprintjs/core';
|
||||||
import { Row, Col, FieldRequiredHint } from 'components';
|
import { Row, Col, FieldRequiredHint } from 'components';
|
||||||
import { inputIntent } from 'utils';
|
import { inputIntent } from 'utils';
|
||||||
import { FormattedMessage as T } from 'react-intl';
|
import { FormattedMessage as T } from 'react-intl';
|
||||||
|
import { decrementCalc, incrementCalc } from './utils';
|
||||||
|
|
||||||
function IncrementAdjustmentFields() {
|
function IncrementAdjustmentFields() {
|
||||||
return (
|
return (
|
||||||
<Row>
|
<Row>
|
||||||
{/*------------ Quantity on hand -----------*/}
|
{/*------------ Quantity on hand -----------*/}
|
||||||
<Col sm={3}>
|
<Col sm={3}>
|
||||||
<FastField name={'quantity'}>
|
<FastField name={'quantity_on_hand'}>
|
||||||
{({ field, meta: { error, touched } }) => (
|
{({ field, meta: { error, touched } }) => (
|
||||||
<FormGroup
|
<FormGroup
|
||||||
label={<T id={'qty_on_hand'} />}
|
label={<T id={'qty_on_hand'} />}
|
||||||
intent={inputIntent({ error, touched })}
|
intent={inputIntent({ error, touched })}
|
||||||
helperText={<ErrorMessage name="quantity" />}
|
helperText={<ErrorMessage name="quantity_on_hand" />}
|
||||||
>
|
>
|
||||||
<InputGroup disabled={true} medium={'true'} {...field} />
|
<InputGroup disabled={true} medium={'true'} {...field} />
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
@@ -24,15 +25,24 @@ function IncrementAdjustmentFields() {
|
|||||||
</Col>
|
</Col>
|
||||||
{/*------------ Increment -----------*/}
|
{/*------------ Increment -----------*/}
|
||||||
<Col sm={2}>
|
<Col sm={2}>
|
||||||
<FastField name={'increment'}>
|
<FastField name={'quantity'}>
|
||||||
{({ field, meta: { error, touched } }) => (
|
{({
|
||||||
|
form: { values, setFieldValue },
|
||||||
|
field,
|
||||||
|
meta: { error, touched },
|
||||||
|
}) => (
|
||||||
<FormGroup
|
<FormGroup
|
||||||
label={<T id={'increment'} />}
|
label={<T id={'increment'} />}
|
||||||
intent={inputIntent({ error, touched })}
|
intent={inputIntent({ error, touched })}
|
||||||
helperText={<ErrorMessage name="increment" />}
|
helperText={<ErrorMessage name="quantity" />}
|
||||||
fill={true}
|
fill={true}
|
||||||
>
|
>
|
||||||
<InputGroup medium={'true'} {...field} />
|
<InputGroup
|
||||||
|
{...field}
|
||||||
|
onBlur={(event) => {
|
||||||
|
setFieldValue('new_quantity', incrementCalc(values, event));
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
)}
|
)}
|
||||||
</FastField>
|
</FastField>
|
||||||
@@ -54,13 +64,22 @@ function IncrementAdjustmentFields() {
|
|||||||
{/*------------ New quantity -----------*/}
|
{/*------------ New quantity -----------*/}
|
||||||
<Col sm={4}>
|
<Col sm={4}>
|
||||||
<FastField name={'new_quantity'}>
|
<FastField name={'new_quantity'}>
|
||||||
{({ field, meta: { error, touched } }) => (
|
{({
|
||||||
|
form: { values, setFieldValue },
|
||||||
|
field,
|
||||||
|
meta: { error, touched },
|
||||||
|
}) => (
|
||||||
<FormGroup
|
<FormGroup
|
||||||
label={<T id={'new_quantity'} />}
|
label={<T id={'new_quantity'} />}
|
||||||
intent={inputIntent({ error, touched })}
|
intent={inputIntent({ error, touched })}
|
||||||
helperText={<ErrorMessage name="new_quantity" />}
|
helperText={<ErrorMessage name="new_quantity" />}
|
||||||
>
|
>
|
||||||
<InputGroup medium={'true'} {...field} />
|
<InputGroup
|
||||||
|
{...field}
|
||||||
|
onBlur={(event) => {
|
||||||
|
setFieldValue('quantity', decrementCalc(values, event));
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
)}
|
)}
|
||||||
</FastField>
|
</FastField>
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Intent, Button, Classes } from '@blueprintjs/core';
|
||||||
|
import { useFormikContext } from 'formik';
|
||||||
|
import { FormattedMessage as T } from 'react-intl';
|
||||||
|
import { saveInvoke } from 'utils';
|
||||||
|
|
||||||
|
export default function InventoryAdjustmentFloatingActions({
|
||||||
|
onCloseClick,
|
||||||
|
onSubmitClick,
|
||||||
|
}) {
|
||||||
|
const { isSubmitting } = useFormikContext();
|
||||||
|
|
||||||
|
const handleSubmitDraftBtnClick = (event) => {
|
||||||
|
saveInvoke(onSubmitClick, event, {
|
||||||
|
publish: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const handleSubmitMakeAdjustmentBtnClick = (event) => {
|
||||||
|
saveInvoke(onSubmitClick, event, {
|
||||||
|
publish: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={Classes.DIALOG_FOOTER}>
|
||||||
|
<div className={Classes.DIALOG_FOOTER_ACTIONS}>
|
||||||
|
<Button onClick={onCloseClick} style={{ minWidth: '75px' }}>
|
||||||
|
<T id={'close'} />
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
disabled={isSubmitting}
|
||||||
|
style={{ minWidth: '75px' }}
|
||||||
|
type="submit"
|
||||||
|
onClick={handleSubmitDraftBtnClick}
|
||||||
|
>
|
||||||
|
{<T id={'save_as_draft'} />}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
intent={Intent.PRIMARY}
|
||||||
|
disabled={isSubmitting}
|
||||||
|
style={{ minWidth: '75px' }}
|
||||||
|
type="submit"
|
||||||
|
onClick={handleSubmitMakeAdjustmentBtnClick}
|
||||||
|
>
|
||||||
|
{<T id={'make_adjustment'} />}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -6,22 +6,25 @@ const Schema = Yup.object().shape({
|
|||||||
date: Yup.date()
|
date: Yup.date()
|
||||||
.required()
|
.required()
|
||||||
.label(formatMessage({ id: 'date' })),
|
.label(formatMessage({ id: 'date' })),
|
||||||
type: Yup.number().required(),
|
type: Yup.string().required(),
|
||||||
adjustment_account_id: Yup.number().required(),
|
adjustment_account_id: Yup.string().required(),
|
||||||
|
item_id: Yup.number().required(),
|
||||||
reason: Yup.string()
|
reason: Yup.string()
|
||||||
.required()
|
.required()
|
||||||
.label(formatMessage({ id: 'reason' })),
|
.label(formatMessage({ id: 'reason' })),
|
||||||
quantity: Yup.number().when(['type'], {
|
quantity_on_hand: Yup.number()
|
||||||
is: (type) => type,
|
.min(0)
|
||||||
then: Yup.number().required(),
|
.required()
|
||||||
}),
|
.label(formatMessage({ id: 'qty' })),
|
||||||
|
quantity: Yup.number().integer().max(Yup.ref('quantity_on_hand')).required(),
|
||||||
cost: Yup.number().when(['type'], {
|
cost: Yup.number().when(['type'], {
|
||||||
is: (type) => type,
|
is: (type) => type,
|
||||||
then: Yup.number().required(),
|
then: Yup.number(),
|
||||||
}),
|
}),
|
||||||
reference_no: Yup.string(),
|
reference_no: Yup.string(),
|
||||||
new_quantity: Yup.number(),
|
new_quantity: Yup.number().min(Yup.ref('quantity')).required(),
|
||||||
description: Yup.string().min(3).max(DATATYPES_LENGTH.TEXT).nullable().trim(),
|
description: Yup.string().min(3).max(DATATYPES_LENGTH.TEXT).nullable().trim(),
|
||||||
|
publish: Yup.boolean(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const CreateInventoryAdjustmentFormSchema = Schema;
|
export const CreateInventoryAdjustmentFormSchema = Schema;
|
||||||
|
|||||||
@@ -1,33 +1,31 @@
|
|||||||
import React, { useCallback, useMemo } from 'react';
|
import React, { useState, useCallback, useMemo } from 'react';
|
||||||
import { Intent } from '@blueprintjs/core';
|
import { Intent } from '@blueprintjs/core';
|
||||||
import { Formik } from 'formik';
|
import { Formik, Form } from 'formik';
|
||||||
import { FormattedMessage as T, useIntl } from 'react-intl';
|
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||||
import { useQuery, queryCache } from 'react-query';
|
import { useQuery, queryCache } from 'react-query';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { omit } from 'lodash';
|
import { omit } from 'lodash';
|
||||||
|
|
||||||
import {
|
import { AppToaster, DialogContent } from 'components';
|
||||||
AppToaster,
|
|
||||||
DialogContent,
|
|
||||||
Row,
|
|
||||||
Col,
|
|
||||||
ListSelect,
|
|
||||||
IF,
|
|
||||||
} from 'components';
|
|
||||||
import { CreateInventoryAdjustmentFormSchema } from './InventoryAdjustmentForm.schema';
|
import { CreateInventoryAdjustmentFormSchema } from './InventoryAdjustmentForm.schema';
|
||||||
import InventoryAdjustmentFormDialogFields from './InventoryAdjustmentFormDialogFields';
|
import InventoryAdjustmentFormDialogFields from './InventoryAdjustmentFormDialogFields';
|
||||||
|
import InventoryAdjustmentFloatingActions from './InventoryAdjustmentFloatingActions';
|
||||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||||
|
import withInventoryAdjustmentActions from 'containers/Items/withInventoryAdjustmentActions';
|
||||||
import { compose } from 'utils';
|
import { compose } from 'utils';
|
||||||
|
|
||||||
const defaultInitialValues = {
|
const defaultInitialValues = {
|
||||||
date: moment(new Date()).format('YYYY-MM-DD'),
|
date: moment(new Date()).format('YYYY-MM-DD'),
|
||||||
type: 'decrement',
|
type: 'decrement',
|
||||||
adjustment_account_id: '',
|
adjustment_account_id: '',
|
||||||
|
item_id: '',
|
||||||
reason: '',
|
reason: '',
|
||||||
|
cost: '',
|
||||||
|
quantity: '',
|
||||||
reference_no: '',
|
reference_no: '',
|
||||||
|
quantity_on_hand: '',
|
||||||
description: '',
|
description: '',
|
||||||
|
publish: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -40,31 +38,38 @@ function InventoryAdjustmentFormDialogContent({
|
|||||||
// #withAccountsActions
|
// #withAccountsActions
|
||||||
requestFetchAccounts,
|
requestFetchAccounts,
|
||||||
|
|
||||||
|
// #withInventoryAdjustmentActions
|
||||||
|
requestSubmitInventoryAdjustment,
|
||||||
|
|
||||||
// #ownProp
|
// #ownProp
|
||||||
|
itemDetail,
|
||||||
dialogName,
|
dialogName,
|
||||||
action,
|
|
||||||
}) {
|
}) {
|
||||||
const { formatMessage } = useIntl();
|
const { formatMessage } = useIntl();
|
||||||
|
const [submitPayload, setSubmitPayload] = useState({});
|
||||||
|
|
||||||
// Fetches accounts list.
|
// Fetches accounts list.
|
||||||
const fetchAccountsList = useQuery('accounts-list', () =>
|
const fetchAccount = useQuery('accounts-list', () => requestFetchAccounts());
|
||||||
requestFetchAccounts(),
|
|
||||||
);
|
|
||||||
|
|
||||||
const initialValues = useMemo(
|
const initialValues = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
...defaultInitialValues,
|
...defaultInitialValues,
|
||||||
|
...itemDetail,
|
||||||
}),
|
}),
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Handles the form submit.
|
// Handles the form submit.
|
||||||
const handleFormSubmit = (values, { setSubmitting, setErrors }) => {
|
const handleFormSubmit = (values, { setSubmitting, setErrors }) => {
|
||||||
const form = { ...values };
|
const form = {
|
||||||
|
...omit(values, ['quantity_on_hand', 'new_quantity', 'action']),
|
||||||
|
publish: submitPayload.publish,
|
||||||
|
};
|
||||||
|
|
||||||
const onSuccess = ({ response }) => {
|
const onSuccess = ({ response }) => {
|
||||||
closeDialog(dialogName);
|
closeDialog(dialogName);
|
||||||
queryCache.invalidateQueries('accounts-list');
|
queryCache.invalidateQueries('accounts-list');
|
||||||
|
queryCache.invalidateQueries('items-table');
|
||||||
|
|
||||||
AppToaster.show({
|
AppToaster.show({
|
||||||
message: formatMessage({
|
message: formatMessage({
|
||||||
@@ -76,14 +81,21 @@ function InventoryAdjustmentFormDialogContent({
|
|||||||
const onError = (error) => {
|
const onError = (error) => {
|
||||||
setSubmitting(false);
|
setSubmitting(false);
|
||||||
};
|
};
|
||||||
//requestInventoryAdjustment
|
requestSubmitInventoryAdjustment({ form }).then(onSuccess).catch(onError);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handles dialog close.
|
// Handles dialog close.
|
||||||
const handleClose = useCallback(() => {
|
const handleCloseClick = useCallback(() => {
|
||||||
closeDialog(dialogName);
|
closeDialog(dialogName);
|
||||||
}, [closeDialog, dialogName]);
|
}, [closeDialog, dialogName]);
|
||||||
|
|
||||||
|
const handleSubmitClick = useCallback(
|
||||||
|
(event, payload) => {
|
||||||
|
setSubmitPayload({ ...payload });
|
||||||
|
},
|
||||||
|
[setSubmitPayload],
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<Formik
|
<Formik
|
||||||
@@ -91,13 +103,19 @@ function InventoryAdjustmentFormDialogContent({
|
|||||||
initialValues={initialValues}
|
initialValues={initialValues}
|
||||||
onSubmit={handleFormSubmit}
|
onSubmit={handleFormSubmit}
|
||||||
>
|
>
|
||||||
<InventoryAdjustmentFormDialogFields
|
<Form>
|
||||||
dialogName={dialogName}
|
<InventoryAdjustmentFormDialogFields dialogName={dialogName} />
|
||||||
onClose={handleClose}
|
<InventoryAdjustmentFloatingActions
|
||||||
/>
|
onSubmitClick={handleSubmitClick}
|
||||||
|
onCloseClick={handleCloseClick}
|
||||||
|
/>
|
||||||
|
</Form>
|
||||||
</Formik>
|
</Formik>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default compose(withDialogActions)(InventoryAdjustmentFormDialogContent);
|
export default compose(
|
||||||
|
withInventoryAdjustmentActions,
|
||||||
|
withDialogActions,
|
||||||
|
)(InventoryAdjustmentFormDialogContent);
|
||||||
|
|||||||
@@ -1,22 +1,14 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { FastField, ErrorMessage, useFormikContext } from 'formik';
|
||||||
import {
|
import {
|
||||||
Form,
|
|
||||||
FastField,
|
|
||||||
ErrorMessage,
|
|
||||||
useFormikContext,
|
|
||||||
useField,
|
|
||||||
} from 'formik';
|
|
||||||
import {
|
|
||||||
Button,
|
|
||||||
Classes,
|
Classes,
|
||||||
FormGroup,
|
FormGroup,
|
||||||
InputGroup,
|
InputGroup,
|
||||||
Intent,
|
|
||||||
TextArea,
|
TextArea,
|
||||||
Position,
|
Position,
|
||||||
} from '@blueprintjs/core';
|
} from '@blueprintjs/core';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { FormattedMessage as T } from 'react-intl';
|
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||||
import { DateInput } from '@blueprintjs/datetime';
|
import { DateInput } from '@blueprintjs/datetime';
|
||||||
import { ListSelect, Choose, If, FieldRequiredHint } from 'components';
|
import { ListSelect, Choose, If, FieldRequiredHint } from 'components';
|
||||||
import {
|
import {
|
||||||
@@ -30,166 +22,149 @@ import adjustmentType from 'common/adjustmentType';
|
|||||||
import IncrementAdjustmentFields from './IncrementAdjustmentFields';
|
import IncrementAdjustmentFields from './IncrementAdjustmentFields';
|
||||||
import DecrementAdjustmentFields from './DecrementAdjustmentFields';
|
import DecrementAdjustmentFields from './DecrementAdjustmentFields';
|
||||||
import AccountsSuggestField from 'components/AccountsSuggestField';
|
import AccountsSuggestField from 'components/AccountsSuggestField';
|
||||||
|
|
||||||
import withAccounts from 'containers/Accounts/withAccounts';
|
import withAccounts from 'containers/Accounts/withAccounts';
|
||||||
import { compose } from 'redux';
|
import { compose } from 'redux';
|
||||||
|
import { decrementCalc, incrementCalc, dec } from './utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inventory adjustment form dialogs fields.
|
* Inventory adjustment form dialogs fields.
|
||||||
*/
|
*/
|
||||||
function InventoryAdjustmentFormDialogFields({
|
function InventoryAdjustmentFormDialogFields({
|
||||||
// #ownProps
|
|
||||||
onClose,
|
|
||||||
|
|
||||||
//# withAccount
|
//# withAccount
|
||||||
accountsList,
|
accountsList,
|
||||||
}) {
|
}) {
|
||||||
const { values, isSubmitting } = useFormikContext();
|
const { values } = useFormikContext();
|
||||||
|
const { formatMessage } = useIntl();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form>
|
<div className={Classes.DIALOG_BODY}>
|
||||||
<div className={Classes.DIALOG_BODY}>
|
{/*------------ Date -----------*/}
|
||||||
{/*------------ Date -----------*/}
|
<FastField name={'date'}>
|
||||||
<FastField name={'date'}>
|
{({ form, field: { value }, meta: { error, touched } }) => (
|
||||||
{({ form, field: { value }, meta: { error, touched } }) => (
|
<FormGroup
|
||||||
<FormGroup
|
label={<T id={'date'} />}
|
||||||
label={<T id={'date'} />}
|
labelInfo={<FieldRequiredHint />}
|
||||||
labelInfo={<FieldRequiredHint />}
|
intent={inputIntent({ error, touched })}
|
||||||
intent={inputIntent({ error, touched })}
|
helperText={<ErrorMessage name="date" />}
|
||||||
helperText={<ErrorMessage name="date" />}
|
minimal={true}
|
||||||
minimal={true}
|
className={classNames(CLASSES.FILL)}
|
||||||
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'} />}
|
<DateInput
|
||||||
</Button>
|
{...momentFormatter('YYYY/MM/DD')}
|
||||||
<Button
|
onChange={handleDateChange((formattedDate) => {
|
||||||
intent={Intent.PRIMARY}
|
form.setFieldValue('date', formattedDate);
|
||||||
disabled={isSubmitting}
|
})}
|
||||||
style={{ minWidth: '75px' }}
|
value={tansformDateValue(value)}
|
||||||
type="submit"
|
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)}
|
||||||
>
|
>
|
||||||
{<T id={'make_adjustment'} />}
|
<ListSelect
|
||||||
</Button>
|
items={adjustmentType}
|
||||||
</div>
|
onItemSelect={(type) => {
|
||||||
</div>
|
form.setFieldValue('type', type.value);
|
||||||
</Form>
|
type?.value == 'increment'
|
||||||
|
? form.setFieldValue('new_quantity', incrementCalc(values))
|
||||||
|
: form.setFieldValue(
|
||||||
|
'new_quantity',
|
||||||
|
values.quantity_on_hand - values.quantity,
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
filterable={false}
|
||||||
|
selectedItem={value}
|
||||||
|
selectedItemProp={'value'}
|
||||||
|
textProp={'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.id)
|
||||||
|
}
|
||||||
|
inputProps={{
|
||||||
|
placeholder: formatMessage({
|
||||||
|
id: 'select_adjustment_account',
|
||||||
|
}),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ function InventoryAdjustmentFormDialog({
|
|||||||
<DialogSuspense>
|
<DialogSuspense>
|
||||||
<InventoryAdjustmentFormDialogContent
|
<InventoryAdjustmentFormDialogContent
|
||||||
dialogName={dialogName}
|
dialogName={dialogName}
|
||||||
action={payload.action}
|
itemDetail={payload}
|
||||||
/>
|
/>
|
||||||
</DialogSuspense>
|
</DialogSuspense>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
export const decrementCalc = ({ quantity_on_hand, type }, e) => {
|
||||||
|
if (type == 'decrement') {
|
||||||
|
return parseInt(quantity_on_hand, 10) - parseInt(e.currentTarget.value, 10);
|
||||||
|
} else {
|
||||||
|
return e.currentTarget.value - quantity_on_hand;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const incrementCalc = ({ quantity_on_hand, quantity }, e) => {
|
||||||
|
return parseInt(quantity_on_hand, 10) + parseInt(quantity, 10);
|
||||||
|
};
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import React from 'react';
|
import React, { useState } from 'react';
|
||||||
import {
|
import {
|
||||||
NavbarGroup,
|
NavbarGroup,
|
||||||
Button,
|
Button,
|
||||||
@@ -13,6 +13,7 @@ import classNames from 'classnames';
|
|||||||
|
|
||||||
import Icon from 'components/Icon';
|
import Icon from 'components/Icon';
|
||||||
import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar';
|
import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar';
|
||||||
|
import NumberFormats from 'components/NumberFormats';
|
||||||
|
|
||||||
import { compose } from 'utils';
|
import { compose } from 'utils';
|
||||||
import withBalanceSheetDetail from './withBalanceSheetDetail';
|
import withBalanceSheetDetail from './withBalanceSheetDetail';
|
||||||
@@ -72,6 +73,18 @@ function BalanceSheetActionsBar({
|
|||||||
icon={<Icon icon="filter-16" iconSize={16} />}
|
icon={<Icon icon="filter-16" iconSize={16} />}
|
||||||
/>
|
/>
|
||||||
</Popover>
|
</Popover>
|
||||||
|
<Popover
|
||||||
|
content={<NumberFormats />}
|
||||||
|
minimal={true}
|
||||||
|
interactionKind={PopoverInteractionKind.CLICK}
|
||||||
|
position={Position.BOTTOM_LEFT}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
className={classNames(Classes.MINIMAL, 'button--filter')}
|
||||||
|
text={<T id={'format'} />}
|
||||||
|
icon={<Icon icon="filter-16" iconSize={16} />}
|
||||||
|
/>
|
||||||
|
</Popover>
|
||||||
|
|
||||||
<NavbarDivider />
|
<NavbarDivider />
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ export default function FinancialAccountsFilter({ ...restProps }) {
|
|||||||
filterable={false}
|
filterable={false}
|
||||||
selectedItem={value}
|
selectedItem={value}
|
||||||
selectedItemProp={'key'}
|
selectedItemProp={'key'}
|
||||||
labelProp={'name'}
|
textProp={'name'}
|
||||||
onItemSelect={(item) => {
|
onItemSelect={(item) => {
|
||||||
setFieldValue('accountsFilter', item.key);
|
setFieldValue('accountsFilter', item.key);
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ export default function SelectsListColumnsBy(props) {
|
|||||||
filterable={false}
|
filterable={false}
|
||||||
selectedItem={value}
|
selectedItem={value}
|
||||||
selectedItemProp={'key'}
|
selectedItemProp={'key'}
|
||||||
labelProp={'name'}
|
textProp={'name'}
|
||||||
onItemSelect={(item) => {
|
onItemSelect={(item) => {
|
||||||
form.setFieldValue('displayColumnsType', item.key);
|
form.setFieldValue('displayColumnsType', item.key);
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -7,38 +7,42 @@ import {
|
|||||||
MenuItem,
|
MenuItem,
|
||||||
MenuDivider,
|
MenuDivider,
|
||||||
Position,
|
Position,
|
||||||
|
Tag,
|
||||||
} from '@blueprintjs/core';
|
} from '@blueprintjs/core';
|
||||||
import { FormattedMessage as T, useIntl } from 'react-intl';
|
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import {
|
import { DataTable, Icon, LoadingIndicator } from 'components';
|
||||||
DataTable,
|
|
||||||
If,
|
|
||||||
Money,
|
|
||||||
Choose,
|
|
||||||
Icon,
|
|
||||||
LoadingIndicator,
|
|
||||||
} from 'components';
|
|
||||||
import { CLASSES } from 'common/classes';
|
import { CLASSES } from 'common/classes';
|
||||||
import { useIsValuePassed } from 'hooks';
|
import { useIsValuePassed } from 'hooks';
|
||||||
|
|
||||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||||
// withInventoryAdjustments
|
import withInventoryAdjustments from './withInventoryAdjustments';
|
||||||
// withInventoryAdjustmentsActions
|
import withInventoryAdjustmentActions from './withInventoryAdjustmentActions';
|
||||||
|
|
||||||
import { compose, saveInvoke } from 'utils';
|
import { compose, saveInvoke } from 'utils';
|
||||||
import { withRouter } from 'react-router-dom';
|
import { withRouter } from 'react-router-dom';
|
||||||
|
|
||||||
function InventoryAdjustmentDataTable({
|
function InventoryAdjustmentDataTable({
|
||||||
|
// withInventoryAdjustments
|
||||||
|
inventoryAdjustmentItems,
|
||||||
|
inventoryAdjustmentCurrentPage,
|
||||||
|
inventoryAdjustmentLoading,
|
||||||
|
inventoryAdjustmentsPagination,
|
||||||
|
|
||||||
|
// withInventoryAdjustmentsActions
|
||||||
|
addInventoryAdjustmentTableQueries,
|
||||||
|
|
||||||
// #ownProps
|
// #ownProps
|
||||||
onDeleteInventoryAdjustment,
|
onDeleteInventoryAdjustment,
|
||||||
onSelectedRowsChange,
|
onSelectedRowsChange,
|
||||||
}) {
|
}) {
|
||||||
const { formatMessage } = useIntl();
|
const { formatMessage } = useIntl();
|
||||||
|
const isLoadedBefore = useIsValuePassed(inventoryAdjustmentLoading, false);
|
||||||
|
|
||||||
const handleDeleteInventoryAdjustment = useCallback(
|
const handleDeleteInventoryAdjustment = useCallback(
|
||||||
(_inventory) => {
|
(_adjustment) => () => {
|
||||||
saveInvoke(onDeleteInventoryAdjustment, _inventory);
|
saveInvoke(onDeleteInventoryAdjustment, _adjustment);
|
||||||
},
|
},
|
||||||
[onDeleteInventoryAdjustment],
|
[onDeleteInventoryAdjustment],
|
||||||
);
|
);
|
||||||
@@ -53,9 +57,9 @@ function InventoryAdjustmentDataTable({
|
|||||||
<MenuDivider />
|
<MenuDivider />
|
||||||
<MenuItem
|
<MenuItem
|
||||||
text={formatMessage({ id: 'delete_adjustment' })}
|
text={formatMessage({ id: 'delete_adjustment' })}
|
||||||
icon={<Icon icon="trash-16" iconSize={16} />}
|
|
||||||
intent={Intent.DANGER}
|
intent={Intent.DANGER}
|
||||||
onClick={handleDeleteInventoryAdjustment(adjustment)}
|
onClick={handleDeleteInventoryAdjustment(adjustment)}
|
||||||
|
icon={<Icon icon="trash-16" iconSize={16} />}
|
||||||
/>
|
/>
|
||||||
</Menu>
|
</Menu>
|
||||||
),
|
),
|
||||||
@@ -79,41 +83,53 @@ function InventoryAdjustmentDataTable({
|
|||||||
{
|
{
|
||||||
id: 'type',
|
id: 'type',
|
||||||
Header: formatMessage({ id: 'type' }),
|
Header: formatMessage({ id: 'type' }),
|
||||||
accessor: 'type',
|
accessor: (row) =>
|
||||||
|
row.type ? (
|
||||||
|
<Tag minimal={true} round={true} intent={Intent.NONE}>
|
||||||
|
{formatMessage({ id: row.type })}
|
||||||
|
</Tag>
|
||||||
|
) : (
|
||||||
|
''
|
||||||
|
),
|
||||||
className: 'type',
|
className: 'type',
|
||||||
width: 100,
|
width: 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'reason',
|
id: 'reason',
|
||||||
Header: formatMessage({ id: 'reason' }),
|
Header: formatMessage({ id: 'reason' }),
|
||||||
// accessor: (r) => (
|
accessor: 'reason',
|
||||||
// <Tooltip
|
|
||||||
// content={}
|
|
||||||
// position={Position.RIGHT_BOTTOM}
|
|
||||||
// >
|
|
||||||
// </Tooltip>
|
|
||||||
// ),
|
|
||||||
className: 'reason',
|
className: 'reason',
|
||||||
width: 115,
|
width: 115,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'reference',
|
id: 'reference_no',
|
||||||
Header: formatMessage({ id: 'reference' }),
|
Header: formatMessage({ id: 'reference_no' }),
|
||||||
accessor: (row) => `#${row.reference}`,
|
accessor: 'reference_no',
|
||||||
className: 'reference',
|
className: 'reference_no',
|
||||||
width: 100,
|
width: 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'status',
|
id: 'publish',
|
||||||
Header: formatMessage({ id: 'status' }),
|
Header: formatMessage({ id: 'status' }),
|
||||||
accessor: 'status',
|
accessor: (r) => {
|
||||||
|
return r.is_published ? (
|
||||||
|
<Tag minimal={true}>
|
||||||
|
<T id={'published'} />
|
||||||
|
</Tag>
|
||||||
|
) : (
|
||||||
|
<Tag minimal={true} intent={Intent.WARNING}>
|
||||||
|
<T id={'draft'} />
|
||||||
|
</Tag>
|
||||||
|
);
|
||||||
|
},
|
||||||
width: 95,
|
width: 95,
|
||||||
className: 'status',
|
className: 'publish',
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
id: 'description',
|
id: 'description',
|
||||||
Header: formatMessage({ id: 'description' }),
|
Header: formatMessage({ id: 'description' }),
|
||||||
|
accessor: 'description',
|
||||||
disableSorting: true,
|
disableSorting: true,
|
||||||
width: 85,
|
width: 85,
|
||||||
className: 'description',
|
className: 'description',
|
||||||
@@ -144,6 +160,23 @@ function InventoryAdjustmentDataTable({
|
|||||||
[actionMenuList, formatMessage],
|
[actionMenuList, formatMessage],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleDataTableFetchData = useCallback(
|
||||||
|
({ pageSize, pageIndex, sortBy }) => {
|
||||||
|
addInventoryAdjustmentTableQueries({
|
||||||
|
...(sortBy.length > 0
|
||||||
|
? {
|
||||||
|
column_sort_by: sortBy[0].id,
|
||||||
|
sort_order: sortBy[0].desc ? 'desc' : 'asc',
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
|
page_size: pageSize,
|
||||||
|
page: pageIndex + 1,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[addInventoryAdjustmentTableQueries],
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
const handleSelectedRowsChange = useCallback(
|
const handleSelectedRowsChange = useCallback(
|
||||||
(selectedRows) => {
|
(selectedRows) => {
|
||||||
saveInvoke(
|
saveInvoke(
|
||||||
@@ -160,11 +193,23 @@ function InventoryAdjustmentDataTable({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classNames(CLASSES.DASHBOARD_DATATABLE)}>
|
<div className={classNames(CLASSES.DASHBOARD_DATATABLE)}>
|
||||||
<LoadingIndicator
|
<LoadingIndicator loading={inventoryAdjustmentLoading && !isLoadedBefore}>
|
||||||
|
<DataTable
|
||||||
// loading={}
|
columns={columns}
|
||||||
>
|
data={inventoryAdjustmentItems}
|
||||||
<DataTable noInitialFetch={true} columns={columns} data={[]} />
|
onFetchData={handleDataTableFetchData}
|
||||||
|
manualSortBy={true}
|
||||||
|
selectionColumn={true}
|
||||||
|
noInitialFetch={true}
|
||||||
|
onSelectedRowsChange={handleSelectedRowsChange}
|
||||||
|
rowContextMenu={onRowContextMenu}
|
||||||
|
pagination={true}
|
||||||
|
autoResetSortBy={false}
|
||||||
|
autoResetPage={false}
|
||||||
|
pagesCount={inventoryAdjustmentsPagination.pagesCount}
|
||||||
|
initialPageSize={inventoryAdjustmentsPagination.pageSize}
|
||||||
|
initialPageIndex={inventoryAdjustmentsPagination.page - 1}
|
||||||
|
/>
|
||||||
</LoadingIndicator>
|
</LoadingIndicator>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -173,4 +218,18 @@ function InventoryAdjustmentDataTable({
|
|||||||
export default compose(
|
export default compose(
|
||||||
withRouter,
|
withRouter,
|
||||||
withDialogActions,
|
withDialogActions,
|
||||||
|
withInventoryAdjustmentActions,
|
||||||
|
withInventoryAdjustments(
|
||||||
|
({
|
||||||
|
inventoryAdjustmentLoading,
|
||||||
|
inventoryAdjustmentItems,
|
||||||
|
inventoryAdjustmentCurrentPage,
|
||||||
|
inventoryAdjustmentsPagination,
|
||||||
|
}) => ({
|
||||||
|
inventoryAdjustmentLoading,
|
||||||
|
inventoryAdjustmentItems,
|
||||||
|
inventoryAdjustmentCurrentPage,
|
||||||
|
inventoryAdjustmentsPagination,
|
||||||
|
}),
|
||||||
|
),
|
||||||
)(InventoryAdjustmentDataTable);
|
)(InventoryAdjustmentDataTable);
|
||||||
|
|||||||
@@ -3,13 +3,15 @@ import { useQuery } from 'react-query';
|
|||||||
import { Alert, Intent } from '@blueprintjs/core';
|
import { Alert, Intent } from '@blueprintjs/core';
|
||||||
import { FormattedMessage as T, useIntl } from 'react-intl';
|
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||||
|
|
||||||
|
import AppToaster from 'components/AppToaster';
|
||||||
import DashboardPageContent from 'components/Dashboard/DashboardPageContent';
|
import DashboardPageContent from 'components/Dashboard/DashboardPageContent';
|
||||||
import DashboardInsider from 'components/Dashboard/DashboardInsider';
|
import DashboardInsider from 'components/Dashboard/DashboardInsider';
|
||||||
|
|
||||||
import InventoryAdjustmentDataTable from './InventoryAdjustmentDataTable';
|
import InventoryAdjustmentDataTable from './InventoryAdjustmentDataTable';
|
||||||
|
import withInventoryAdjustmentActions from './withInventoryAdjustmentActions';
|
||||||
|
import withInventoryAdjustments from './withInventoryAdjustments';
|
||||||
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
|
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
|
||||||
//withInventoryAdjustmentsActions
|
|
||||||
import { compose } from 'utils';
|
import { compose } from 'utils';
|
||||||
import { Route, Switch } from 'react-router-dom';
|
import { Route, Switch } from 'react-router-dom';
|
||||||
|
|
||||||
@@ -19,7 +21,13 @@ import { Route, Switch } from 'react-router-dom';
|
|||||||
function InventoryAdjustmentList({
|
function InventoryAdjustmentList({
|
||||||
// #withDashboardActions
|
// #withDashboardActions
|
||||||
changePageTitle,
|
changePageTitle,
|
||||||
|
|
||||||
|
// #withInventoryAdjustments
|
||||||
|
inventoryAdjustmentTableQuery,
|
||||||
|
|
||||||
// #withInventoryAdjustmentsActions
|
// #withInventoryAdjustmentsActions
|
||||||
|
requestFetchInventoryAdjustmentTable,
|
||||||
|
requestDeleteInventoryAdjustment,
|
||||||
}) {
|
}) {
|
||||||
const { formatMessage } = useIntl();
|
const { formatMessage } = useIntl();
|
||||||
const [selectedRows, setSelectedRows] = useState([]);
|
const [selectedRows, setSelectedRows] = useState([]);
|
||||||
@@ -32,8 +40,8 @@ function InventoryAdjustmentList({
|
|||||||
}, [changePageTitle, formatMessage]);
|
}, [changePageTitle, formatMessage]);
|
||||||
|
|
||||||
const fetchInventoryAdjustments = useQuery(
|
const fetchInventoryAdjustments = useQuery(
|
||||||
['inventory-adjustment-list'],
|
['inventory-adjustment-list' ,inventoryAdjustmentTableQuery],
|
||||||
() => {},
|
(key, query) => requestFetchInventoryAdjustmentTable({ ...query }),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Handle selected rows change.
|
// Handle selected rows change.
|
||||||
@@ -55,7 +63,25 @@ function InventoryAdjustmentList({
|
|||||||
setDeleteInventoryAdjustment(false);
|
setDeleteInventoryAdjustment(false);
|
||||||
}, [setDeleteInventoryAdjustment]);
|
}, [setDeleteInventoryAdjustment]);
|
||||||
|
|
||||||
const handleConfirmInventoryAdjustmentDelete = useCallback(() => {}, []);
|
const handleConfirmInventoryAdjustmentDelete = useCallback(() => {
|
||||||
|
requestDeleteInventoryAdjustment(deleteInventoryAdjustment.id)
|
||||||
|
.then(() => {
|
||||||
|
setDeleteInventoryAdjustment(false);
|
||||||
|
AppToaster.show({
|
||||||
|
message: formatMessage({
|
||||||
|
id: 'the_adjustment_has_been_successfully_deleted',
|
||||||
|
}),
|
||||||
|
intent: Intent.SUCCESS,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((errors) => {
|
||||||
|
setDeleteInventoryAdjustment(false);
|
||||||
|
});
|
||||||
|
}, [
|
||||||
|
deleteInventoryAdjustment,
|
||||||
|
requestDeleteInventoryAdjustment,
|
||||||
|
formatMessage,
|
||||||
|
]);
|
||||||
|
|
||||||
// Calculates the data table selected rows count.
|
// Calculates the data table selected rows count.
|
||||||
const selectedRowsCount = useMemo(() => Object.values(selectedRows).length, [
|
const selectedRowsCount = useMemo(() => Object.values(selectedRows).length, [
|
||||||
@@ -63,7 +89,7 @@ function InventoryAdjustmentList({
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DashboardInsider>
|
<DashboardInsider name={'inventory_adjustments'}>
|
||||||
<DashboardPageContent>
|
<DashboardPageContent>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route exact={true}>
|
<Route exact={true}>
|
||||||
@@ -73,9 +99,32 @@ function InventoryAdjustmentList({
|
|||||||
/>
|
/>
|
||||||
</Route>
|
</Route>
|
||||||
</Switch>
|
</Switch>
|
||||||
|
<Alert
|
||||||
|
cancelButtonText={<T id={'cancel'} />}
|
||||||
|
confirmButtonText={<T id={'delete'} />}
|
||||||
|
icon={'trash'}
|
||||||
|
intent={Intent.DANGER}
|
||||||
|
isOpen={deleteInventoryAdjustment}
|
||||||
|
onCancel={handleCancelInventoryAdjustmentDelete}
|
||||||
|
onConfirm={handleConfirmInventoryAdjustmentDelete}
|
||||||
|
>
|
||||||
|
<p>
|
||||||
|
<T
|
||||||
|
id={
|
||||||
|
'once_delete_this_inventory_a_adjustment_you_will_able_to_restore_it'
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
</Alert>
|
||||||
</DashboardPageContent>
|
</DashboardPageContent>
|
||||||
</DashboardInsider>
|
</DashboardInsider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default compose(withDashboardActions)(InventoryAdjustmentList);
|
export default compose(
|
||||||
|
withDashboardActions,
|
||||||
|
withInventoryAdjustmentActions,
|
||||||
|
withInventoryAdjustments(({ inventoryAdjustmentTableQuery }) => ({
|
||||||
|
inventoryAdjustmentTableQuery,
|
||||||
|
})),
|
||||||
|
)(InventoryAdjustmentList);
|
||||||
|
|||||||
@@ -45,9 +45,6 @@ const defaultInitialValues = {
|
|||||||
category_id: '',
|
category_id: '',
|
||||||
sellable: 1,
|
sellable: 1,
|
||||||
purchasable: true,
|
purchasable: true,
|
||||||
opening_quantity: '',
|
|
||||||
opening_cost: '',
|
|
||||||
opening_date: moment(new Date()).format('YYYY-MM-DD'),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -61,26 +61,6 @@ const Schema = Yup.object().shape({
|
|||||||
stock: Yup.string() || Yup.boolean(),
|
stock: Yup.string() || Yup.boolean(),
|
||||||
sellable: Yup.boolean().required(),
|
sellable: Yup.boolean().required(),
|
||||||
purchasable: Yup.boolean().required(),
|
purchasable: Yup.boolean().required(),
|
||||||
opening_cost: Yup.number().when(['opening_quantity'], {
|
|
||||||
is: (value) => value,
|
|
||||||
then: Yup.number()
|
|
||||||
.min(0)
|
|
||||||
.required()
|
|
||||||
.label(formatMessage({ id: 'opening_cost_' })),
|
|
||||||
otherwise: Yup.number().nullable(),
|
|
||||||
}),
|
|
||||||
opening_quantity: Yup.number()
|
|
||||||
.integer()
|
|
||||||
.min(1)
|
|
||||||
.nullable()
|
|
||||||
.label(formatMessage({ id: 'opening_quantity_' })),
|
|
||||||
opening_date: Yup.date().when(['opening_quantity', 'opening_cost'], {
|
|
||||||
is: (quantity, cost) => !isBlank(quantity) && !isBlank(cost),
|
|
||||||
then: Yup.date()
|
|
||||||
.required()
|
|
||||||
.label(formatMessage({ id: 'opening_date_' })),
|
|
||||||
otherwise: Yup.date().nullable(),
|
|
||||||
}),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export const transformItemFormData = (item, defaultValue) => {
|
export const transformItemFormData = (item, defaultValue) => {
|
||||||
|
|||||||
@@ -65,77 +65,6 @@ function ItemFormInventorySection({ accountsList, baseCurrency }) {
|
|||||||
</FormGroup>
|
</FormGroup>
|
||||||
)}
|
)}
|
||||||
</FastField>
|
</FastField>
|
||||||
|
|
||||||
{/*------------- Opening quantity ------------- */}
|
|
||||||
<FastField name={'opening_quantity'}>
|
|
||||||
{({ field, meta: { touched, error } }) => (
|
|
||||||
<FormGroup
|
|
||||||
label={<T id={'opening_quantity'} />}
|
|
||||||
labelInfo={<Hint />}
|
|
||||||
className={'form-group--opening_quantity'}
|
|
||||||
intent={inputIntent({ error, touched })}
|
|
||||||
helperText={<ErrorMessage name={'opening_quantity'} />}
|
|
||||||
inline={true}
|
|
||||||
>
|
|
||||||
<InputGroup medium={true} {...field} />
|
|
||||||
</FormGroup>
|
|
||||||
)}
|
|
||||||
</FastField>
|
|
||||||
|
|
||||||
{/*------------- Opening date ------------- */}
|
|
||||||
<FastField name={'opening_date'}>
|
|
||||||
{({ form, field: { value }, meta: { touched, error } }) => (
|
|
||||||
<FormGroup
|
|
||||||
label={<T id={'opening_date'} />}
|
|
||||||
labelInfo={<Hint />}
|
|
||||||
className={classNames(
|
|
||||||
'form-group--select-list',
|
|
||||||
'form-group--opening_date',
|
|
||||||
CLASSES.FILL,
|
|
||||||
)}
|
|
||||||
intent={inputIntent({ error, touched })}
|
|
||||||
helperText={<ErrorMessage name={'opening_date'} />}
|
|
||||||
inline={true}
|
|
||||||
>
|
|
||||||
<DateInput
|
|
||||||
{...momentFormatter('YYYY/MM/DD')}
|
|
||||||
value={tansformDateValue(value)}
|
|
||||||
onChange={handleDateChange((value) => {
|
|
||||||
form.setFieldValue('opening_date', value);
|
|
||||||
})}
|
|
||||||
helperText={<ErrorMessage name={'opening_date'} />}
|
|
||||||
popoverProps={{ position: Position.BOTTOM, minimal: true }}
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
)}
|
|
||||||
</FastField>
|
|
||||||
</Col>
|
|
||||||
|
|
||||||
{/*------------- Opening cost ------------- */}
|
|
||||||
<Col xs={6}>
|
|
||||||
<FastField name={'opening_cost'}>
|
|
||||||
{({ form, field: { value }, meta: { touched, error } }) => (
|
|
||||||
<FormGroup
|
|
||||||
label={<T id={'opening_average_cost'} />}
|
|
||||||
labelInfo={<Hint />}
|
|
||||||
className={'form-group--opening_cost'}
|
|
||||||
intent={inputIntent({ error, touched })}
|
|
||||||
helperText={<ErrorMessage name={'opening_cost'} />}
|
|
||||||
inline={true}
|
|
||||||
>
|
|
||||||
<ControlGroup>
|
|
||||||
<InputPrependText text={baseCurrency} />
|
|
||||||
<MoneyInputGroup
|
|
||||||
value={value}
|
|
||||||
inputGroupProps={{ fill: true }}
|
|
||||||
onChange={(unformattedValue) => {
|
|
||||||
form.setFieldValue('opening_cost', unformattedValue);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</ControlGroup>
|
|
||||||
</FormGroup>
|
|
||||||
)}
|
|
||||||
</FastField>
|
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -75,6 +75,17 @@ function ItemsDataTable({
|
|||||||
[addItemsTableQueries],
|
[addItemsTableQueries],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleMakeAdjustment = useCallback(
|
||||||
|
(item) => () => {
|
||||||
|
openDialog('inventory-adjustment-form', {
|
||||||
|
action: 'make_adjustment',
|
||||||
|
item_id: item.id,
|
||||||
|
quantity_on_hand: item.quantity_on_hand,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[openDialog],
|
||||||
|
);
|
||||||
|
|
||||||
const handleEditItem = useCallback(
|
const handleEditItem = useCallback(
|
||||||
(item) => () => {
|
(item) => () => {
|
||||||
onEditItem && onEditItem(item);
|
onEditItem && onEditItem(item);
|
||||||
@@ -89,10 +100,6 @@ function ItemsDataTable({
|
|||||||
[onDeleteItem],
|
[onDeleteItem],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleMakeAdjustment = useCallback(() => {
|
|
||||||
openDialog('inventory-adjustment-form', {});
|
|
||||||
}, [openDialog]);
|
|
||||||
|
|
||||||
const actionMenuList = useCallback(
|
const actionMenuList = useCallback(
|
||||||
(item) => (
|
(item) => (
|
||||||
<Menu>
|
<Menu>
|
||||||
@@ -120,11 +127,11 @@ function ItemsDataTable({
|
|||||||
onClick={() => onActivateItem(item)}
|
onClick={() => onActivateItem(item)}
|
||||||
/>
|
/>
|
||||||
</If>
|
</If>
|
||||||
|
|
||||||
<If condition={item.type === 'inventory'}>
|
<If condition={item.type === 'inventory'}>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
text={formatMessage({ id: 'make_adjustment' })}
|
text={formatMessage({ id: 'make_adjustment' })}
|
||||||
onClick={handleMakeAdjustment}
|
onClick={handleMakeAdjustment(item)}
|
||||||
/>
|
/>
|
||||||
</If>
|
</If>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
|
|||||||
@@ -98,6 +98,33 @@ function ItemsList({
|
|||||||
setDeleteItem(false);
|
setDeleteItem(false);
|
||||||
}, [setDeleteItem]);
|
}, [setDeleteItem]);
|
||||||
|
|
||||||
|
const handleDeleteErrors = (errors) => {
|
||||||
|
if (
|
||||||
|
errors.find((error) => error.type === 'ITEM_HAS_ASSOCIATED_TRANSACTINS')
|
||||||
|
) {
|
||||||
|
AppToaster.show({
|
||||||
|
message: formatMessage({
|
||||||
|
id: 'the_item_has_associated_transactions',
|
||||||
|
}),
|
||||||
|
intent: Intent.DANGER,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
errors.find(
|
||||||
|
(error) => error.type === 'ITEM_HAS_ASSOCIATED_INVENTORY_ADJUSTMENT',
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
AppToaster.show({
|
||||||
|
message: formatMessage({
|
||||||
|
id:
|
||||||
|
'you_could_not_delete_item_that_has_associated_inventory_adjustments_transacions',
|
||||||
|
}),
|
||||||
|
intent: Intent.DANGER,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// handle confirm delete item.
|
// handle confirm delete item.
|
||||||
const handleConfirmDeleteItem = useCallback(() => {
|
const handleConfirmDeleteItem = useCallback(() => {
|
||||||
requestDeleteItem(deleteItem.id)
|
requestDeleteItem(deleteItem.id)
|
||||||
@@ -112,19 +139,8 @@ function ItemsList({
|
|||||||
setDeleteItem(false);
|
setDeleteItem(false);
|
||||||
})
|
})
|
||||||
.catch(({ errors }) => {
|
.catch(({ errors }) => {
|
||||||
if (
|
|
||||||
errors.find(
|
|
||||||
(error) => error.type === 'ITEM_HAS_ASSOCIATED_TRANSACTINS',
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
AppToaster.show({
|
|
||||||
message: formatMessage({
|
|
||||||
id: 'the_item_has_associated_transactions',
|
|
||||||
}),
|
|
||||||
intent: Intent.DANGER,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
setDeleteItem(false);
|
setDeleteItem(false);
|
||||||
|
handleDeleteErrors(errors);
|
||||||
});
|
});
|
||||||
}, [requestDeleteItem, deleteItem, formatMessage]);
|
}, [requestDeleteItem, deleteItem, formatMessage]);
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
import t from 'store/types';
|
import t from 'store/types';
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
requestSubmitInventoryAdjustment: (form) =>
|
requestSubmitInventoryAdjustment: ({ form }) =>
|
||||||
dispatch(submitInventoryAdjustment({ form })),
|
dispatch(submitInventoryAdjustment({ form })),
|
||||||
requestFetchInventoryAdjustmentTable: (query = {}) =>
|
requestFetchInventoryAdjustmentTable: (query = {}) =>
|
||||||
dispatch(fetchInventoryAdjustmentsTable({ query: { ...query } })),
|
dispatch(fetchInventoryAdjustmentsTable({ query: { ...query } })),
|
||||||
|
|||||||
@@ -1,4 +1,34 @@
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
import {
|
||||||
|
getInvoiceTableQueryFactory,
|
||||||
|
getInventoryAdjustmentCurrentPageFactory,
|
||||||
|
getInventoryAdjustmentPaginationMetaFactory,
|
||||||
|
} from 'store/inventoryAdjustments/inventoryAdjustment.selector';
|
||||||
|
|
||||||
|
export default (mapState) => {
|
||||||
|
const getInventoryAdjustmentItems = getInventoryAdjustmentCurrentPageFactory();
|
||||||
|
const getInventoryAdjustmentTableQuery = getInvoiceTableQueryFactory();
|
||||||
|
const getInventoryAdjustmentsPaginationMeta = getInventoryAdjustmentPaginationMetaFactory();
|
||||||
|
|
||||||
|
const mapStateToProps = (state, props) => {
|
||||||
|
const query = getInventoryAdjustmentTableQuery(state, props);
|
||||||
|
|
||||||
|
const mapped = {
|
||||||
|
inventoryAdjustmentCurrentPage: getInventoryAdjustmentItems(
|
||||||
|
state,
|
||||||
|
props,
|
||||||
|
query,
|
||||||
|
),
|
||||||
|
inventoryAdjustmentItems: Object.values(state.inventoryAdjustments.items),
|
||||||
|
inventoryAdjustmentTableQuery: query,
|
||||||
|
inventoryAdjustmentsPagination: getInventoryAdjustmentsPaginationMeta(
|
||||||
|
state,
|
||||||
|
props,
|
||||||
|
query,
|
||||||
|
),
|
||||||
|
inventoryAdjustmentLoading: state.inventoryAdjustments.loading,
|
||||||
|
};
|
||||||
|
return mapState ? mapState(mapped, state, props) : mapped;
|
||||||
|
};
|
||||||
|
return connect(mapStateToProps);
|
||||||
|
};
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ export default function PreferencesGeneralForm({}) {
|
|||||||
selectedItem={value}
|
selectedItem={value}
|
||||||
selectedItemProp={'value'}
|
selectedItemProp={'value'}
|
||||||
defaultText={<T id={'select_business_location'} />}
|
defaultText={<T id={'select_business_location'} />}
|
||||||
labelProp={'name'}
|
textProp={'name'}
|
||||||
popoverProps={{ minimal: true }}
|
popoverProps={{ minimal: true }}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
@@ -130,7 +130,7 @@ export default function PreferencesGeneralForm({}) {
|
|||||||
selectedItem={value}
|
selectedItem={value}
|
||||||
selectedItemProp={'code'}
|
selectedItemProp={'code'}
|
||||||
defaultText={<T id={'select_base_currency'} />}
|
defaultText={<T id={'select_base_currency'} />}
|
||||||
labelProp={'label'}
|
textProp={'label'}
|
||||||
popoverProps={{ minimal: true }}
|
popoverProps={{ minimal: true }}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
@@ -150,7 +150,7 @@ export default function PreferencesGeneralForm({}) {
|
|||||||
<ListSelect
|
<ListSelect
|
||||||
items={fiscalYearOptions}
|
items={fiscalYearOptions}
|
||||||
selectedItemProp={'value'}
|
selectedItemProp={'value'}
|
||||||
labelProp={'name'}
|
textProp={'name'}
|
||||||
defaultText={<T id={'select_fiscal_year'} />}
|
defaultText={<T id={'select_fiscal_year'} />}
|
||||||
selectedItem={value}
|
selectedItem={value}
|
||||||
onItemSelect={(item) => {}}
|
onItemSelect={(item) => {}}
|
||||||
@@ -173,7 +173,7 @@ export default function PreferencesGeneralForm({}) {
|
|||||||
<ListSelect
|
<ListSelect
|
||||||
items={languages}
|
items={languages}
|
||||||
selectedItemProp={'value'}
|
selectedItemProp={'value'}
|
||||||
labelProp={'name'}
|
textProp={'name'}
|
||||||
defaultText={<T id={'select_language'} />}
|
defaultText={<T id={'select_language'} />}
|
||||||
selectedItem={value}
|
selectedItem={value}
|
||||||
onItemSelect={(item) => {}}
|
onItemSelect={(item) => {}}
|
||||||
@@ -227,7 +227,7 @@ export default function PreferencesGeneralForm({}) {
|
|||||||
selectedItem={value}
|
selectedItem={value}
|
||||||
selectedItemProp={'value'}
|
selectedItemProp={'value'}
|
||||||
defaultText={<T id={'select_date_format'} />}
|
defaultText={<T id={'select_date_format'} />}
|
||||||
labelProp={'name'}
|
textProp={'name'}
|
||||||
popoverProps={{ minimal: true }}
|
popoverProps={{ minimal: true }}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|||||||
@@ -324,7 +324,7 @@ function SetupOrganizationForm({
|
|||||||
selectedItem={values.base_currency}
|
selectedItem={values.base_currency}
|
||||||
selectedItemProp={'value'}
|
selectedItemProp={'value'}
|
||||||
defaultText={<T id={'select_base_currency'} />}
|
defaultText={<T id={'select_base_currency'} />}
|
||||||
labelProp={'name'}
|
textProp={'name'}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
</Col>
|
</Col>
|
||||||
@@ -354,7 +354,7 @@ function SetupOrganizationForm({
|
|||||||
selectedItem={values.language}
|
selectedItem={values.language}
|
||||||
selectedItemProp={'value'}
|
selectedItemProp={'value'}
|
||||||
defaultText={<T id={'select_language'} />}
|
defaultText={<T id={'select_language'} />}
|
||||||
labelProp={'name'}
|
textProp={'name'}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
</Col>
|
</Col>
|
||||||
@@ -383,7 +383,7 @@ function SetupOrganizationForm({
|
|||||||
selectedItem={values.fiscal_year}
|
selectedItem={values.fiscal_year}
|
||||||
selectedItemProp={'value'}
|
selectedItemProp={'value'}
|
||||||
defaultText={<T id={'select_fiscal_year'} />}
|
defaultText={<T id={'select_fiscal_year'} />}
|
||||||
labelProp={'name'}
|
textProp={'name'}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -950,9 +950,24 @@ export default {
|
|||||||
cost: 'Cost',
|
cost: 'Cost',
|
||||||
qty_on_hand: 'Qty on hand',
|
qty_on_hand: 'Qty on hand',
|
||||||
adjustment_account: 'Adjustment account',
|
adjustment_account: 'Adjustment account',
|
||||||
inventory_adjustment_list:'Inventory Adjustment List',
|
inventory_adjustment_list: 'Inventory Adjustment List',
|
||||||
delete_adjustment:'Delete Adjustment',
|
delete_adjustment: 'Delete Adjustment',
|
||||||
the_make_adjustment_has_been_successfully_created:
|
the_make_adjustment_has_been_successfully_created:
|
||||||
'The make adjustment has been successfully created.',
|
'The make adjustment has been successfully created.',
|
||||||
|
the_adjustment_has_been_successfully_deleted:
|
||||||
|
'The adjustment has been successfully deleted.',
|
||||||
|
once_delete_this_inventory_a_adjustment_you_will_able_to_restore_it: `Once you delete this inventory a adjustment, you won\'t be able to restore it later. Are you sure you want to delete this invoice?`,
|
||||||
|
select_adjustment_account: 'Select Adjustment account',
|
||||||
|
qty: 'Quantity on hand',
|
||||||
|
money_format: 'Money format',
|
||||||
|
show_zero: 'Show zero',
|
||||||
|
show_negative_in_red: 'Show negative in red',
|
||||||
|
divide_on_1000: 'Divide on 1000',
|
||||||
|
negative_format: 'Negative format',
|
||||||
|
decimal_places: 'Decimal places',
|
||||||
|
run: 'Run',
|
||||||
|
you_could_not_delete_item_that_has_associated_inventory_adjustments_transacions:
|
||||||
|
'You could not delete item that has associated inventory adjustments transactions',
|
||||||
|
format: 'Format',
|
||||||
current: 'Current',
|
current: 'Current',
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,10 +4,11 @@ import t from 'store/types';
|
|||||||
export const submitInventoryAdjustment = ({ form }) => {
|
export const submitInventoryAdjustment = ({ form }) => {
|
||||||
return (dispatch) =>
|
return (dispatch) =>
|
||||||
new Promise((resolve, reject) => {
|
new Promise((resolve, reject) => {
|
||||||
ApiService.post('inventory_adjustments', form).then((response) => {
|
ApiService.post('inventory_adjustments/quick', form)
|
||||||
resolve(response);
|
.then((response) => {
|
||||||
}),
|
resolve(response);
|
||||||
caches((error) => {
|
})
|
||||||
|
.catch((error) => {
|
||||||
const { response } = error;
|
const { response } = error;
|
||||||
const { data } = response;
|
const { data } = response;
|
||||||
|
|
||||||
@@ -51,7 +52,7 @@ export const fetchInventoryAdjustmentsTable = ({ query } = {}) => {
|
|||||||
dispatch({
|
dispatch({
|
||||||
type: t.INVENTORY_ADJUSTMENTS_PAGE_SET,
|
type: t.INVENTORY_ADJUSTMENTS_PAGE_SET,
|
||||||
payload: {
|
payload: {
|
||||||
inventory_adjustments: response.data,
|
inventory_adjustments: response.data.inventoy_adjustments,
|
||||||
pagination: response.data.pagination,
|
pagination: response.data.pagination,
|
||||||
customViewId:
|
customViewId:
|
||||||
response.data?.filter_meta?.view?.custom_view_id || -1,
|
response.data?.filter_meta?.view?.custom_view_id || -1,
|
||||||
@@ -60,7 +61,7 @@ export const fetchInventoryAdjustmentsTable = ({ query } = {}) => {
|
|||||||
dispatch({
|
dispatch({
|
||||||
type: t.INVENTORY_ADJUSTMENT_ITEMS_SET,
|
type: t.INVENTORY_ADJUSTMENT_ITEMS_SET,
|
||||||
payload: {
|
payload: {
|
||||||
inventory_adjustment: response.data,
|
inventory_adjustment: response.data.inventoy_adjustments,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
dispatch({
|
dispatch({
|
||||||
|
|||||||
@@ -14,9 +14,6 @@ const initialState = {
|
|||||||
page_size: 12,
|
page_size: 12,
|
||||||
page: 1,
|
page: 1,
|
||||||
},
|
},
|
||||||
paginationMeta: {
|
|
||||||
total: 0,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default createReducer(initialState, {
|
export default createReducer(initialState, {
|
||||||
@@ -37,7 +34,6 @@ export default createReducer(initialState, {
|
|||||||
|
|
||||||
const viewId = customViewId || -1;
|
const viewId = customViewId || -1;
|
||||||
const view = state.views[viewId] || {};
|
const view = state.views[viewId] || {};
|
||||||
|
|
||||||
state.views[viewId] = {
|
state.views[viewId] = {
|
||||||
...view,
|
...view,
|
||||||
pages: {
|
pages: {
|
||||||
@@ -49,7 +45,6 @@ export default createReducer(initialState, {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
//useless
|
|
||||||
[t.INVENTORY_ADJUSTMENT_ITEMS_SET]: (state, action) => {
|
[t.INVENTORY_ADJUSTMENT_ITEMS_SET]: (state, action) => {
|
||||||
const { inventory_adjustment } = action.payload;
|
const { inventory_adjustment } = action.payload;
|
||||||
const _inventory_adjustment = {};
|
const _inventory_adjustment = {};
|
||||||
|
|||||||
@@ -5,3 +5,55 @@ import {
|
|||||||
defaultPaginationMeta,
|
defaultPaginationMeta,
|
||||||
} from 'store/selectors';
|
} from 'store/selectors';
|
||||||
|
|
||||||
|
const inventoryAdjustmentTableQuery = (state) =>
|
||||||
|
state.inventoryAdjustments.tableQuery;
|
||||||
|
|
||||||
|
const inventoryAdjustmentsPaginationSelector = (state, props) => {
|
||||||
|
const viewId = state.inventoryAdjustments.currentViewId;
|
||||||
|
return state.inventoryAdjustments.views?.[viewId];
|
||||||
|
};
|
||||||
|
|
||||||
|
const inventoryAdjustmentItemsSelector = (state) =>
|
||||||
|
state.inventoryAdjustments.items;
|
||||||
|
|
||||||
|
const inventoryAdjustmentCurrentPageSelector = (state, props) => {
|
||||||
|
const currentViewId = state.inventoryAdjustments.currentViewId;
|
||||||
|
const currentView = state.inventoryAdjustments.views?.[currentViewId];
|
||||||
|
const currentPageId = currentView?.paginationMeta?.page;
|
||||||
|
|
||||||
|
return currentView?.pages?.[currentPageId];
|
||||||
|
};
|
||||||
|
|
||||||
|
const getinventoryAdjustmentCurrentViewIdSelector = (state) =>
|
||||||
|
state.inventoryAdjustments.currentViewId;
|
||||||
|
|
||||||
|
export const getInvoiceTableQueryFactory = () =>
|
||||||
|
createSelector(
|
||||||
|
paginationLocationQuery,
|
||||||
|
inventoryAdjustmentTableQuery,
|
||||||
|
(locationQuery, tableQuery) => {
|
||||||
|
return {
|
||||||
|
...locationQuery,
|
||||||
|
...tableQuery,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
export const getInventoryAdjustmentCurrentPageFactory = () =>
|
||||||
|
createSelector(
|
||||||
|
inventoryAdjustmentCurrentPageSelector,
|
||||||
|
inventoryAdjustmentItemsSelector,
|
||||||
|
(currentPage, items) => {
|
||||||
|
return typeof currentPage === 'object'
|
||||||
|
? pickItemsFromIds(items, currentPage.ids) || []
|
||||||
|
: [];
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
export const getInventoryAdjustmentPaginationMetaFactory = () =>
|
||||||
|
createSelector(inventoryAdjustmentsPaginationSelector, (Page) => {
|
||||||
|
return {
|
||||||
|
...defaultPaginationMeta(),
|
||||||
|
...(Page?.paginationMeta || {}),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ export default {
|
|||||||
|
|
||||||
|
|
||||||
INVENTORY_ADJUSTMENTS_TABLE_QUERIES_ADD:
|
INVENTORY_ADJUSTMENTS_TABLE_QUERIES_ADD:
|
||||||
'INVENTORY_ADJUSTMENTS_TABLE_QUERIES_ADD',
|
'INVENTORY_ADJUSTMENTS/TABLE_QUERIES_ADD',
|
||||||
INVENTORY_ADJUSTMENTS_SET_CURRENT_VIEW:
|
INVENTORY_ADJUSTMENTS_SET_CURRENT_VIEW:
|
||||||
'INVENTORY_ADJUSTMENTS_SET_CURRENT_VIEW',
|
'INVENTORY_ADJUSTMENTS_SET_CURRENT_VIEW',
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -30,6 +30,8 @@
|
|||||||
@import 'pages/view-form';
|
@import 'pages/view-form';
|
||||||
@import 'pages/register-organizaton';
|
@import 'pages/register-organizaton';
|
||||||
|
|
||||||
|
@import 'pages/number-format.scss';
|
||||||
|
|
||||||
// Views
|
// Views
|
||||||
@import 'views/filter-dropdown';
|
@import 'views/filter-dropdown';
|
||||||
|
|
||||||
|
|||||||
24
client/src/style/pages/number-format.scss
Normal file
24
client/src/style/pages/number-format.scss
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
.number-format {
|
||||||
|
width: 400px;
|
||||||
|
padding: 12px;
|
||||||
|
// width: 300px;
|
||||||
|
// padding: 10px;
|
||||||
|
&__content {
|
||||||
|
.bp3-form-group {
|
||||||
|
margin-bottom: 5px;
|
||||||
|
// margin-bottom: 0px;
|
||||||
|
.bp3-form-content {
|
||||||
|
.bp3-label {
|
||||||
|
margin-bottom: 3px;
|
||||||
|
}
|
||||||
|
.bp3-control {
|
||||||
|
margin: 5px 0px 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&__footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user