fix: opening quantity & cost & date

This commit is contained in:
elforjani3
2020-12-26 23:09:48 +02:00
parent af96d4bde4
commit 085545c039
7 changed files with 112 additions and 45 deletions

View File

@@ -6,6 +6,7 @@ import { useHistory } from 'react-router-dom';
import { useIntl } from 'react-intl'; import { useIntl } from 'react-intl';
import classNames from 'classnames'; import classNames from 'classnames';
import { defaultTo } from 'lodash'; import { defaultTo } from 'lodash';
import moment from 'moment';
import { CLASSES } from 'common/classes'; import { CLASSES } from 'common/classes';
import AppToaster from 'components/AppToaster'; import AppToaster from 'components/AppToaster';
@@ -42,6 +43,9 @@ 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'),
}; };
/** /**

View File

@@ -2,6 +2,7 @@ import * as Yup from 'yup';
import { defaultTo } from 'lodash'; import { defaultTo } from 'lodash';
import { formatMessage } from 'services/intl'; import { formatMessage } from 'services/intl';
import { DATATYPES_LENGTH } from 'common/dataTypes'; import { DATATYPES_LENGTH } from 'common/dataTypes';
import { isBlank } from 'utils';
const Schema = Yup.object().shape({ const Schema = Yup.object().shape({
active: Yup.boolean(), active: Yup.boolean(),
@@ -17,20 +18,24 @@ const Schema = Yup.object().shape({
.max(DATATYPES_LENGTH.STRING) .max(DATATYPES_LENGTH.STRING)
.label(formatMessage({ id: 'item_type_' })), .label(formatMessage({ id: 'item_type_' })),
code: Yup.string().trim().min(0).max(DATATYPES_LENGTH.STRING), code: Yup.string().trim().min(0).max(DATATYPES_LENGTH.STRING),
cost_price: Yup.number().min(0).when(['purchasable'], { cost_price: Yup.number()
is: true, .min(0)
then: Yup.number() .when(['purchasable'], {
.required() is: true,
.label(formatMessage({ id: 'cost_price_' })), then: Yup.number()
otherwise: Yup.number().nullable(true), .required()
}), .label(formatMessage({ id: 'cost_price_' })),
sell_price: Yup.number().min(0).when(['sellable'], { otherwise: Yup.number().nullable(true),
is: true, }),
then: Yup.number() sell_price: Yup.number()
.required() .min(0)
.label(formatMessage({ id: 'sell_price_' })), .when(['sellable'], {
otherwise: Yup.number().nullable(true), is: true,
}), then: Yup.number()
.required()
.label(formatMessage({ id: 'sell_price_' })),
otherwise: Yup.number().nullable(true),
}),
cost_account_id: Yup.number() cost_account_id: Yup.number()
.when(['purchasable'], { .when(['purchasable'], {
is: true, is: true,
@@ -56,9 +61,27 @@ 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()
.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) => {
return { return {
...item, ...item,
@@ -66,7 +89,7 @@ export const transformItemFormData = (item, defaultValue) => {
purchasable: !!defaultTo(item?.purchasable, defaultValue.purchasable), purchasable: !!defaultTo(item?.purchasable, defaultValue.purchasable),
active: !!defaultTo(item?.active, defaultValue.active), active: !!defaultTo(item?.active, defaultValue.active),
}; };
} };
export const CreateItemFormSchema = Schema; export const CreateItemFormSchema = Schema;
export const EditItemFormSchema = Schema; export const EditItemFormSchema = Schema;

View File

@@ -57,7 +57,6 @@ function ItemFormBody({ accountsList, baseCurrency }) {
<InputPrependText text={baseCurrency} /> <InputPrependText text={baseCurrency} />
<MoneyInputGroup <MoneyInputGroup
value={value} value={value}
prefix={'$'}
inputGroupProps={{ fill: true }} inputGroupProps={{ fill: true }}
disabled={!form.values.sellable} disabled={!form.values.sellable}
onChange={(unformattedValue) => { onChange={(unformattedValue) => {
@@ -132,7 +131,6 @@ function ItemFormBody({ accountsList, baseCurrency }) {
<InputPrependText text={baseCurrency} /> <InputPrependText text={baseCurrency} />
<MoneyInputGroup <MoneyInputGroup
value={value} value={value}
prefix={'$'}
inputGroupProps={{ medium: true }} inputGroupProps={{ medium: true }}
disabled={!form.values.purchasable} disabled={!form.values.purchasable}
onChange={(unformattedValue) => { onChange={(unformattedValue) => {

View File

@@ -1,18 +1,37 @@
import React from 'react'; import React from 'react';
import { FastField, ErrorMessage } from 'formik'; import { FastField, ErrorMessage } from 'formik';
import { FormGroup, InputGroup, Position } from '@blueprintjs/core'; import {
FormGroup,
InputGroup,
ControlGroup,
Position,
} from '@blueprintjs/core';
import { DateInput } from '@blueprintjs/datetime'; import { DateInput } from '@blueprintjs/datetime';
import { AccountsSelectList, Col, Row, Hint } from 'components'; import {
AccountsSelectList,
MoneyInputGroup,
InputPrependText,
Col,
Row,
Hint,
} from 'components';
import { CLASSES } from 'common/classes'; import { CLASSES } from 'common/classes';
import { FormattedMessage as T } from 'react-intl'; import { FormattedMessage as T } from 'react-intl';
import classNames from 'classnames'; import classNames from 'classnames';
import withAccounts from 'containers/Accounts/withAccounts'; import withAccounts from 'containers/Accounts/withAccounts';
import { compose, tansformDateValue, momentFormatter, inputIntent } from 'utils'; import withSettings from 'containers/Settings/withSettings';
import {
compose,
tansformDateValue,
momentFormatter,
inputIntent,
handleDateChange,
} from 'utils';
/** /**
* Item form inventory sections. * Item form inventory sections.
*/ */
function ItemFormInventorySection({ accountsList }) { function ItemFormInventorySection({ accountsList, baseCurrency }) {
return ( return (
<div class="page-form__section page-form__section--inventory"> <div class="page-form__section page-form__section--inventory">
<h3> <h3>
@@ -47,23 +66,23 @@ function ItemFormInventorySection({ accountsList }) {
)} )}
</FastField> </FastField>
{/*------------- Opening quantity ------------- */}
<FastField name={'opening_quantity'}> <FastField name={'opening_quantity'}>
{({ field, field: { value }, meta: { touched, error } }) => ( {({ field, meta: { touched, error } }) => (
<FormGroup <FormGroup
label={<T id={'opening_quantity'} />} label={<T id={'opening_quantity'} />}
labelInfo={<Hint />} labelInfo={<Hint />}
className={'form-group--opening_quantity'} className={'form-group--opening_quantity'}
intent={inputIntent({ error, touched })} intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name={'opening_quantity'} />}
inline={true} inline={true}
> >
<InputGroup <InputGroup medium={true} {...field} />
medium={true}
{...field}
/>
</FormGroup> </FormGroup>
)} )}
</FastField> </FastField>
{/*------------- Opening date ------------- */}
<FastField name={'opening_date'}> <FastField name={'opening_date'}>
{({ form, field: { value }, meta: { touched, error } }) => ( {({ form, field: { value }, meta: { touched, error } }) => (
<FormGroup <FormGroup
@@ -75,14 +94,16 @@ function ItemFormInventorySection({ accountsList }) {
CLASSES.FILL, CLASSES.FILL,
)} )}
intent={inputIntent({ error, touched })} intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name={'opening_date'} />}
inline={true} inline={true}
> >
<DateInput <DateInput
{...momentFormatter('YYYY/MM/DD')} {...momentFormatter('YYYY/MM/DD')}
value={tansformDateValue(value)} value={tansformDateValue(value)}
onChange={(value) => { onChange={handleDateChange((value) => {
form.setFieldValue('opening_date', value); form.setFieldValue('opening_date', value);
}} })}
helperText={<ErrorMessage name={'opening_date'} />}
popoverProps={{ position: Position.BOTTOM, minimal: true }} popoverProps={{ position: Position.BOTTOM, minimal: true }}
/> />
</FormGroup> </FormGroup>
@@ -90,20 +111,28 @@ function ItemFormInventorySection({ accountsList }) {
</FastField> </FastField>
</Col> </Col>
{/*------------- Opening cost ------------- */}
<Col xs={6}> <Col xs={6}>
<FastField name={'opening_average_rate'}> <FastField name={'opening_cost'}>
{({ field, field: { value }, meta: { touched, error } }) => ( {({ form, field: { value }, meta: { touched, error } }) => (
<FormGroup <FormGroup
label={'Opening average rate'} label={<T id={'opening_average_cost'} />}
labelInfo={<Hint />} labelInfo={<Hint />}
className={'form-group--opening_average_rate'} className={'form-group--opening_cost'}
intent={inputIntent({ error, touched })} intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name={'opening_cost'} />}
inline={true} inline={true}
> >
<InputGroup <ControlGroup>
medium={true} <InputPrependText text={baseCurrency} />
{...field} <MoneyInputGroup
/> value={value}
inputGroupProps={{ fill: true }}
onChange={(unformattedValue) => {
form.setFieldValue('opening_cost', unformattedValue);
}}
/>
</ControlGroup>
</FormGroup> </FormGroup>
)} )}
</FastField> </FastField>
@@ -117,4 +146,7 @@ export default compose(
withAccounts(({ accountsList }) => ({ withAccounts(({ accountsList }) => ({
accountsList, accountsList,
})), })),
withSettings(({ organizationSettings }) => ({
baseCurrency: organizationSettings?.baseCurrency,
})),
)(ItemFormInventorySection); )(ItemFormInventorySection);

