This commit is contained in:
a.bouhuolia
2021-03-22 19:23:55 +02:00
22 changed files with 605 additions and 103 deletions

View File

@@ -2,9 +2,11 @@ import * as Yup from 'yup';
const Schema = Yup.object().shape({
accounting_basis: Yup.string().required(),
account_code_required: Yup.boolean(),
customer_deposit_account: Yup.number().nullable(),
vendor_withdrawal_account: Yup.number().nullable(),
account_code_required: Yup.boolean().nullable(),
account_code_unique: Yup.boolean().nullable(),
deposit_account: Yup.number().nullable(),
withdrawal_account: Yup.number().nullable(),
advance_deposit: Yup.number().nullable(),
});
export const AccountantSchema = Schema;
export const AccountantSchema = Schema;

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { Form, FastField, Field } from 'formik';
import { Form, FastField, useFormikContext } from 'formik';
import {
FormGroup,
RadioGroup,
@@ -9,20 +9,20 @@ import {
Intent,
} from '@blueprintjs/core';
import { useHistory } from 'react-router-dom';
import { AccountsSelectList } from 'components';
import { FieldRequiredHint } from 'components';
import { AccountsSelectList, FieldRequiredHint } from 'components';
import { FormattedMessage as T, useIntl } from 'react-intl';
// import { } from 'common/accountTypes';
import { handleStringChange, saveInvoke } from 'utils';
import { ACCOUNT_PARENT_TYPE } from 'common/accountTypes';
import { handleStringChange, inputIntent } from 'utils';
import { useAccountantFormContext } from './AccountantFormProvider';
export default function AccountantForm() {
const history = useHistory();
const { formatMessage } = useIntl();
const { isSubmitting } = useFormikContext();
const handleCloseClick = () => {
history.go(-1);
};
@@ -38,26 +38,60 @@ export default function AccountantForm() {
<T id={'accounts'} />
</strong>
}
className={'accounts-checkbox'}
>
<Checkbox
label={'Make account code required when create a new accounts.'}
/>
<Checkbox
label={'Should account code be unique when create a new account.'}
/>
{/*------------ account code required -----------*/}
<FastField name={'account_code_required'} type={'checkbox'}>
{({ field }) => (
<FormGroup inline={true}>
<Checkbox
inline={true}
label={'Make account code required when create a new accounts.'}
name={'account_code_required'}
{...field}
/>
</FormGroup>
)}
</FastField>
{/*------------ account code unique -----------*/}
<FastField name={'account_code_unique'} type={'checkbox'}>
{({ field }) => (
<FormGroup inline={true}>
<Checkbox
inline={true}
label={
'Should account code be unique when create a new account.'
}
name={'account_code_unique'}
{...field}
/>
</FormGroup>
)}
</FastField>
</FormGroup>
{/* ----------- Accounting basis ----------- */}
<FastField name={'accounting_basis'}>
{({ form, field: { value }, meta: { error, touched } }) => (
{({
form: { setFieldValue },
field: { value },
meta: { error, touched },
}) => (
<FormGroup
labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
label={
<strong>
<T id={'accounting_basis_'} />
</strong>
}
>
<RadioGroup inline={true}>
<RadioGroup
inline={true}
selectedValue={value}
onChange={handleStringChange((_value) => {
setFieldValue('accounting_basis', _value);
})}
>
<Radio label={formatMessage({ id: 'Cash' })} value="cash" />
<Radio label={formatMessage({ id: 'accrual' })} value="accrual" />
</RadioGroup>
@@ -66,8 +100,12 @@ export default function AccountantForm() {
</FastField>
{/* ----------- Deposit customer account ----------- */}
<FastField name={'deposit_customer_account'}>
{({ form, field: { value }, meta: { error, touched } }) => (
<FastField name={'deposit_account'}>
{({
form: { values, setFieldValue },
field: { value },
meta: { error, touched },
}) => (
<FormGroup
label={
<strong>
@@ -78,20 +116,28 @@ export default function AccountantForm() {
'Select a preferred account to deposit into it after customer make payment.'
}
labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
>
<AccountsSelectList
accounts={accounts}
// onAccountSelected
onAccountSelected={({ id }) => {
setFieldValue('deposit_account', id);
}}
selectedAccountId={value}
defaultSelectText={<T id={'select_payment_account'} />}
// filterByTypes={['current_asset']}
// filterByParentTypes={[ACCOUNT_PARENT_TYPE.CURRENT_ASSET]}
/>
</FormGroup>
)}
</FastField>
{/* ----------- Withdrawal customer account ----------- */}
<FastField name={'withdrawal_customer_account'}>
{({ form, field: { value }, meta: { error, touched } }) => (
{/* ----------- Withdrawal vendor account ----------- */}
<FastField name={'withdrawal_account'}>
{({
form: { values, setFieldValue },
field: { value },
meta: { error, touched },
}) => (
<FormGroup
label={
<strong>
@@ -102,19 +148,27 @@ export default function AccountantForm() {
'Select a preferred account to deposit into it after customer make payment.'
}
labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
>
<AccountsSelectList
accounts={accounts}
onAccountSelected={({ id }) => {
setFieldValue('withdrawal_account', id);
}}
selectedAccountId={value}
defaultSelectText={<T id={'select_payment_account'} />}
// filterByTypes={['current_asset']}
/>
</FormGroup>
)}
</FastField>
{/* ----------- Withdrawal customer account ----------- */}
<FastField name={'vendor_advance_deposit'}>
{({ form, field: { value }, meta: { error, touched } }) => (
<FastField name={'advance_deposit'}>
{({
form: { values, setFieldValue },
field: { value },
meta: { error, touched },
}) => (
<FormGroup
label={
<strong>
@@ -125,17 +179,23 @@ export default function AccountantForm() {
'Select a preferred account to deposit into it vendor advanced deposits.'
}
labelInfo={<FieldRequiredHint />}
intent={inputIntent({ error, touched })}
>
<AccountsSelectList
accounts={accounts}
onAccountSelected={({ id }) => {
setFieldValue('advance_deposit', id);
}}
selectedAccountId={value}
defaultSelectText={<T id={'select_payment_account'} />}
// filterByTypes={['current_asset', 'other_current_asset']}
// filterByParentTypes={[ACCOUNT_PARENT_TYPE.CURRENT_ASSET]}
/>
</FormGroup>
)}
</FastField>
<div className={'card__footer'}>
<Button intent={Intent.PRIMARY} type="submit">
<Button intent={Intent.PRIMARY} disabled={isSubmitting} type="submit">
<T id={'save'} />
</Button>
<Button onClick={handleCloseClick}>

View File

@@ -1,28 +1,72 @@
import React, { useEffect } from 'react';
import classNames from 'classnames';
import { Formik } from 'formik';
import { pick } from 'lodash';
import { Intent } from '@blueprintjs/core';
import { CLASSES } from 'common/classes';
import { AppToaster } from 'components';
import { useIntl } from 'react-intl';
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import withSettings from 'containers/Settings/withSettings';
import AccountantForm from './AccountantForm';
import { AccountantSchema } from './Accountant.schema';
import { useAccountantFormContext } from './AccountantFormProvider';
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import { compose } from 'utils';
import { transformToOptions } from './utils';
import { compose, transformGeneralSettings } from 'utils';
import 'style/pages/Preferences/Accounting.scss';
// Accountant preferences.
function AccountantFormPage({ changePreferencesPageTitle }) {
function AccountantFormPage({
//# withDashboardActions
changePreferencesPageTitle,
// #withSettings
organizationSettings,
paymentReceiveSettings,
accountsSettings,
billPaymentSettings,
}) {
const { formatMessage } = useIntl();
const { saveSettingMutate } = useAccountantFormContext();
const initialValues = {};
const accountantSettings = {
...billPaymentSettings,
...accountsSettings,
...pick(organizationSettings, ['accountingBasis']),
...pick(paymentReceiveSettings, ['depositAccount', 'advanceDeposit']),
};
const initialValues = {
...transformGeneralSettings(accountantSettings),
};
useEffect(() => {
changePreferencesPageTitle('Accountant');
changePreferencesPageTitle(formatMessage({ id: 'accountant' }));
}, [changePreferencesPageTitle]);
const handleFormSubmit = (values, { setSubmitting }) => {
const options = transformToOptions(values);
setSubmitting(true);
const onSuccess = () => {
AppToaster.show({
message: formatMessage({
id: 'the_accountant_preferences_has_been_saved',
}),
intent: Intent.SUCCESS,
});
setSubmitting(false);
};
const onError = (errors) => {
setSubmitting(false);
};
saveSettingMutate({ options }).then(onSuccess).catch(onError);
};
return (
<div
className={classNames(
@@ -34,6 +78,7 @@ function AccountantFormPage({ changePreferencesPageTitle }) {
<Formik
initialValues={initialValues}
validationSchema={AccountantSchema}
onSubmit={handleFormSubmit}
component={AccountantForm}
/>
</div>
@@ -41,4 +86,19 @@ function AccountantFormPage({ changePreferencesPageTitle }) {
);
}
export default compose(withDashboardActions)(AccountantFormPage);
export default compose(
withSettings(
({
organizationSettings,
paymentReceiveSettings,
accountsSettings,
billPaymentSettings,
}) => ({
organizationSettings,
paymentReceiveSettings,
accountsSettings,
billPaymentSettings,
}),
),
withDashboardActions,
)(AccountantFormPage);

View File

@@ -0,0 +1,37 @@
export const transformToOptions = (option) => {
return [
{
key: 'accounting_basis',
value: option.accounting_basis,
group: 'organization',
},
{
key: 'withdrawal_account',
value: option.withdrawal_account,
group: 'bill_payments',
},
{
key: 'deposit_account',
value: option.deposit_account,
group: 'payment_receives',
},
{
key: 'advance_deposit',
value: option.advance_deposit,
group: 'payment_receives',
},
{
key: 'account_code_required',
value: option.account_code_required,
group: 'accounts',
},
{
key: 'account_code_unique',
value: option.account_code_unique,
group: 'accounts',
},
];
};

View 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>
);
}

View 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;

View 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>
);
}

View 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);

View 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 };