mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-19 22:30:31 +00:00
Merge branch 'master' of https://github.com/abouolia/Ratteb
# Conflicts: # client/src/lang/en/index.js
This commit is contained in:
@@ -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'),
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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,28 @@ 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) => {
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
@@ -66,7 +90,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;
|
||||||
|
|||||||
@@ -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) => {
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
@@ -178,7 +186,7 @@ function ItemsDataTable({
|
|||||||
{
|
{
|
||||||
Header: formatMessage({ id: 'cost_price' }),
|
Header: formatMessage({ id: 'cost_price' }),
|
||||||
accessor: (row) =>
|
accessor: (row) =>
|
||||||
!isBlank(row.sell_price) ? (
|
!isBlank(row.cost_price) ? (
|
||||||
<Money amount={row.cost_price} currency={'USD'} />
|
<Money amount={row.cost_price} currency={'USD'} />
|
||||||
) : (
|
) : (
|
||||||
''
|
''
|
||||||
@@ -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,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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',
|
||||||
@@ -930,4 +931,8 @@ export default {
|
|||||||
activate_item: 'Activate Item',
|
activate_item: 'Activate Item',
|
||||||
all_payments:'All Payments',
|
all_payments:'All Payments',
|
||||||
hide_customizer: 'Hide Customizer',
|
hide_customizer: 'Hide Customizer',
|
||||||
|
opening_quantity_: 'Opening quantity',
|
||||||
|
opening_average_cost: 'Opening average cost',
|
||||||
|
opening_cost_: 'Opening cost ',
|
||||||
|
opening_date_: 'Opening date ',
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -95,6 +95,9 @@
|
|||||||
color: #9eaab6;
|
color: #9eaab6;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.quantity_on_hand {
|
||||||
|
color: #ff0000;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user