View File

@@ -124,6 +124,14 @@ function ItemsDataTable({
], ],
); );
const quantityonHandCell = ({ value: quantity }) => {
return quantity <= 0 ? (
<span className={'quantity_on_hand'}>{quantity}</span>
) : (
<span>{quantity}</span>
);
};
const handleRowContextMenu = useCallback( const handleRowContextMenu = useCallback(
(cell) => { (cell) => {
return actionMenuList(cell.row.original); return actionMenuList(cell.row.original);
@@ -189,13 +197,7 @@ function ItemsDataTable({
{ {
Header: formatMessage({ id: 'quantity_on_hand' }), Header: formatMessage({ id: 'quantity_on_hand' }),
accessor: 'quantity_on_hand', accessor: 'quantity_on_hand',
className: 'quantity_on_hand', Cell: quantityonHandCell,
width: 140,
},
{
Header: formatMessage({ id: 'average_rate' }),
accessor: 'average_cost_rate',
className: 'average_cost_rate',
width: 140, width: 140,
}, },
{ {

View File

@@ -100,6 +100,7 @@ export default {
inventory_information: 'Inventory Information', inventory_information: 'Inventory Information',
inventory_account: 'Inventory Account', inventory_account: 'Inventory Account',
opening_quantity: 'Opening quantity', opening_quantity: 'Opening quantity',
opening_cost: 'Opening cost',
save: 'Save', save: 'Save',
save_as_draft: 'Save as Draft', save_as_draft: 'Save as Draft',
active: 'Active', active: 'Active',
@@ -928,5 +929,9 @@ export default {
'Are you sure you want to activate this item? You will be able to inactivate it later', 'Are you sure you want to activate this item? You will be able to inactivate it later',
inactivate_item: 'Inactivate Item', inactivate_item: 'Inactivate Item',
activate_item: 'Activate Item', activate_item: 'Activate Item',
all_payments:'All Payments' all_payments: 'All Payments',
opening_quantity_: 'Opening quantity',
opening_average_cost: 'Opening average cost',
opening_cost_: 'Opening cost ',
opening_date_: 'Opening date ',
}; };

View File

@@ -95,6 +95,9 @@
color: #9eaab6; color: #9eaab6;
} }
} }
.quantity_on_hand {
color: #ff0000;
}
} }
} }
} }