mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-15 20:30:33 +00:00
feat(items) : items preference.
This commit is contained in:
@@ -21,4 +21,9 @@ export default [
|
||||
disabled: false,
|
||||
href: '/preferences/accountant',
|
||||
},
|
||||
{
|
||||
text: <T id={'items'}/>,
|
||||
disabled: false,
|
||||
href: '/preferences/items',
|
||||
},
|
||||
];
|
||||
|
||||
14
client/src/containers/Preferences/Item/Item.js
Normal file
14
client/src/containers/Preferences/Item/Item.js
Normal file
@@ -0,0 +1,14 @@
|
||||
import React from 'react';
|
||||
import ItemFormPage from './ItemFormPage';
|
||||
import { ItemFormProvider } from './ItemFormProvider';
|
||||
|
||||
/**
|
||||
* items preferences.
|
||||
*/
|
||||
export default function ItemsPreferences() {
|
||||
return (
|
||||
<ItemFormProvider>
|
||||
<ItemFormPage />
|
||||
</ItemFormProvider>
|
||||
);
|
||||
}
|
||||
9
client/src/containers/Preferences/Item/Item.schema.js
Normal file
9
client/src/containers/Preferences/Item/Item.schema.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import * as Yup from 'yup';
|
||||
|
||||
const Schema = Yup.object().shape({
|
||||
sell_account: Yup.number().nullable().required(),
|
||||
cost_account: Yup.number().nullable().required(),
|
||||
inventory_account: Yup.number().nullable().required(),
|
||||
});
|
||||
|
||||
export const ItemPreferencesSchema = Schema;
|
||||
133
client/src/containers/Preferences/Item/ItemForm.js
Normal file
133
client/src/containers/Preferences/Item/ItemForm.js
Normal file
@@ -0,0 +1,133 @@
|
||||
import React from 'react';
|
||||
import { Form, FastField, useFormikContext } from 'formik';
|
||||
import { FormGroup, Button, Intent } from '@blueprintjs/core';
|
||||
import { AccountsSelectList, FieldRequiredHint } from 'components';
|
||||
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { inputIntent } from 'utils';
|
||||
import { ACCOUNT_PARENT_TYPE, ACCOUNT_TYPE } from 'common/accountTypes';
|
||||
|
||||
import { useItemFormContext } from './ItemFormProvider';
|
||||
|
||||
/**
|
||||
* item form preferences.
|
||||
*/
|
||||
export default function ItemForm() {
|
||||
const history = useHistory();
|
||||
const { accounts } = useItemFormContext();
|
||||
|
||||
const { isSubmitting } = useFormikContext();
|
||||
|
||||
const handleCloseClick = () => {
|
||||
history.go(-1);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form>
|
||||
{/* ----------- preferred sell account ----------- */}
|
||||
<FastField name={'sell_account'}>
|
||||
{({
|
||||
form: { values, setFieldValue },
|
||||
field: { value },
|
||||
meta: { error, touched },
|
||||
}) => (
|
||||
<FormGroup
|
||||
label={
|
||||
<strong>
|
||||
<T id={'preferred_sell_account'} />
|
||||
</strong>
|
||||
}
|
||||
helperText={
|
||||
'Select a preferred account to deposit into it after customer make payment.'
|
||||
}
|
||||
labelInfo={<FieldRequiredHint />}
|
||||
intent={inputIntent({ error, touched })}
|
||||
>
|
||||
<AccountsSelectList
|
||||
accounts={accounts}
|
||||
onAccountSelected={({ id }) => {
|
||||
setFieldValue('sell_account', id);
|
||||
}}
|
||||
selectedAccountId={value}
|
||||
defaultSelectText={<T id={'select_payment_account'} />}
|
||||
filterByParentTypes={[ACCOUNT_PARENT_TYPE.INCOME]}
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
</FastField>
|
||||
|
||||
{/* ----------- preferred cost account ----------- */}
|
||||
<FastField name={'cost_account'}>
|
||||
{({
|
||||
form: { values, setFieldValue },
|
||||
field: { value },
|
||||
meta: { error, touched },
|
||||
}) => (
|
||||
<FormGroup
|
||||
label={
|
||||
<strong>
|
||||
<T id={'preferred_cost_account'} />
|
||||
</strong>
|
||||
}
|
||||
helperText={
|
||||
'Select a preferred account to deposit into it after customer make payment.'
|
||||
}
|
||||
labelInfo={<FieldRequiredHint />}
|
||||
intent={inputIntent({ error, touched })}
|
||||
>
|
||||
<AccountsSelectList
|
||||
accounts={accounts}
|
||||
onAccountSelected={({ id }) => {
|
||||
setFieldValue('cost_account', id);
|
||||
}}
|
||||
selectedAccountId={value}
|
||||
defaultSelectText={<T id={'select_payment_account'} />}
|
||||
filterByParentTypes={[ACCOUNT_PARENT_TYPE.EXPENSE]}
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
</FastField>
|
||||
|
||||
{/* ----------- preferred inventory account ----------- */}
|
||||
<FastField name={'inventory_account'}>
|
||||
{({
|
||||
form: { values, setFieldValue },
|
||||
field: { value },
|
||||
meta: { error, touched },
|
||||
}) => (
|
||||
<FormGroup
|
||||
label={
|
||||
<strong>
|
||||
<T id={'preferred_inventory_account'} />
|
||||
</strong>
|
||||
}
|
||||
helperText={
|
||||
'Select a preferred account to deposit into it vendor advanced deposits.'
|
||||
}
|
||||
labelInfo={<FieldRequiredHint />}
|
||||
intent={inputIntent({ error, touched })}
|
||||
>
|
||||
<AccountsSelectList
|
||||
accounts={accounts}
|
||||
onAccountSelected={({ id }) => {
|
||||
setFieldValue('inventory_account', id);
|
||||
}}
|
||||
selectedAccountId={value}
|
||||
defaultSelectText={<T id={'select_payment_account'} />}
|
||||
filterByTypes={[ACCOUNT_TYPE.INVENTORY]}
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
</FastField>
|
||||
|
||||
<div className={'card__footer'}>
|
||||
<Button intent={Intent.PRIMARY} disabled={isSubmitting} type="submit">
|
||||
<T id={'save'} />
|
||||
</Button>
|
||||
<Button onClick={handleCloseClick}>
|
||||
<T id={'close'} />
|
||||
</Button>
|
||||
</div>
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
79
client/src/containers/Preferences/Item/ItemFormPage.js
Normal file
79
client/src/containers/Preferences/Item/ItemFormPage.js
Normal file
@@ -0,0 +1,79 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { Formik } from 'formik';
|
||||
import { Intent } from '@blueprintjs/core';
|
||||
import classNames from 'classnames';
|
||||
import { CLASSES } from 'common/classes';
|
||||
import { AppToaster } from 'components';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { ItemPreferencesSchema } from './Item.schema';
|
||||
import ItemForm from './ItemForm';
|
||||
|
||||
import { useItemFormContext } from './ItemFormProvider';
|
||||
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
|
||||
import withSettings from 'containers/Settings/withSettings';
|
||||
import { compose, optionsMapToArray, transformGeneralSettings } from 'utils';
|
||||
|
||||
import 'style/pages/Preferences/Accounting.scss';
|
||||
|
||||
// item form page preferences.
|
||||
function ItemFormPage({
|
||||
// #withSettings
|
||||
itemsSettings,
|
||||
//# withDashboardActions
|
||||
changePreferencesPageTitle,
|
||||
}) {
|
||||
const { formatMessage } = useIntl();
|
||||
const { saveSettingMutate } = useItemFormContext();
|
||||
|
||||
const initialValues = {
|
||||
...transformGeneralSettings(itemsSettings),
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
changePreferencesPageTitle(formatMessage({ id: 'items' }));
|
||||
}, [changePreferencesPageTitle]);
|
||||
|
||||
const handleFormSubmit = (values, { setSubmitting, setErrors }) => {
|
||||
const options = optionsMapToArray(values).map((option) => {
|
||||
return { key: option.key, ...option, group: 'items' };
|
||||
});
|
||||
|
||||
const onSuccess = () => {
|
||||
AppToaster.show({
|
||||
message: formatMessage({
|
||||
id: 'the_items_preferences_has_been_saved',
|
||||
}),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
setSubmitting(false);
|
||||
};
|
||||
|
||||
const onError = (errors) => {
|
||||
setSubmitting(false);
|
||||
};
|
||||
saveSettingMutate({ options }).then(onSuccess).catch(onError);
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
CLASSES.PREFERENCES_PAGE_INSIDE_CONTENT,
|
||||
CLASSES.PREFERENCES_PAGE_INSIDE_CONTENT_ACCOUNTANT,
|
||||
)}
|
||||
>
|
||||
<div className={classNames(CLASSES.CARD)}>
|
||||
<Formik
|
||||
initialValues={initialValues}
|
||||
validationSchema={ItemPreferencesSchema}
|
||||
onSubmit={handleFormSubmit}
|
||||
component={ItemForm}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withSettings(({ itemsSettings }) => ({ itemsSettings })),
|
||||
withDashboardActions,
|
||||
)(ItemFormPage);
|
||||
34
client/src/containers/Preferences/Item/ItemFormProvider.js
Normal file
34
client/src/containers/Preferences/Item/ItemFormProvider.js
Normal file
@@ -0,0 +1,34 @@
|
||||
import React, { useContext, createContext } from 'react';
|
||||
import { LoadingIndicator } from 'components';
|
||||
|
||||
import { useAccounts, useSaveSettings } from 'hooks/query';
|
||||
|
||||
const ItemFormContext = createContext();
|
||||
|
||||
/**
|
||||
* Item data provider.
|
||||
*/
|
||||
|
||||
function ItemFormProvider({ ...props }) {
|
||||
// Fetches the accounts list.
|
||||
const { isLoading: isAccountsLoading, data: accounts } = useAccounts();
|
||||
|
||||
// Save Organization Settings.
|
||||
const { mutateAsync: saveSettingMutate } = useSaveSettings();
|
||||
|
||||
// Provider state.
|
||||
const provider = {
|
||||
accounts,
|
||||
saveSettingMutate,
|
||||
};
|
||||
|
||||
return (
|
||||
<LoadingIndicator loading={isAccountsLoading}>
|
||||
<ItemFormContext.Provider value={provider} {...props} />
|
||||
</LoadingIndicator>
|
||||
);
|
||||
}
|
||||
|
||||
const useItemFormContext = () => useContext(ItemFormContext);
|
||||
|
||||
export { useItemFormContext, ItemFormProvider };
|
||||
@@ -5,13 +5,14 @@ export default (mapState) => {
|
||||
const mapped = {
|
||||
organizationSettings: state.settings.data.organization,
|
||||
manualJournalsSettings: state.settings.data.manualJournals,
|
||||
billsettings: state.settings.data.bills,
|
||||
billPaymentSettings: state.settings.data.billPayments,
|
||||
paymentReceiveSettings: state.settings.data.paymentReceives,
|
||||
estimatesSettings: state.settings.data.salesEstimates,
|
||||
receiptSettings: state.settings.data.salesReceipts,
|
||||
invoiceSettings: state.settings.data.salesInvoices,
|
||||
itemsSettings: state.settings.data.items,
|
||||
expenseSettings: state.settings.data.expenses,
|
||||
accountsSettings: state.settings.data.accounts,
|
||||
};
|
||||
return mapState ? mapState(mapped, state, props) : mapped;
|
||||
};
|
||||
|
||||
@@ -3,6 +3,7 @@ import Users from 'containers/Preferences/Users/Users';
|
||||
import Accountant from 'containers/Preferences/Accountant/Accountant';
|
||||
import Accounts from 'containers/Preferences/Accounts/Accounts';
|
||||
import Currencies from 'containers/Preferences/Currencies/Currencies';
|
||||
import Item from 'containers/Preferences/Item/Item';
|
||||
|
||||
const BASE_URL = '/preferences';
|
||||
|
||||
@@ -27,4 +28,9 @@ export default [
|
||||
component: Accountant,
|
||||
exact: true,
|
||||
},
|
||||
{
|
||||
path: `${BASE_URL}/items`,
|
||||
component: Item,
|
||||
exact: true,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -4,7 +4,7 @@ export default {
|
||||
type: "string",
|
||||
},
|
||||
base_currency: {
|
||||
type: 'string',
|
||||
type: "string",
|
||||
},
|
||||
industry: {
|
||||
type: "string",
|
||||
@@ -13,50 +13,50 @@ export default {
|
||||
type: "string",
|
||||
},
|
||||
fiscal_year: {
|
||||
type: 'string',
|
||||
type: "string",
|
||||
},
|
||||
financial_date_start: {
|
||||
type: 'string',
|
||||
type: "string",
|
||||
},
|
||||
language: {
|
||||
type: 'string',
|
||||
type: "string",
|
||||
},
|
||||
time_zone: {
|
||||
type: 'string',
|
||||
type: "string",
|
||||
},
|
||||
date_format: {
|
||||
type: 'string',
|
||||
type: "string",
|
||||
},
|
||||
accounting_basis: {
|
||||
type: 'string',
|
||||
}
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
manual_journals: {
|
||||
next_number: {
|
||||
type: 'string',
|
||||
type: "string",
|
||||
},
|
||||
number_prefix: {
|
||||
type: 'string',
|
||||
type: "string",
|
||||
},
|
||||
auto_increment: {
|
||||
type: 'boolean',
|
||||
}
|
||||
type: "boolean",
|
||||
},
|
||||
},
|
||||
bill_payments: {
|
||||
withdrawal_account: {
|
||||
type: 'string'
|
||||
type: "number",
|
||||
},
|
||||
},
|
||||
sales_estimates: {
|
||||
next_number: {
|
||||
type: 'string',
|
||||
type: "string",
|
||||
},
|
||||
number_prefix: {
|
||||
type: 'string',
|
||||
type: "string",
|
||||
},
|
||||
auto_increment: {
|
||||
type: "boolean",
|
||||
}
|
||||
},
|
||||
},
|
||||
sales_receipts: {
|
||||
next_number: {
|
||||
@@ -70,7 +70,7 @@ export default {
|
||||
},
|
||||
preferred_deposit_account: {
|
||||
type: "number",
|
||||
}
|
||||
},
|
||||
},
|
||||
sales_invoices: {
|
||||
next_number: {
|
||||
@@ -91,37 +91,37 @@ export default {
|
||||
type: "string",
|
||||
},
|
||||
auto_increment: {
|
||||
type: 'boolean',
|
||||
type: "boolean",
|
||||
},
|
||||
deposit_account: {
|
||||
type: 'number',
|
||||
type: "number",
|
||||
},
|
||||
advance_deposit: {
|
||||
type: 'number',
|
||||
}
|
||||
type: "number",
|
||||
},
|
||||
},
|
||||
items: {
|
||||
sell_account: {
|
||||
type: 'number',
|
||||
type: "number",
|
||||
},
|
||||
cost_account: {
|
||||
type: 'number',
|
||||
type: "number",
|
||||
},
|
||||
inventory_account: {
|
||||
type: 'number',
|
||||
type: "number",
|
||||
},
|
||||
},
|
||||
expenses: {
|
||||
preferred_payment_account: {
|
||||
type: "number",
|
||||
}
|
||||
},
|
||||
},
|
||||
accounts: {
|
||||
account_code_required: {
|
||||
type: 'boolean',
|
||||
type: "boolean",
|
||||
},
|
||||
account_code_unique: {
|
||||
type: 'boolean',
|
||||
}
|
||||
}
|
||||
type: "boolean",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user