Merge remote-tracking branch 'origin/Tasks'

This commit is contained in:
Ahmed Bouhuolia
2020-10-20 20:08:53 +02:00
13 changed files with 414 additions and 94 deletions

View File

@@ -6,10 +6,11 @@ export default function MakeJournalEntriesFooter({
formik: { isSubmitting },
onSubmitClick,
onCancelClick,
manualJournal,
}) {
return (
<div>
<div class='form__floating-footer'>
<div class="form__floating-footer">
<Button
disabled={isSubmitting}
intent={Intent.PRIMARY}
@@ -18,7 +19,11 @@ export default function MakeJournalEntriesFooter({
onSubmitClick({ publish: true, redirect: true });
}}
>
<T id={'save'} />
{manualJournal && manualJournal.id ? (
<T id={'edit'} />
) : (
<T id={'save'} />
)}
</Button>
<Button
@@ -49,7 +54,7 @@ export default function MakeJournalEntriesFooter({
onCancelClick && onCancelClick();
}}
>
<T id={'cancel'}/>
<T id={'cancel'} />
</Button>
</div>
</div>

View File

@@ -34,7 +34,8 @@ const ERROR = {
VENDORS_NOT_WITH_PAYABLE_ACCOUNT: 'VENDORS.NOT.WITH.PAYABLE.ACCOUNT',
PAYABLE_ENTRIES_HAS_NO_VENDORS: 'PAYABLE.ENTRIES.HAS.NO.VENDORS',
RECEIVABLE_ENTRIES_HAS_NO_CUSTOMERS: 'RECEIVABLE.ENTRIES.HAS.NO.CUSTOMERS',
CREDIT_DEBIT_SUMATION_SHOULD_NOT_EQUAL_ZERO:'CREDIT.DEBIT.SUMATION.SHOULD.NOT.EQUAL.ZERO'
CREDIT_DEBIT_SUMATION_SHOULD_NOT_EQUAL_ZERO:
'CREDIT.DEBIT.SUMATION.SHOULD.NOT.EQUAL.ZERO',
};
/**
@@ -58,7 +59,6 @@ function MakeJournalEntriesForm({
onFormSubmit,
onCancelForm,
}) {
const { formatMessage } = useIntl();
const {
setFiles,
@@ -75,7 +75,6 @@ function MakeJournalEntriesForm({
setFiles(_files.filter((file) => file.uploaded === false));
}, []);
const savedMediaIds = useRef([]);
const clearSavedMediaIds = () => {
savedMediaIds.current = [];
@@ -140,6 +139,7 @@ function MakeJournalEntriesForm({
const defaultEntry = useMemo(
() => ({
index: 0,
account_id: null,
credit: 0,
debit: 0,
@@ -251,7 +251,7 @@ function MakeJournalEntriesForm({
}),
intent: Intent.DANGER,
});
}
}
};
const formik = useFormik({
@@ -262,7 +262,7 @@ function MakeJournalEntriesForm({
},
onSubmit: async (values, { setErrors, setSubmitting, resetForm }) => {
const entries = values.entries.filter(
(entry) => entry.credit || entry.debit,
(entry) => entry.debit || entry.credit,
);
const getTotal = (type = 'credit') => {
return entries.reduce((total, item) => {
@@ -413,6 +413,7 @@ function MakeJournalEntriesForm({
formik={formik}
onSubmitClick={handleSubmitClick}
onCancelClick={handleCancelClick}
manualJournal={manualJournal}
/>
</form>

View File

@@ -5,6 +5,7 @@ import {
Intent,
Position,
Classes,
Button,
} from '@blueprintjs/core';
import { DateInput } from '@blueprintjs/datetime';
import { FormattedMessage as T } from 'react-intl';
@@ -18,11 +19,18 @@ import {
Hint,
FieldHint,
FieldRequiredHint,
Icon,
} from 'components';
import withDialogActions from 'containers/Dialog/withDialogActions';
export default function MakeJournalEntriesHeader({
import { compose } from 'utils';
function MakeJournalEntriesHeader({
formik: { errors, touched, values, setFieldValue, getFieldProps },
// #withDialog
openDialog,
}) {
const handleDateChange = useCallback(
(date) => {
@@ -31,6 +39,9 @@ export default function MakeJournalEntriesHeader({
},
[setFieldValue],
);
const handleJournalNumberChange = useCallback(() => {
openDialog('journalNumber-form', {});
}, [openDialog]);
return (
<div class="make-journal-entries__header">
@@ -62,7 +73,15 @@ export default function MakeJournalEntriesHeader({
/>
</FormGroup>
</Col>
<Col width={50}>
{/* <FormGroup> */}
<Button
className={classNames('btn', Classes.SMALL)}
icon={<Icon icon="setting" />}
onClick={handleJournalNumberChange}
/>
{/* </FormGroup> */}
</Col>
<Col width={220}>
<FormGroup
label={<T id={'date'} />}
@@ -153,3 +172,5 @@ export default function MakeJournalEntriesHeader({
</div>
);
}
export default compose(withDialogActions)(MakeJournalEntriesHeader);

View File

@@ -78,15 +78,9 @@ function ItemCategoryDialog({
.required()
.label(formatMessage({ id: 'category_name_' })),
parent_category_id: Yup.string().nullable(),
cost_account_id: Yup.number()
.required()
.label(formatMessage({ id: 'cost_account_' })),
sell_account_id: Yup.number()
.required()
.label(formatMessage({ id: 'sell_account_' })),
inventory_account_id: Yup.number()
.required()
.label(formatMessage({ id: 'inventory_account_' })),
cost_account_id: Yup.number().nullable(),
sell_account_id: Yup.number().nullable(),
inventory_account_id: Yup.number(),
description: Yup.string().trim().nullable(),
});
@@ -122,7 +116,7 @@ function ItemCategoryDialog({
onSubmit: (values, { setSubmitting }) => {
const afterSubmit = () => {
closeDialog(dialogName);
queryCache.invalidateQueries('items-categories-table');
queryCache.invalidateQueries('items-categories-list');
queryCache.invalidateQueries('accounts-list');
};
if (payload.action === 'edit') {

View File

@@ -0,0 +1,71 @@
import React, { useEffect, useCallback, useMemo } from 'react';
import { FormattedMessage as T, useIntl } from 'react-intl';
import { useQuery, queryCache } from 'react-query';
import { Dialog } from 'components';
import withDialogActions from 'containers/Dialog/withDialogActions';
import withDialogRedux from 'components/DialogReduxConnect';
import withSettingsActions from 'containers/Settings/withSettingsActions';
import withSettings from 'containers/Settings/withSettings';
import ReferenceNumberForm from 'containers/JournalNumber/ReferenceNumberForm';
import classNames from 'classnames';
import { connect } from 'react-redux';
import { compose, optionsMapToArray } from 'utils';
function JournalNumberDailog({
dialogName,
payload,
isOpen,
// #withSettingsActions
requestSubmitOptions,
// #withDialogActions
closeDialog,
}) {
// Handles dialog close.
const handleClose = useCallback(() => {
closeDialog(dialogName);
}, [closeDialog, dialogName]);
const handleSubmitForm = useCallback(() => {});
// Handle dialog on closed.
// const onDialogClosed = useCallback(() => {
// resetForm();
// }, [resetForm]);
return (
<Dialog
name={dialogName}
// isLoading={}
title={<T id={'journal_number_settings'} />}
autoFocus={true}
canEscapeKeyClose={true}
isOpen={isOpen}
onClose={handleClose}
>
<ReferenceNumberForm
onSubmit={handleSubmitForm}
initialNumber={'1000'}
initialPrefix={'A'}
onClose={handleClose}
groupName={'manual_journals'}
/>
</Dialog>
);
}
const mapStateToProps = (state, props) => ({
dialogName: 'journalNumber-form',
journalNumberId: props?.payload?.id || null,
});
const withJournalNumberDailog = connect(mapStateToProps);
export default compose(
withDialogRedux(null, 'journalNumber-form'),
withJournalNumberDailog,
withDialogActions,
withSettingsActions,
)(JournalNumberDailog);

View File

@@ -164,10 +164,10 @@ function ExpenseForm({
...expense.categories.map((category) => ({
...pick(category, Object.keys(defaultCategory)),
})),
...repeatValue(
defaultCategory,
Math.max(MIN_LINES_NUMBER - expense.categories.length, 0),
),
// ...repeatValue(
// defaultCategory,
// Math.max(MIN_LINES_NUMBER - expense.categories.length, 0),
// ),
],
}
: {
@@ -226,10 +226,12 @@ function ExpenseForm({
});
return;
}
const categories = values.categories.filter(
(category) =>
category.amount && category.index && category.expense_account_id,
);
const form = {
...values,
publish: payload.publish,
@@ -329,10 +331,21 @@ function ExpenseForm({
const handleClearAllLines = () => {
formik.setFieldValue(
'categories',
orderingCategoriesIndex([...repeatValue(defaultCategory, MIN_LINES_NUMBER)]),
orderingCategoriesIndex([
...repeatValue(defaultCategory, MIN_LINES_NUMBER),
]),
);
};
const categories = formik.values.categories.filter(
(category) =>
category.amount && category.index && category.expense_account_id,
);
console.log(categories, 'V');
console.log(formik.errors, 'Error');
return (
<div className={'expense-form'}>
<form onSubmit={formik.handleSubmit}>

View File

@@ -22,12 +22,14 @@ import {
} from 'components';
import withCurrencies from 'containers/Currencies/withCurrencies';
import withAccounts from 'containers/Accounts/withAccounts';
import withCustomers from 'containers/Customers/withCustomers';
function ExpenseFormHeader({
formik: { errors, touched, setFieldValue, getFieldProps, values },
currenciesList,
accountsList,
accountsTypes,
customersItems,
}) {
const [selectedItems, setSelectedItems] = useState({});
@@ -84,10 +86,46 @@ function ExpenseFormHeader({
// Filter payment accounts.
const paymentAccounts = useMemo(
() => accountsList.filter(a => a?.type?.key === 'current_asset'),
() => accountsList.filter((a) => a?.type?.key === 'current_asset'),
[accountsList],
);
const CustomerRenderer = useCallback(
(cutomer, { handleClick }) => (
<MenuItem
key={cutomer.id}
text={cutomer.display_name}
onClick={handleClick}
/>
),
[],
);
// Filter Customer
const filterCustomer = (query, customer, _index, exactMatch) => {
const normalizedTitle = customer.display_name.toLowerCase();
const normalizedQuery = query.toLowerCase();
if (exactMatch) {
return normalizedTitle === normalizedQuery;
} else {
return (
`${customer.display_name} ${normalizedTitle}`.indexOf(
normalizedQuery,
) >= 0
);
}
};
// handle change customer
const onChangeCustomer = useCallback(
(filedName) => {
return (customer) => {
setFieldValue(filedName, customer.id);
};
},
[setFieldValue],
);
return (
<div className={'dashboard__insider--expense-form__header'}>
<Row>
@@ -105,16 +143,16 @@ function ExpenseFormHeader({
}
>
<ListSelect
items={[]}
items={customersItems}
noResults={<MenuItem disabled={true} text="No results." />}
// itemRenderer={}
// itemPredicate={}
itemRenderer={CustomerRenderer}
itemPredicate={filterCustomer}
popoverProps={{ minimal: true }}
// onItemSelect={}
selectedItem={values.beneficiary}
// selectedItemProp={'id'}
defaultText={<T id={'select_customer'} />}
labelProp={'beneficiary'}
onItemSelect={onChangeCustomer('customer_id')}
selectedItem={values.customer_id}
selectedItemProp={'id'}
defaultText={<T id={'select_customer_account'} />}
labelProp={'display_name'}
/>
</FormGroup>
</Col>
@@ -235,4 +273,7 @@ export default compose(
withCurrencies(({ currenciesList }) => ({
currenciesList,
})),
withCustomers(({ customersItems }) => ({
customersItems,
})),
)(ExpenseFormHeader);

View File

@@ -8,6 +8,7 @@ import DashboardInsider from 'components/Dashboard/DashboardInsider';
import withAccountsActions from 'containers/Accounts/withAccountsActions';
import withExpensesActions from 'containers/Expenses/withExpensesActions';
import withCurrenciesActions from 'containers/Currencies/withCurrenciesActions';
import withCustomersActions from 'containers/Customers/withCustomersActions';
import { compose } from 'utils';
@@ -21,6 +22,9 @@ function Expenses({
// #wihtCurrenciesActions
requestFetchCurrencies,
// #withCustomersActions
requestFetchCustomers,
}) {
const history = useHistory();
const { id } = useParams();
@@ -38,6 +42,12 @@ function Expenses({
const fetchCurrencies = useQuery('currencies', () =>
requestFetchCurrencies(),
);
// Handle fetch customers data table or list
const fetchCustomers = useQuery('customers-table', () =>
requestFetchCustomers({}),
);
const handleFormSubmit = useCallback(
(payload) => {
payload.redirect && history.push('/expenses-list');
@@ -54,7 +64,8 @@ function Expenses({
loading={
fetchExpense.isFetching ||
fetchAccounts.isFetching ||
fetchCurrencies.isFetching
fetchCurrencies.isFetching ||
fetchCustomers.isFetching
}
name={'expense-form'}
>
@@ -71,4 +82,5 @@ export default compose(
withAccountsActions,
withCurrenciesActions,
withExpensesActions,
withCustomersActions,
)(Expenses);

View File

@@ -0,0 +1,152 @@
import React, { useMemo, useCallback } from 'react';
import * as Yup from 'yup';
import { useFormik } from 'formik';
import { Row, Col } from 'react-grid-system';
import { FormattedMessage as T, useIntl } from 'react-intl';
import { ErrorMessage, AppToaster } from 'components';
import {
Button,
Classes,
FormGroup,
InputGroup,
Intent,
Position,
} from '@blueprintjs/core';
import { compose, optionsMapToArray } from 'utils';
import withSettingsActions from 'containers/Settings/withSettingsActions';
import withSettings from 'containers/Settings/withSettings';
function ReferenceNumberForm({
onSubmit,
onClose,
initialPrefix,
initialNumber,
groupName,
requestSubmitOptions,
}) {
const { formatMessage } = useIntl();
const validationSchema = Yup.object().shape({
prefix: Yup.string(),
next_number: Yup.number(),
});
const initialValues = useMemo(
() => ({
prefix: initialPrefix || '',
next_number: initialNumber || '',
}),
[],
);
const {
errors,
values,
touched,
setFieldValue,
resetForm,
handleSubmit,
isSubmitting,
getFieldProps,
} = useFormik({
enableReinitialize: true,
initialValues: {
...initialValues,
},
validationSchema,
onSubmit: (values, { setSubmitting, setErrors }) => {
const options = optionsMapToArray(values).map((option) => {
return { key: option.key, ...option, group: groupName };
});
onSubmit(
requestSubmitOptions({ options })
.then(() => {
setSubmitting(false);
})
.catch((erros) => {
setSubmitting(false);
}),
);
},
});
// Handles dialog close.
// const handleClose = useCallback(() => {
// closeDialog(dialogName);
// }, [closeDialog, dialogName]);
// Handle dialog on closed.
const onClosed = useCallback(() => {
resetForm();
}, [resetForm]);
return (
<div>
<form onSubmit={handleSubmit}>
<div className={Classes.DIALOG_BODY}>
<p className="paragraph">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce
tincidunt porta quam,
</p>
<Row>
{/* prefix */}
<Col>
<FormGroup
label={<T id={'prefix'} />}
className={'form-group--'}
intent={errors.prefix && touched.prefix && Intent.DANGER}
helperText={
<ErrorMessage name={'prefix'} {...{ errors, touched }} />
}
>
<InputGroup
intent={errors.prefix && touched.prefix && Intent.DANGER}
{...getFieldProps('prefix')}
/>
</FormGroup>
</Col>
{/* next_number */}
<Col>
<FormGroup
label={<T id={'next_number'} />}
className={'form-group--'}
intent={
errors.next_number && touched.next_number && Intent.DANGER
}
helperText={
<ErrorMessage name={'next_number'} {...{ errors, touched }} />
}
>
<InputGroup
intent={
errors.next_number && touched.next_number && Intent.DANGER
}
{...getFieldProps('next_number')}
/>
</FormGroup>
</Col>
</Row>
</div>
<div className={Classes.DIALOG_FOOTER}>
<div className={Classes.DIALOG_FOOTER_ACTIONS}>
<Button onClick={onClose}>
<T id={'cancel'} />
</Button>
<Button
intent={Intent.PRIMARY}
type="submit"
disabled={isSubmitting}
>
<T id={'submit'} />
</Button>
</div>
</div>
</form>
</div>
);
}
export default compose(withSettingsActions)(ReferenceNumberForm);