Merge remote-tracking branch 'origin/master'

This commit is contained in:
Ahmed Bouhuolia
2020-11-16 13:40:44 +02:00
16 changed files with 137 additions and 78 deletions

View File

@@ -126,6 +126,7 @@ function MakeJournalEntriesForm({
date: Yup.date() date: Yup.date()
.required() .required()
.label(formatMessage({ id: 'date' })), .label(formatMessage({ id: 'date' })),
currency_code: Yup.string(),
reference: Yup.string().min(1).max(255), reference: Yup.string().min(1).max(255),
description: Yup.string().min(1).max(1024), description: Yup.string().min(1).max(1024),
entries: Yup.array().of( entries: Yup.array().of(
@@ -172,6 +173,7 @@ function MakeJournalEntriesForm({
date: moment(new Date()).format('YYYY-MM-DD'), date: moment(new Date()).format('YYYY-MM-DD'),
description: '', description: '',
reference: '', reference: '',
currency_code: '',
entries: [...repeatValue(defaultEntry, 4)], entries: [...repeatValue(defaultEntry, 4)],
}), }),
[defaultEntry, journalNumber], [defaultEntry, journalNumber],
@@ -442,11 +444,12 @@ function MakeJournalEntriesForm({
}, },
[changePageSubtitle], [changePageSubtitle],
); );
console.log(values, 'Val');
return ( return (
<div class="make-journal-entries"> <div class="make-journal-entries">
<form onSubmit={handleSubmit}> <form onSubmit={handleSubmit}>
<MakeJournalEntriesHeader <MakeJournalEntriesHeader
manualJournal={manualJournalId}
errors={errors} errors={errors}
touched={touched} touched={touched}
values={values} values={values}

View File

@@ -1,4 +1,4 @@
import React, { useMemo, useCallback } from 'react'; import React, { useMemo, useState, useCallback } from 'react';
import { import {
InputGroup, InputGroup,
FormGroup, FormGroup,
@@ -15,16 +15,18 @@ import classNames from 'classnames';
import { CLASSES } from 'common/classes'; import { CLASSES } from 'common/classes';
import { momentFormatter, tansformDateValue, saveInvoke } from 'utils'; import { momentFormatter, tansformDateValue, saveInvoke } from 'utils';
import { import {
CurrenciesSelectList,
ErrorMessage, ErrorMessage,
Hint, Hint,
FieldHint, FieldHint,
FieldRequiredHint, FieldRequiredHint,
Icon, Icon,
InputPrependButton, InputPrependButton,
CurrencySelectList,
} from 'components'; } from 'components';
import withDialogActions from 'containers/Dialog/withDialogActions'; import withDialogActions from 'containers/Dialog/withDialogActions';
import withCurrencies from 'containers/Currencies/withCurrencies';
import withSettings from 'containers/Settings/withSettings';
import { compose } from 'utils'; import { compose } from 'utils';
@@ -36,11 +38,20 @@ function MakeJournalEntriesHeader({
getFieldProps, getFieldProps,
// #ownProps // #ownProps
manualJournal,
onJournalNumberChanged, onJournalNumberChanged,
// #withSettings
baseCurrency,
// #withCurrencies
currenciesList,
// #withDialog // #withDialog
openDialog, openDialog,
}) { }) {
const [selectedItems, setSelectedItems] = useState({});
const handleDateChange = useCallback( const handleDateChange = useCallback(
(date) => { (date) => {
const formatted = moment(date).format('YYYY-MM-DD'); const formatted = moment(date).format('YYYY-MM-DD');
@@ -57,6 +68,19 @@ function MakeJournalEntriesHeader({
saveInvoke(onJournalNumberChanged, event.currentTarget.value); saveInvoke(onJournalNumberChanged, event.currentTarget.value);
}; };
const onItemsSelect = useCallback(
(filedName) => {
return (filed) => {
setSelectedItems({
...selectedItems,
[filedName]: filed,
});
setFieldValue(filedName, filed.currency_code);
};
},
[setFieldValue, selectedItems],
);
return ( return (
<div class="make-journal-entries__header"> <div class="make-journal-entries__header">
<Row> <Row>
@@ -197,7 +221,12 @@ function MakeJournalEntriesHeader({
CLASSES.FILL, CLASSES.FILL,
)} )}
> >
<CurrenciesSelectList /> <CurrencySelectList
currenciesList={currenciesList}
selectedCurrencyCode={values.currency_code}
onCurrencySelected={onItemsSelect('currency_code')}
defaultSelectText={baseCurrency}
/>
</FormGroup> </FormGroup>
</Col> </Col>
</Row> </Row>
@@ -205,4 +234,12 @@ function MakeJournalEntriesHeader({
); );
} }
export default compose(withDialogActions)(MakeJournalEntriesHeader); export default compose(
withDialogActions,
withSettings(({ organizationSettings }) => ({
baseCurrency: organizationSettings?.baseCurrency,
})),
withCurrencies(({ currenciesList }) => ({
currenciesList,
})),
)(MakeJournalEntriesHeader);

View File

@@ -8,6 +8,7 @@ import DashboardInsider from 'components/Dashboard/DashboardInsider';
import withCustomersActions from 'containers/Customers/withCustomersActions'; import withCustomersActions from 'containers/Customers/withCustomersActions';
import withAccountsActions from 'containers/Accounts/withAccountsActions'; import withAccountsActions from 'containers/Accounts/withAccountsActions';
import withManualJournalsActions from 'containers/Accounting/withManualJournalsActions'; import withManualJournalsActions from 'containers/Accounting/withManualJournalsActions';
import withCurrenciesActions from 'containers/Currencies/withCurrenciesActions';
import withSettingsActions from 'containers/Settings/withSettingsActions'; import withSettingsActions from 'containers/Settings/withSettingsActions';
import { compose } from 'utils'; import { compose } from 'utils';
@@ -22,6 +23,9 @@ function MakeJournalEntriesPage({
// #withManualJournalActions // #withManualJournalActions
requestFetchManualJournal, requestFetchManualJournal,
// #wihtCurrenciesActions
requestFetchCurrencies,
// #withSettingsActions // #withSettingsActions
requestFetchOptions, requestFetchOptions,
}) { }) {
@@ -36,11 +40,12 @@ function MakeJournalEntriesPage({
requestFetchCustomers(), requestFetchCustomers(),
); );
const fetchSettings = useQuery( const fetchCurrencies = useQuery('currencies', () =>
['settings'], requestFetchCurrencies(),
() => requestFetchOptions({}),
); );
const fetchSettings = useQuery(['settings'], () => requestFetchOptions({}));
const fetchJournal = useQuery( const fetchJournal = useQuery(
['manual-journal', id], ['manual-journal', id],
(key, journalId) => requestFetchManualJournal(journalId), (key, journalId) => requestFetchManualJournal(journalId),
@@ -63,6 +68,7 @@ function MakeJournalEntriesPage({
loading={ loading={
fetchJournal.isFetching || fetchJournal.isFetching ||
fetchAccounts.isFetching || fetchAccounts.isFetching ||
fetchCurrencies.isFetching ||
fetchCustomers.isFetching fetchCustomers.isFetching
} }
name={'make-journal-page'} name={'make-journal-page'}
@@ -80,5 +86,6 @@ export default compose(
withAccountsActions, withAccountsActions,
withCustomersActions, withCustomersActions,
withManualJournalsActions, withManualJournalsActions,
withSettingsActions withCurrenciesActions,
withSettingsActions,
)(MakeJournalEntriesPage); )(MakeJournalEntriesPage);

View File

@@ -68,7 +68,7 @@ function AccountFormDialogContent({
.max(255) .max(255)
.label(formatMessage({ id: 'account_name_' })), .label(formatMessage({ id: 'account_name_' })),
code: Yup.string().digits().min(3).max(6), code: Yup.string().digits().min(3).max(6),
account_type_id: Yup.number() account_type_id: Yup.number().nullable()
.required() .required()
.label(formatMessage({ id: 'account_type_id' })), .label(formatMessage({ id: 'account_type_id' })),
description: Yup.string().min(3).max(512).nullable().trim(), description: Yup.string().min(3).max(512).nullable().trim(),
@@ -76,7 +76,7 @@ function AccountFormDialogContent({
}); });
const initialValues = useMemo( const initialValues = useMemo(
() => ({ () => ({
account_type_id: null, account_type_id: '',
name: '', name: '',
code: '', code: '',
description: '', description: '',

View File

@@ -24,6 +24,7 @@ export default function ItemCategoryForm({
accountsList, accountsList,
categoriesList, categoriesList,
isSubmitting, isSubmitting,
onClose,
}) { }) {
// Filters Item Categories list. // Filters Item Categories list.
const filterItemCategories = useCallback( const filterItemCategories = useCallback(
@@ -73,7 +74,7 @@ export default function ItemCategoryForm({
</FastField> </FastField>
{/* ----------- Parent Category ----------- */} {/* ----------- Parent Category ----------- */}
<FastField name={'parent_account_id'}> <FastField name={'parent_category_id'}>
{({ form, field: { value }, meta: { error, touched } }) => ( {({ form, field: { value }, meta: { error, touched } }) => (
<FormGroup <FormGroup
label={<T id={'parent_category'} />} label={<T id={'parent_category'} />}
@@ -106,7 +107,7 @@ export default function ItemCategoryForm({
</FastField> </FastField>
{/* ----------- Description ----------- */} {/* ----------- Description ----------- */}
<FastField name={'description`'}> <FastField name={'description'}>
{({ field, field: { value }, meta: { error, touched } }) => ( {({ field, field: { value }, meta: { error, touched } }) => (
<FormGroup <FormGroup
label={<T id={'description'} />} label={<T id={'description'} />}
@@ -137,7 +138,7 @@ export default function ItemCategoryForm({
<AccountsSelectList <AccountsSelectList
accounts={accountsList} accounts={accountsList}
onAccountSelected={(account) => { onAccountSelected={(account) => {
form.setFieldValue(account.id); form.setFieldValue('cost_account_id', account.id);
}} }}
defaultSelectText={<T id={'select_account'} />} defaultSelectText={<T id={'select_account'} />}
selectedAccountId={value} selectedAccountId={value}
@@ -203,7 +204,7 @@ export default function ItemCategoryForm({
<div className={Classes.DIALOG_FOOTER}> <div className={Classes.DIALOG_FOOTER}>
<div className={Classes.DIALOG_FOOTER_ACTIONS}> <div className={Classes.DIALOG_FOOTER_ACTIONS}>
<Button> <Button onClick={onClose}>
<T id={'close'} /> <T id={'close'} />
</Button> </Button>
<Button intent={Intent.PRIMARY} type="submit" disabled={isSubmitting}> <Button intent={Intent.PRIMARY} type="submit" disabled={isSubmitting}>

View File

@@ -1,4 +1,4 @@
import React, { useMemo } from 'react'; import React, { useMemo, useCallback } from 'react';
import { Intent } from '@blueprintjs/core'; import { Intent } from '@blueprintjs/core';
import * as Yup from 'yup'; import * as Yup from 'yup';
import { useQuery, queryCache } from 'react-query'; import { useQuery, queryCache } from 'react-query';
@@ -121,6 +121,11 @@ function ItemCategoryFormDialogContent({
} }
}; };
// Handles dialog close.
const handleClose = useCallback(() => {
closeDialog(dialogName);
}, [closeDialog, dialogName]);
return ( return (
<DialogContent <DialogContent
isLoading={fetchCategoriesList.isFetching || fetchAccountsList.isFetching} isLoading={fetchCategoriesList.isFetching || fetchAccountsList.isFetching}
@@ -136,6 +141,7 @@ function ItemCategoryFormDialogContent({
accountsList={accountsList} accountsList={accountsList}
categoriesList={categoriesList} categoriesList={categoriesList}
isSubmitting={isSubmitting} isSubmitting={isSubmitting}
onClose={handleClose}
/> />
)} )}
</Formik> </Formik>

View File

@@ -9,6 +9,7 @@ import {
} from 'react-intl'; } from 'react-intl';
import AppToaster from 'components/AppToaster'; import AppToaster from 'components/AppToaster';
import DashboardPageContent from 'components/Dashboard/DashboardPageContent';
import DashboardInsider from 'components/Dashboard/DashboardInsider'; import DashboardInsider from 'components/Dashboard/DashboardInsider';
import ItemCategoriesDataTable from 'containers/Items/ItemCategoriesTable'; import ItemCategoriesDataTable from 'containers/Items/ItemCategoriesTable';
import ItemsCategoryActionsBar from 'containers/Items/ItemsCategoryActionsBar'; import ItemsCategoryActionsBar from 'containers/Items/ItemsCategoryActionsBar';
@@ -156,7 +157,7 @@ const ItemCategoryList = ({
return ( return (
<DashboardInsider <DashboardInsider
loading={fetchResourceFields.isFetching} loading={fetchResourceFields.isFetching || fetchCategories.isFetching}
name={'item-category-list'} name={'item-category-list'}
> >
<ItemsCategoryActionsBar <ItemsCategoryActionsBar
@@ -164,13 +165,12 @@ const ItemCategoryList = ({
onFilterChanged={handleFilterChanged} onFilterChanged={handleFilterChanged}
onBulkDelete={handleBulkDelete} onBulkDelete={handleBulkDelete}
/> />
<DashboardPageContent>
<ItemCategoriesDataTable <ItemCategoriesDataTable
onEditCategory={handleEditCategory} onEditCategory={handleEditCategory}
onFetchData={handleFetchData} onFetchData={handleFetchData}
onSelectedRowsChange={handleSelectedRowsChange} onSelectedRowsChange={handleSelectedRowsChange}
onDeleteCategory={handleDeleteCategory} onDeleteCategory={handleDeleteCategory}
loading={fetchCategories.isFetching}
/> />
<Alert <Alert
@@ -208,6 +208,7 @@ const ItemCategoryList = ({
/> />
</p> </p>
</Alert> </Alert>
</DashboardPageContent>
</DashboardInsider> </DashboardInsider>
); );
}; };

View File

@@ -21,6 +21,7 @@ import withDialogActions from 'containers/Dialog/withDialogActions';
const ItemsCategoryList = ({ const ItemsCategoryList = ({
// #withItemCategories // #withItemCategories
categoriesList, categoriesList,
categoriesTableLoading,
// #withDialogActions. // #withDialogActions.
openDialog, openDialog,
@@ -72,21 +73,21 @@ const ItemsCategoryList = ({
id: 'name', id: 'name',
Header: formatMessage({ id: 'category_name' }), Header: formatMessage({ id: 'category_name' }),
accessor: 'name', accessor: 'name',
width: 150, width: 220,
}, },
{ {
id: 'description', id: 'description',
Header: formatMessage({ id: 'description' }), Header: formatMessage({ id: 'description' }),
accessor: 'description', accessor: 'description',
className: 'description', className: 'description',
width: 150, width: 220,
}, },
{ {
id: 'count', id: 'count',
Header: formatMessage({ id: 'count' }), Header: formatMessage({ id: 'count' }),
accessor: 'count', accessor: 'count',
className: 'count', className: 'count',
width: 50, width: 180,
}, },
{ {
id: 'actions', id: 'actions',
@@ -94,14 +95,13 @@ const ItemsCategoryList = ({
Cell: ({ cell }) => ( Cell: ({ cell }) => (
<Popover <Popover
content={actionMenuList(cell.row.original)} content={actionMenuList(cell.row.original)}
position={Position.RIGHT_BOTTOM} position={Position.RIGHT_TOP}
> >
<Button icon={<Icon icon="more-h-16" iconSize={16} />} /> <Button icon={<Icon icon="more-h-16" iconSize={16} />} />
</Popover> </Popover>
), ),
className: 'actions', className: 'actions',
width: 50, width: 50,
disableResizing: false,
}, },
], ],
[actionMenuList, formatMessage], [actionMenuList, formatMessage],
@@ -148,9 +148,9 @@ const ItemsCategoryList = ({
manualSortBy={true} manualSortBy={true}
selectionColumn={selectionColumn} selectionColumn={selectionColumn}
expandable={true} expandable={true}
sticky={true}
onSelectedRowsChange={handleSelectedRowsChange} onSelectedRowsChange={handleSelectedRowsChange}
treeGraph={true} loading={categoriesTableLoading}
spinnerProps={{ size: 30 }}
rowContextMenu={handleRowContextMenu} rowContextMenu={handleRowContextMenu}
/> />
</LoadingIndicator> </LoadingIndicator>
@@ -158,8 +158,9 @@ const ItemsCategoryList = ({
}; };
export default compose( export default compose(
withItemCategories(({ categoriesList }) => ({ withItemCategories(({ categoriesList, categoriesTableLoading }) => ({
categoriesList, categoriesList,
categoriesTableLoading,
})), })),
withDialogActions, withDialogActions,
)(ItemsCategoryList); )(ItemsCategoryList);

View File

@@ -89,12 +89,14 @@ function ItemForm({
sku: Yup.string().trim(), sku: Yup.string().trim(),
cost_price: Yup.number().when(['purchasable'], { cost_price: Yup.number().when(['purchasable'], {
is: true, is: true,
then: Yup.number().required(), then: Yup.number().required()
.label(formatMessage({ id: 'cost_price_' })),
otherwise: Yup.number().nullable(true), otherwise: Yup.number().nullable(true),
}), }),
sell_price: Yup.number().when(['sellable'], { sell_price: Yup.number().when(['sellable'], {
is: true, is: true,
then: Yup.number().required(), then: Yup.number().required()
.label(formatMessage({ id: 'sell_price_' })),
otherwise: Yup.number().nullable(true), otherwise: Yup.number().nullable(true),
}), }),
cost_account_id: Yup.number() cost_account_id: Yup.number()

View File

@@ -54,7 +54,7 @@ export default function ItemFormFloatingActions({
</Button> </Button>
{/*----------- Active ----------*/} {/*----------- Active ----------*/}
<FastField name={'type'}> <FastField name={'active'}>
{({ field, field: { value } }) => ( {({ field, field: { value } }) => (
<FormGroup label={' '} inline={true} className={'form-group--active'}> <FormGroup label={' '} inline={true} className={'form-group--active'}>
<Checkbox <Checkbox

View File

@@ -34,7 +34,7 @@ function ItemFormPrimarySection({
categoriesList, categoriesList,
// #withDashboardActions // #withDashboardActions
changePageSubtitle changePageSubtitle,
}) { }) {
const { formatMessage } = useIntl(); const { formatMessage } = useIntl();
@@ -88,13 +88,14 @@ function ItemFormPrimarySection({
changePageSubtitle(formatMessage({ id: _value })); changePageSubtitle(formatMessage({ id: _value }));
})} })}
selectedValue={value} selectedValue={value}
disabled={value === 'inventory'}
> >
<Radio label={<T id={'service'} />} value="service" /> <Radio label={<T id={'service'} />} value="service" />
<Radio label={<T id={'inventory'} />} value="inventory" />
<Radio <Radio
label={<T id={'non_inventory'} />} label={<T id={'non_inventory'} />}
value="non-inventory" value="non-inventory"
/> />
<Radio label={<T id={'inventory'} />} value="inventory" />
</RadioGroup> </RadioGroup>
</FormGroup> </FormGroup>
)} )}
@@ -179,5 +180,5 @@ export default compose(
withItemCategories(({ categoriesList }) => ({ withItemCategories(({ categoriesList }) => ({
categoriesList, categoriesList,
})), })),
withDashboardActions withDashboardActions,
)(ItemFormPrimarySection); )(ItemFormPrimarySection);

View File

@@ -12,7 +12,6 @@ const BillFormSchema = Yup.object().shape({
.required() .required()
.label(formatMessage({ id: 'due_date_' })), .label(formatMessage({ id: 'due_date_' })),
bill_number: Yup.string() bill_number: Yup.string()
.required()
.label(formatMessage({ id: 'bill_number_' })), .label(formatMessage({ id: 'bill_number_' })),
reference_no: Yup.string().nullable().min(1).max(255), reference_no: Yup.string().nullable().min(1).max(255),
note: Yup.string() note: Yup.string()

View File

@@ -12,10 +12,9 @@ const Schema = Yup.object().shape({
.required() .required()
.label(formatMessage({ id: 'expiration_date_' })), .label(formatMessage({ id: 'expiration_date_' })),
estimate_number: Yup.string() estimate_number: Yup.string()
.required()
.nullable() .nullable()
.label(formatMessage({ id: 'estimate_number_' })), .label(formatMessage({ id: 'estimate_number_' })),
reference: Yup.string().min(1).max(255), reference: Yup.string().min(1).max(255).nullable(),
note: Yup.string() note: Yup.string()
.trim() .trim()
.min(1) .min(1)

View File

@@ -11,7 +11,8 @@ const Schema = Yup.object().shape({
due_date: Yup.date() due_date: Yup.date()
.required() .required()
.label(formatMessage({ id: 'due_date_' })), .label(formatMessage({ id: 'due_date_' })),
invoice_no: Yup.string().label(formatMessage({ id: 'invoice_no_' })), invoice_no: Yup.string()
.label(formatMessage({ id: 'invoice_no_' })),
reference_no: Yup.string().min(1).max(255), reference_no: Yup.string().min(1).max(255),
status: Yup.string().required(), status: Yup.string().required(),
invoice_message: Yup.string() invoice_message: Yup.string()

View File

@@ -9,7 +9,6 @@ const Schema = Yup.object().shape({
.required() .required()
.label(formatMessage({ id: 'receipt_date_' })), .label(formatMessage({ id: 'receipt_date_' })),
receipt_number: Yup.string() receipt_number: Yup.string()
.required()
.label(formatMessage({ id: 'receipt_no_' })), .label(formatMessage({ id: 'receipt_no_' })),
deposit_account_id: Yup.number() deposit_account_id: Yup.number()
.required() .required()

View File

@@ -107,6 +107,8 @@ export default {
draft: 'Draft', draft: 'Draft',
published: 'Published', published: 'Published',
new_item: 'New Item', new_item: 'New Item',
cost_price_: 'Cost price',
sell_price_: 'Sell price',
table_views: 'Table Views', table_views: 'Table Views',
delete: 'Delete', delete: 'Delete',
delete_count: 'Delete ({count})', delete_count: 'Delete ({count})',