mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-20 23:00:34 +00:00
WIP: Feature JournalNumber dialog / Fix: ItemCategory & EditMakeJournal & Expenses
This commit is contained in:
@@ -5,6 +5,7 @@ import ItemCategoryDialog from 'containers/Dialogs/ItemCategoryDialog';
|
|||||||
import CurrencyDialog from 'containers/Dialogs/CurrencyDialog';
|
import CurrencyDialog from 'containers/Dialogs/CurrencyDialog';
|
||||||
import InviteUserDialog from 'containers/Dialogs/InviteUserDialog';
|
import InviteUserDialog from 'containers/Dialogs/InviteUserDialog';
|
||||||
import ExchangeRateDialog from 'containers/Dialogs/ExchangeRateDialog';
|
import ExchangeRateDialog from 'containers/Dialogs/ExchangeRateDialog';
|
||||||
|
import JournalNumberDailog from 'containers/Dialogs/JournalNumberDailog';
|
||||||
|
|
||||||
export default function DialogsContainer() {
|
export default function DialogsContainer() {
|
||||||
return (
|
return (
|
||||||
@@ -15,6 +16,7 @@ export default function DialogsContainer() {
|
|||||||
<ItemCategoryDialog />
|
<ItemCategoryDialog />
|
||||||
<AccountFormDialog />
|
<AccountFormDialog />
|
||||||
{/* <UserFormDialog /> */}
|
{/* <UserFormDialog /> */}
|
||||||
|
<JournalNumberDailog />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,10 +6,11 @@ export default function MakeJournalEntriesFooter({
|
|||||||
formik: { isSubmitting },
|
formik: { isSubmitting },
|
||||||
onSubmitClick,
|
onSubmitClick,
|
||||||
onCancelClick,
|
onCancelClick,
|
||||||
|
manualJournal,
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div class='form__floating-footer'>
|
<div class="form__floating-footer">
|
||||||
<Button
|
<Button
|
||||||
disabled={isSubmitting}
|
disabled={isSubmitting}
|
||||||
intent={Intent.PRIMARY}
|
intent={Intent.PRIMARY}
|
||||||
@@ -18,7 +19,11 @@ export default function MakeJournalEntriesFooter({
|
|||||||
onSubmitClick({ publish: true, redirect: true });
|
onSubmitClick({ publish: true, redirect: true });
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
{manualJournal && manualJournal.id ? (
|
||||||
|
<T id={'edit'} />
|
||||||
|
) : (
|
||||||
<T id={'save'} />
|
<T id={'save'} />
|
||||||
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
@@ -49,7 +54,7 @@ export default function MakeJournalEntriesFooter({
|
|||||||
onCancelClick && onCancelClick();
|
onCancelClick && onCancelClick();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<T id={'cancel'}/>
|
<T id={'cancel'} />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -34,7 +34,8 @@ const ERROR = {
|
|||||||
VENDORS_NOT_WITH_PAYABLE_ACCOUNT: 'VENDORS.NOT.WITH.PAYABLE.ACCOUNT',
|
VENDORS_NOT_WITH_PAYABLE_ACCOUNT: 'VENDORS.NOT.WITH.PAYABLE.ACCOUNT',
|
||||||
PAYABLE_ENTRIES_HAS_NO_VENDORS: 'PAYABLE.ENTRIES.HAS.NO.VENDORS',
|
PAYABLE_ENTRIES_HAS_NO_VENDORS: 'PAYABLE.ENTRIES.HAS.NO.VENDORS',
|
||||||
RECEIVABLE_ENTRIES_HAS_NO_CUSTOMERS: 'RECEIVABLE.ENTRIES.HAS.NO.CUSTOMERS',
|
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,
|
onFormSubmit,
|
||||||
onCancelForm,
|
onCancelForm,
|
||||||
}) {
|
}) {
|
||||||
|
|
||||||
const { formatMessage } = useIntl();
|
const { formatMessage } = useIntl();
|
||||||
const {
|
const {
|
||||||
setFiles,
|
setFiles,
|
||||||
@@ -75,7 +75,6 @@ function MakeJournalEntriesForm({
|
|||||||
setFiles(_files.filter((file) => file.uploaded === false));
|
setFiles(_files.filter((file) => file.uploaded === false));
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
||||||
const savedMediaIds = useRef([]);
|
const savedMediaIds = useRef([]);
|
||||||
const clearSavedMediaIds = () => {
|
const clearSavedMediaIds = () => {
|
||||||
savedMediaIds.current = [];
|
savedMediaIds.current = [];
|
||||||
@@ -140,6 +139,7 @@ function MakeJournalEntriesForm({
|
|||||||
|
|
||||||
const defaultEntry = useMemo(
|
const defaultEntry = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
|
index: 0,
|
||||||
account_id: null,
|
account_id: null,
|
||||||
credit: 0,
|
credit: 0,
|
||||||
debit: 0,
|
debit: 0,
|
||||||
@@ -262,7 +262,7 @@ function MakeJournalEntriesForm({
|
|||||||
},
|
},
|
||||||
onSubmit: async (values, { setErrors, setSubmitting, resetForm }) => {
|
onSubmit: async (values, { setErrors, setSubmitting, resetForm }) => {
|
||||||
const entries = values.entries.filter(
|
const entries = values.entries.filter(
|
||||||
(entry) => entry.credit || entry.debit,
|
(entry) => entry.debit || entry.credit,
|
||||||
);
|
);
|
||||||
const getTotal = (type = 'credit') => {
|
const getTotal = (type = 'credit') => {
|
||||||
return entries.reduce((total, item) => {
|
return entries.reduce((total, item) => {
|
||||||
@@ -413,6 +413,7 @@ function MakeJournalEntriesForm({
|
|||||||
formik={formik}
|
formik={formik}
|
||||||
onSubmitClick={handleSubmitClick}
|
onSubmitClick={handleSubmitClick}
|
||||||
onCancelClick={handleCancelClick}
|
onCancelClick={handleCancelClick}
|
||||||
|
manualJournal={manualJournal}
|
||||||
/>
|
/>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {
|
|||||||
Intent,
|
Intent,
|
||||||
Position,
|
Position,
|
||||||
Classes,
|
Classes,
|
||||||
|
Button,
|
||||||
} from '@blueprintjs/core';
|
} from '@blueprintjs/core';
|
||||||
import { DateInput } from '@blueprintjs/datetime';
|
import { DateInput } from '@blueprintjs/datetime';
|
||||||
import { FormattedMessage as T } from 'react-intl';
|
import { FormattedMessage as T } from 'react-intl';
|
||||||
@@ -18,11 +19,18 @@ import {
|
|||||||
Hint,
|
Hint,
|
||||||
FieldHint,
|
FieldHint,
|
||||||
FieldRequiredHint,
|
FieldRequiredHint,
|
||||||
|
Icon,
|
||||||
} from 'components';
|
} from 'components';
|
||||||
|
|
||||||
|
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||||
|
|
||||||
export default function MakeJournalEntriesHeader({
|
import { compose } from 'utils';
|
||||||
|
|
||||||
|
function MakeJournalEntriesHeader({
|
||||||
formik: { errors, touched, values, setFieldValue, getFieldProps },
|
formik: { errors, touched, values, setFieldValue, getFieldProps },
|
||||||
|
|
||||||
|
// #withDialog
|
||||||
|
openDialog,
|
||||||
}) {
|
}) {
|
||||||
const handleDateChange = useCallback(
|
const handleDateChange = useCallback(
|
||||||
(date) => {
|
(date) => {
|
||||||
@@ -31,6 +39,9 @@ export default function MakeJournalEntriesHeader({
|
|||||||
},
|
},
|
||||||
[setFieldValue],
|
[setFieldValue],
|
||||||
);
|
);
|
||||||
|
const handleJournalNumberChange = useCallback(() => {
|
||||||
|
openDialog('journalNumber-form', {});
|
||||||
|
}, [openDialog]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="make-journal-entries__header">
|
<div class="make-journal-entries__header">
|
||||||
@@ -62,7 +73,15 @@ export default function MakeJournalEntriesHeader({
|
|||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
</Col>
|
</Col>
|
||||||
|
<Col width={50}>
|
||||||
|
{/* <FormGroup> */}
|
||||||
|
<Button
|
||||||
|
className={classNames('btn', Classes.SMALL)}
|
||||||
|
icon={<Icon icon="setting" />}
|
||||||
|
onClick={handleJournalNumberChange}
|
||||||
|
/>
|
||||||
|
{/* </FormGroup> */}
|
||||||
|
</Col>
|
||||||
<Col width={220}>
|
<Col width={220}>
|
||||||
<FormGroup
|
<FormGroup
|
||||||
label={<T id={'date'} />}
|
label={<T id={'date'} />}
|
||||||
@@ -153,3 +172,5 @@ export default function MakeJournalEntriesHeader({
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default compose(withDialogActions)(MakeJournalEntriesHeader);
|
||||||
|
|||||||
@@ -78,15 +78,9 @@ function ItemCategoryDialog({
|
|||||||
.required()
|
.required()
|
||||||
.label(formatMessage({ id: 'category_name_' })),
|
.label(formatMessage({ id: 'category_name_' })),
|
||||||
parent_category_id: Yup.string().nullable(),
|
parent_category_id: Yup.string().nullable(),
|
||||||
cost_account_id: Yup.number()
|
cost_account_id: Yup.number().nullable(),
|
||||||
.required()
|
sell_account_id: Yup.number().nullable(),
|
||||||
.label(formatMessage({ id: 'cost_account_' })),
|
inventory_account_id: Yup.number(),
|
||||||
sell_account_id: Yup.number()
|
|
||||||
.required()
|
|
||||||
.label(formatMessage({ id: 'sell_account_' })),
|
|
||||||
inventory_account_id: Yup.number()
|
|
||||||
.required()
|
|
||||||
.label(formatMessage({ id: 'inventory_account_' })),
|
|
||||||
description: Yup.string().trim().nullable(),
|
description: Yup.string().trim().nullable(),
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -122,7 +116,7 @@ function ItemCategoryDialog({
|
|||||||
onSubmit: (values, { setSubmitting }) => {
|
onSubmit: (values, { setSubmitting }) => {
|
||||||
const afterSubmit = () => {
|
const afterSubmit = () => {
|
||||||
closeDialog(dialogName);
|
closeDialog(dialogName);
|
||||||
queryCache.invalidateQueries('items-categories-table');
|
queryCache.invalidateQueries('items-categories-list');
|
||||||
queryCache.invalidateQueries('accounts-list');
|
queryCache.invalidateQueries('accounts-list');
|
||||||
};
|
};
|
||||||
if (payload.action === 'edit') {
|
if (payload.action === 'edit') {
|
||||||
|
|||||||
71
client/src/containers/Dialogs/JournalNumberDailog.js
Normal file
71
client/src/containers/Dialogs/JournalNumberDailog.js
Normal 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);
|
||||||
@@ -164,10 +164,10 @@ function ExpenseForm({
|
|||||||
...expense.categories.map((category) => ({
|
...expense.categories.map((category) => ({
|
||||||
...pick(category, Object.keys(defaultCategory)),
|
...pick(category, Object.keys(defaultCategory)),
|
||||||
})),
|
})),
|
||||||
...repeatValue(
|
// ...repeatValue(
|
||||||
defaultCategory,
|
// defaultCategory,
|
||||||
Math.max(MIN_LINES_NUMBER - expense.categories.length, 0),
|
// Math.max(MIN_LINES_NUMBER - expense.categories.length, 0),
|
||||||
),
|
// ),
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
: {
|
: {
|
||||||
@@ -226,10 +226,12 @@ function ExpenseForm({
|
|||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const categories = values.categories.filter(
|
const categories = values.categories.filter(
|
||||||
(category) =>
|
(category) =>
|
||||||
category.amount && category.index && category.expense_account_id,
|
category.amount && category.index && category.expense_account_id,
|
||||||
);
|
);
|
||||||
|
|
||||||
const form = {
|
const form = {
|
||||||
...values,
|
...values,
|
||||||
publish: payload.publish,
|
publish: payload.publish,
|
||||||
@@ -329,10 +331,21 @@ function ExpenseForm({
|
|||||||
const handleClearAllLines = () => {
|
const handleClearAllLines = () => {
|
||||||
formik.setFieldValue(
|
formik.setFieldValue(
|
||||||
'categories',
|
'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 (
|
return (
|
||||||
<div className={'expense-form'}>
|
<div className={'expense-form'}>
|
||||||
<form onSubmit={formik.handleSubmit}>
|
<form onSubmit={formik.handleSubmit}>
|
||||||
|
|||||||
@@ -22,12 +22,14 @@ import {
|
|||||||
} from 'components';
|
} from 'components';
|
||||||
import withCurrencies from 'containers/Currencies/withCurrencies';
|
import withCurrencies from 'containers/Currencies/withCurrencies';
|
||||||
import withAccounts from 'containers/Accounts/withAccounts';
|
import withAccounts from 'containers/Accounts/withAccounts';
|
||||||
|
import withCustomers from 'containers/Customers/withCustomers';
|
||||||
|
|
||||||
function ExpenseFormHeader({
|
function ExpenseFormHeader({
|
||||||
formik: { errors, touched, setFieldValue, getFieldProps, values },
|
formik: { errors, touched, setFieldValue, getFieldProps, values },
|
||||||
currenciesList,
|
currenciesList,
|
||||||
accountsList,
|
accountsList,
|
||||||
accountsTypes,
|
accountsTypes,
|
||||||
|
customersItems,
|
||||||
}) {
|
}) {
|
||||||
const [selectedItems, setSelectedItems] = useState({});
|
const [selectedItems, setSelectedItems] = useState({});
|
||||||
|
|
||||||
@@ -84,10 +86,46 @@ function ExpenseFormHeader({
|
|||||||
|
|
||||||
// Filter payment accounts.
|
// Filter payment accounts.
|
||||||
const paymentAccounts = useMemo(
|
const paymentAccounts = useMemo(
|
||||||
() => accountsList.filter(a => a?.type?.key === 'current_asset'),
|
() => accountsList.filter((a) => a?.type?.key === 'current_asset'),
|
||||||
[accountsList],
|
[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 (
|
return (
|
||||||
<div className={'dashboard__insider--expense-form__header'}>
|
<div className={'dashboard__insider--expense-form__header'}>
|
||||||
<Row>
|
<Row>
|
||||||
@@ -105,16 +143,16 @@ function ExpenseFormHeader({
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<ListSelect
|
<ListSelect
|
||||||
items={[]}
|
items={customersItems}
|
||||||
noResults={<MenuItem disabled={true} text="No results." />}
|
noResults={<MenuItem disabled={true} text="No results." />}
|
||||||
// itemRenderer={}
|
itemRenderer={CustomerRenderer}
|
||||||
// itemPredicate={}
|
itemPredicate={filterCustomer}
|
||||||
popoverProps={{ minimal: true }}
|
popoverProps={{ minimal: true }}
|
||||||
// onItemSelect={}
|
onItemSelect={onChangeCustomer('customer_id')}
|
||||||
selectedItem={values.beneficiary}
|
selectedItem={values.customer_id}
|
||||||
// selectedItemProp={'id'}
|
selectedItemProp={'id'}
|
||||||
defaultText={<T id={'select_customer'} />}
|
defaultText={<T id={'select_customer_account'} />}
|
||||||
labelProp={'beneficiary'}
|
labelProp={'display_name'}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
</Col>
|
</Col>
|
||||||
@@ -235,4 +273,7 @@ export default compose(
|
|||||||
withCurrencies(({ currenciesList }) => ({
|
withCurrencies(({ currenciesList }) => ({
|
||||||
currenciesList,
|
currenciesList,
|
||||||
})),
|
})),
|
||||||
|
withCustomers(({ customersItems }) => ({
|
||||||
|
customersItems,
|
||||||
|
})),
|
||||||
)(ExpenseFormHeader);
|
)(ExpenseFormHeader);
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import DashboardInsider from 'components/Dashboard/DashboardInsider';
|
|||||||
import withAccountsActions from 'containers/Accounts/withAccountsActions';
|
import withAccountsActions from 'containers/Accounts/withAccountsActions';
|
||||||
import withExpensesActions from 'containers/Expenses/withExpensesActions';
|
import withExpensesActions from 'containers/Expenses/withExpensesActions';
|
||||||
import withCurrenciesActions from 'containers/Currencies/withCurrenciesActions';
|
import withCurrenciesActions from 'containers/Currencies/withCurrenciesActions';
|
||||||
|
import withCustomersActions from 'containers/Customers/withCustomersActions';
|
||||||
|
|
||||||
import { compose } from 'utils';
|
import { compose } from 'utils';
|
||||||
|
|
||||||
@@ -21,6 +22,9 @@ function Expenses({
|
|||||||
|
|
||||||
// #wihtCurrenciesActions
|
// #wihtCurrenciesActions
|
||||||
requestFetchCurrencies,
|
requestFetchCurrencies,
|
||||||
|
|
||||||
|
// #withCustomersActions
|
||||||
|
requestFetchCustomers,
|
||||||
}) {
|
}) {
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
@@ -38,6 +42,12 @@ function Expenses({
|
|||||||
const fetchCurrencies = useQuery('currencies', () =>
|
const fetchCurrencies = useQuery('currencies', () =>
|
||||||
requestFetchCurrencies(),
|
requestFetchCurrencies(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Handle fetch customers data table or list
|
||||||
|
const fetchCustomers = useQuery('customers-table', () =>
|
||||||
|
requestFetchCustomers({}),
|
||||||
|
);
|
||||||
|
|
||||||
const handleFormSubmit = useCallback(
|
const handleFormSubmit = useCallback(
|
||||||
(payload) => {
|
(payload) => {
|
||||||
payload.redirect && history.push('/expenses-list');
|
payload.redirect && history.push('/expenses-list');
|
||||||
@@ -54,7 +64,8 @@ function Expenses({
|
|||||||
loading={
|
loading={
|
||||||
fetchExpense.isFetching ||
|
fetchExpense.isFetching ||
|
||||||
fetchAccounts.isFetching ||
|
fetchAccounts.isFetching ||
|
||||||
fetchCurrencies.isFetching
|
fetchCurrencies.isFetching ||
|
||||||
|
fetchCustomers.isFetching
|
||||||
}
|
}
|
||||||
name={'expense-form'}
|
name={'expense-form'}
|
||||||
>
|
>
|
||||||
@@ -71,4 +82,5 @@ export default compose(
|
|||||||
withAccountsActions,
|
withAccountsActions,
|
||||||
withCurrenciesActions,
|
withCurrenciesActions,
|
||||||
withExpensesActions,
|
withExpensesActions,
|
||||||
|
withCustomersActions,
|
||||||
)(Expenses);
|
)(Expenses);
|
||||||
|
|||||||
152
client/src/containers/JournalNumber/ReferenceNumberForm.js
Normal file
152
client/src/containers/JournalNumber/ReferenceNumberForm.js
Normal 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);
|
||||||
@@ -215,6 +215,8 @@ export default {
|
|||||||
'The item category has been successfully created.',
|
'The item category has been successfully created.',
|
||||||
the_item_category_has_been_successfully_edited:
|
the_item_category_has_been_successfully_edited:
|
||||||
'The item category has been successfully edited.',
|
'The item category has been successfully edited.',
|
||||||
|
the_item_category_has_been_successfully_deleted:
|
||||||
|
'The item category has been successfully deleted',
|
||||||
once_delete_these_views_you_will_not_able_restore_them:
|
once_delete_these_views_you_will_not_able_restore_them:
|
||||||
"Once you delete the custom view, you won't be able to restore it later. Are you sure you want to delete this view?",
|
"Once you delete the custom view, you won't be able to restore it later. Are you sure you want to delete this view?",
|
||||||
the_custom_view_has_been_successfully_deleted:
|
the_custom_view_has_been_successfully_deleted:
|
||||||
@@ -765,5 +767,8 @@ export default {
|
|||||||
something_wentwrong: 'Something went wrong.',
|
something_wentwrong: 'Something went wrong.',
|
||||||
new_password: 'New password',
|
new_password: 'New password',
|
||||||
license_code_: 'License code',
|
license_code_: 'License code',
|
||||||
legal_organization_name: 'Legal Organization Name'
|
legal_organization_name: 'Legal Organization Name',
|
||||||
|
prefix: 'Prefix',
|
||||||
|
next_number: 'Next Number',
|
||||||
|
journal_number_settings: 'Journal Number Settings',
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,159 +1,162 @@
|
|||||||
|
.make-journal-entries {
|
||||||
.make-journal-entries{
|
|
||||||
padding-bottom: 20px;
|
padding-bottom: 20px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
&__header{
|
&__header {
|
||||||
padding: 25px 27px 20px;
|
padding: 25px 27px 20px;
|
||||||
background: #fbfbfb;
|
background: #fbfbfb;
|
||||||
|
|
||||||
.bp3-form-group{
|
.bp3-form-group {
|
||||||
|
.bp3-label {
|
||||||
.bp3-label{
|
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
color: #444;
|
color: #444;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.bp3-button:not([class*='bp3-intent-']):not(.bp3-minimal).bp3-small {
|
||||||
|
font-size: 13px;
|
||||||
|
min-height: 33px;
|
||||||
|
margin-top: 21px;
|
||||||
|
margin-left: -30px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__table{
|
&__table {
|
||||||
padding: 15px 15px 0;
|
padding: 15px 15px 0;
|
||||||
|
|
||||||
.bp3-form-group{
|
.bp3-form-group {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
.table{
|
.table {
|
||||||
border: 1px dotted rgb(195, 195, 195);
|
border: 1px dotted rgb(195, 195, 195);
|
||||||
border-bottom: transparent;
|
border-bottom: transparent;
|
||||||
border-left: transparent;
|
border-left: transparent;
|
||||||
|
|
||||||
.th,
|
.th,
|
||||||
.td{
|
.td {
|
||||||
border-left: 1px dotted rgb(195, 195, 195);
|
border-left: 1px dotted rgb(195, 195, 195);
|
||||||
|
|
||||||
&.index{
|
&.index {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
span{
|
span {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.thead{
|
.thead {
|
||||||
.tr .th{
|
.tr .th {
|
||||||
padding: 10px 10px;
|
padding: 10px 10px;
|
||||||
background-color: #F2F5FA;
|
background-color: #f2f5fa;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: #1e1c3e;
|
color: #1e1c3e;
|
||||||
|
|
||||||
&.index > div{
|
&.index > div {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.tbody{
|
.tbody {
|
||||||
.tr .td{
|
.tr .td {
|
||||||
padding: 7px;
|
padding: 7px;
|
||||||
border-bottom: 1px dotted rgb(195, 195, 195);
|
border-bottom: 1px dotted rgb(195, 195, 195);
|
||||||
min-height: 46px;
|
min-height: 46px;
|
||||||
|
|
||||||
&.index{
|
&.index {
|
||||||
background-color: #F2F5FA;
|
background-color: #f2f5fa;
|
||||||
|
|
||||||
> span{
|
> span {
|
||||||
margin-top: auto;
|
margin-top: auto;
|
||||||
margin-bottom: auto;
|
margin-bottom: auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.tr{
|
.tr {
|
||||||
.bp3-form-group:not(.bp3-intent-danger) .bp3-input,
|
.bp3-form-group:not(.bp3-intent-danger) .bp3-input,
|
||||||
.form-group--select-list .bp3-button{
|
.form-group--select-list .bp3-button {
|
||||||
border-color: #E5E5E5;
|
border-color: #e5e5e5;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
padding-left: 8px;
|
padding-left: 8px;
|
||||||
padding-right: 8px;
|
padding-right: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-group--select-list{
|
.form-group--select-list {
|
||||||
&.bp3-intent-danger{
|
&.bp3-intent-danger {
|
||||||
.bp3-button:not(.bp3-minimal){
|
.bp3-button:not(.bp3-minimal) {
|
||||||
border-color: #db3737;
|
border-color: #db3737;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&:last-of-type{
|
&:last-of-type {
|
||||||
.td{
|
.td {
|
||||||
border-bottom: transparent;
|
border-bottom: transparent;
|
||||||
|
|
||||||
.bp3-button,
|
.bp3-button,
|
||||||
.bp3-input-group{
|
.bp3-input-group {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.td.actions{
|
.td.actions {
|
||||||
.bp3-button{
|
.bp3-button {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
color: #e66d6d;
|
color: #e66d6d;
|
||||||
|
|
||||||
&:hover{
|
&:hover {
|
||||||
color: #c23030;
|
color: #c23030;
|
||||||
}
|
}
|
||||||
|
|
||||||
svg{
|
svg {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.row--total{
|
&.row--total {
|
||||||
|
|
||||||
.account.td,
|
.account.td,
|
||||||
.debit.td,
|
.debit.td,
|
||||||
.credit.td{
|
.credit.td {
|
||||||
> span{
|
> span {
|
||||||
padding-top: 2px;
|
padding-top: 2px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.debit.td,
|
.debit.td,
|
||||||
.credit.td{
|
.credit.td {
|
||||||
> span{
|
> span {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #444;
|
color: #444;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.td{
|
.td {
|
||||||
&.note{
|
&.note {
|
||||||
.bp3-form-group{
|
.bp3-form-group {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.th{
|
.th {
|
||||||
color: #444;
|
color: #444;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
border-bottom: 1px dotted #666;
|
border-bottom: 1px dotted #666;
|
||||||
}
|
}
|
||||||
|
|
||||||
.td{
|
.td {
|
||||||
border-bottom: 1px dotted #999;
|
border-bottom: 1px dotted #999;
|
||||||
}
|
}
|
||||||
|
|
||||||
.actions.td{
|
.actions.td {
|
||||||
.bp3-button{
|
.bp3-button {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
@@ -161,23 +164,22 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.bp3-button{
|
.bp3-button {
|
||||||
&.button--clear-lines{
|
&.button--clear-lines {
|
||||||
background-color: #FCEFEF;
|
background-color: #fcefef;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.button--clear-lines,
|
.button--clear-lines,
|
||||||
.button--new-line{
|
.button--new-line {
|
||||||
padding-left: 14px;
|
padding-left: 14px;
|
||||||
padding-right: 14px;
|
padding-right: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropzone-container{
|
.dropzone-container {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropzone{
|
.dropzone {
|
||||||
|
|
||||||
width: 300px;
|
width: 300px;
|
||||||
height: 75px;
|
height: 75px;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user