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

@@ -21,4 +21,9 @@ export default [
disabled: false, disabled: false,
href: '/preferences/accountant', href: '/preferences/accountant',
}, },
{
text: <T id={'items'}/>,
disabled: false,
href: '/preferences/items',
},
]; ];

View File

@@ -6,7 +6,7 @@ import {
} from 'react-intl'; } from 'react-intl';
import { Intent, Alert } from '@blueprintjs/core'; import { Intent, Alert } from '@blueprintjs/core';
import { AppToaster } from 'components'; import { AppToaster } from 'components';
import { transformErrors } from 'containers/Customers/utils'; import { transformErrors } from 'containers/Vendors/utils';
import { useDeleteVendor } from 'hooks/query'; import { useDeleteVendor } from 'hooks/query';
import withAlertStoreConnect from 'containers/Alert/withAlertStoreConnect'; import withAlertStoreConnect from 'containers/Alert/withAlertStoreConnect';
@@ -28,10 +28,7 @@ function VendorDeleteAlert({
closeAlert, closeAlert,
}) { }) {
const { formatMessage } = useIntl(); const { formatMessage } = useIntl();
const { const { mutateAsync: deleteVendorMutate, isLoading } = useDeleteVendor();
mutateAsync: deleteVendorMutate,
isLoading
} = useDeleteVendor();
// Handle cancel delete the vendor. // Handle cancel delete the vendor.
const handleCancelDeleteAlert = () => { const handleCancelDeleteAlert = () => {
@@ -49,9 +46,15 @@ function VendorDeleteAlert({
intent: Intent.SUCCESS, intent: Intent.SUCCESS,
}); });
}) })
.catch((errors) => { .catch(
transformErrors(errors); ({
}) response: {
data: { errors },
},
}) => {
transformErrors(errors);
},
)
.finally(() => { .finally(() => {
closeAlert(name); closeAlert(name);
}); });

View File

@@ -22,4 +22,13 @@ export const transformErrors = (errors) => {
intent: Intent.DANGER, intent: Intent.DANGER,
}); });
} }
if (errors.find((error) => error.type === 'CUSTOMER_HAS_TRANSACTIONS')) {
AppToaster.show({
message: formatMessage({
id:
'this_customer_cannot_be_deleted_as_it_is_associated_with_transactions',
}),
intent: Intent.DANGER,
});
}
}; };

View File

@@ -67,7 +67,7 @@ function ItemForm({
const history = useHistory(); const history = useHistory();
const { formatMessage } = useIntl(); const { formatMessage } = useIntl();
/** /**
* Initial values in create and edit mode. * Initial values in create and edit mode.
*/ */
@@ -122,10 +122,9 @@ function ItemForm({
AppToaster.show({ AppToaster.show({
message: formatMessage( message: formatMessage(
{ {
id: id: isNewMode
isNewMode ? 'the_item_has_been_created_successfully'
? 'the_item_has_been_created_successfully' : 'the_item_has_been_edited_successfully',
: 'the_item_has_been_edited_successfully',
}, },
{ {
number: itemId, number: itemId,
@@ -181,10 +180,8 @@ function ItemForm({
export default compose( export default compose(
withSettings(({ itemsSettings }) => ({ withSettings(({ itemsSettings }) => ({
preferredCostAccount: parseInt(itemsSettings?.preferredCostAccount), preferredCostAccount: parseInt(itemsSettings?.costAccount),
preferredSellAccount: parseInt(itemsSettings?.preferredSellAccount), preferredSellAccount: parseInt(itemsSettings?.sellAccount),
preferredInventoryAccount: parseInt( preferredInventoryAccount: parseInt(itemsSettings?.inventoryAccount),
itemsSettings?.preferredInventoryAccount,
),
})), })),
)(ItemForm); )(ItemForm);

View File

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

View File

@@ -1,28 +1,72 @@
import React, { useEffect } from 'react'; import React, { useEffect } from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { Formik } from 'formik'; import { Formik } from 'formik';
import { pick } from 'lodash';
import { Intent } from '@blueprintjs/core';
import { CLASSES } from 'common/classes'; 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 AccountantForm from './AccountantForm';
import { AccountantSchema } from './Accountant.schema'; import { AccountantSchema } from './Accountant.schema';
import { useAccountantFormContext } from './AccountantFormProvider'; import { useAccountantFormContext } from './AccountantFormProvider';
import { transformToOptions } from './utils';
import withDashboardActions from 'containers/Dashboard/withDashboardActions'; import { compose, transformGeneralSettings } from 'utils';
import { compose } from 'utils';
import 'style/pages/Preferences/Accounting.scss'; import 'style/pages/Preferences/Accounting.scss';
// Accountant preferences. // Accountant preferences.
function AccountantFormPage({ changePreferencesPageTitle }) { function AccountantFormPage({
//# withDashboardActions
changePreferencesPageTitle,
// #withSettings
organizationSettings,
paymentReceiveSettings,
accountsSettings,
billPaymentSettings,
}) {
const { formatMessage } = useIntl();
const { saveSettingMutate } = useAccountantFormContext(); const { saveSettingMutate } = useAccountantFormContext();
const initialValues = {}; const accountantSettings = {
...billPaymentSettings,
...accountsSettings,
...pick(organizationSettings, ['accountingBasis']),
...pick(paymentReceiveSettings, ['depositAccount', 'advanceDeposit']),
};
const initialValues = {
...transformGeneralSettings(accountantSettings),
};
useEffect(() => { useEffect(() => {
changePreferencesPageTitle('Accountant'); changePreferencesPageTitle(formatMessage({ id: 'accountant' }));
}, [changePreferencesPageTitle]); }, [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 ( return (
<div <div
className={classNames( className={classNames(
@@ -34,6 +78,7 @@ function AccountantFormPage({ changePreferencesPageTitle }) {
<Formik <Formik
initialValues={initialValues} initialValues={initialValues}
validationSchema={AccountantSchema} validationSchema={AccountantSchema}
onSubmit={handleFormSubmit}
component={AccountantForm} component={AccountantForm}
/> />
</div> </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 };

View File

@@ -2,7 +2,7 @@ import React, { useMemo } from 'react';
import { Formik, Form } from 'formik'; import { Formik, Form } from 'formik';
import { Intent } from '@blueprintjs/core'; import { Intent } from '@blueprintjs/core';
import { useIntl } from 'react-intl'; import { useIntl } from 'react-intl';
import { sumBy, pick } from 'lodash'; import { sumBy, pick, defaultTo } from 'lodash';
import classNames from 'classnames'; import classNames from 'classnames';
import { useHistory } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
@@ -26,7 +26,10 @@ import { defaultPaymentMade, transformToEditForm, ERRORS } from './utils';
/** /**
* Payment made form component. * Payment made form component.
*/ */
function PaymentMadeForm() { function PaymentMadeForm({
// #withSettings
preferredPaymentAccount,
}) {
const history = useHistory(); const history = useHistory();
const { formatMessage } = useIntl(); const { formatMessage } = useIntl();
@@ -50,6 +53,7 @@ function PaymentMadeForm() {
} }
: { : {
...defaultPaymentMade, ...defaultPaymentMade,
payment_account_id: defaultTo(preferredPaymentAccount),
entries: orderingLinesIndexes(defaultPaymentMade.entries), entries: orderingLinesIndexes(defaultPaymentMade.entries),
}), }),
}), }),
@@ -156,5 +160,6 @@ export default compose(
withSettings(({ billPaymentSettings }) => ({ withSettings(({ billPaymentSettings }) => ({
paymentNextNumber: billPaymentSettings?.next_number, paymentNextNumber: billPaymentSettings?.next_number,
paymentNumberPrefix: billPaymentSettings?.number_prefix, paymentNumberPrefix: billPaymentSettings?.number_prefix,
preferredPaymentAccount: parseInt(billPaymentSettings?.withdrawalAccount),
})), })),
)(PaymentMadeForm); )(PaymentMadeForm);

View File

@@ -1,7 +1,7 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import { Formik, Form } from 'formik'; import { Formik, Form } from 'formik';
import { useIntl } from 'react-intl'; import { useIntl } from 'react-intl';
import { omit, sumBy, pick, isEmpty } from 'lodash'; import { omit, sumBy, pick, isEmpty, defaultTo } from 'lodash';
import { Intent } from '@blueprintjs/core'; import { Intent } from '@blueprintjs/core';
import classNames from 'classnames'; import classNames from 'classnames';
import { useHistory } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
@@ -33,6 +33,7 @@ import { defaultPaymentReceive, transformToEditForm } from './utils';
*/ */
function PaymentReceiveForm({ function PaymentReceiveForm({
// #withSettings // #withSettings
preferredDepositAccount,
paymentReceiveNextNumber, paymentReceiveNextNumber,
paymentReceiveNumberPrefix, paymentReceiveNumberPrefix,
paymentReceiveAutoIncrement, paymentReceiveAutoIncrement,
@@ -65,6 +66,7 @@ function PaymentReceiveForm({
...defaultPaymentReceive, ...defaultPaymentReceive,
...(paymentReceiveAutoIncrement && { ...(paymentReceiveAutoIncrement && {
payment_receive_no: nextPaymentNumber, payment_receive_no: nextPaymentNumber,
deposit_account_id: defaultTo(preferredDepositAccount, ''),
}), }),
}), }),
}), }),
@@ -161,7 +163,6 @@ function PaymentReceiveForm({
createPaymentReceiveMutate(form).then(onSaved).catch(onError); createPaymentReceiveMutate(form).then(onSaved).catch(onError);
} }
}; };
return ( return (
<div <div
className={classNames( className={classNames(
@@ -198,8 +199,10 @@ function PaymentReceiveForm({
export default compose( export default compose(
withSettings(({ paymentReceiveSettings }) => ({ withSettings(({ paymentReceiveSettings }) => ({
paymentReceiveSettings,
paymentReceiveNextNumber: paymentReceiveSettings?.nextNumber, paymentReceiveNextNumber: paymentReceiveSettings?.nextNumber,
paymentReceiveNumberPrefix: paymentReceiveSettings?.numberPrefix, paymentReceiveNumberPrefix: paymentReceiveSettings?.numberPrefix,
paymentReceiveAutoIncrement: paymentReceiveSettings?.autoIncrement, paymentReceiveAutoIncrement: paymentReceiveSettings?.autoIncrement,
preferredDepositAccount: paymentReceiveSettings?.depositAccount,
})), })),
)(PaymentReceiveForm); )(PaymentReceiveForm);

View File

@@ -5,13 +5,14 @@ export default (mapState) => {
const mapped = { const mapped = {
organizationSettings: state.settings.data.organization, organizationSettings: state.settings.data.organization,
manualJournalsSettings: state.settings.data.manualJournals, manualJournalsSettings: state.settings.data.manualJournals,
billsettings: state.settings.data.bills, billPaymentSettings: state.settings.data.billPayments,
paymentReceiveSettings: state.settings.data.paymentReceives, paymentReceiveSettings: state.settings.data.paymentReceives,
estimatesSettings: state.settings.data.salesEstimates, estimatesSettings: state.settings.data.salesEstimates,
receiptSettings: state.settings.data.salesReceipts, receiptSettings: state.settings.data.salesReceipts,
invoiceSettings: state.settings.data.salesInvoices, invoiceSettings: state.settings.data.salesInvoices,
itemsSettings: state.settings.data.items, itemsSettings: state.settings.data.items,
expenseSettings: state.settings.data.expenses, expenseSettings: state.settings.data.expenses,
accountsSettings: state.settings.data.accounts,
}; };
return mapState ? mapState(mapped, state, props) : mapped; return mapState ? mapState(mapped, state, props) : mapped;
}; };

View File

@@ -0,0 +1,24 @@
import React from 'react';
import { Intent } from '@blueprintjs/core';
import { AppToaster } from 'components';
import { formatMessage } from 'services/intl';
export const transformErrors = (errors) => {
if (errors.find((error) => error.type === 'VENDOR.HAS.ASSOCIATED.BILLS')) {
AppToaster.show({
message: formatMessage({
id: 'cannot_delete_vendor_that_has_associated_purchase_bills',
}),
intent: Intent.DANGER,
});
}
if (errors.find((error) => error.type === 'VENDOR_HAS_TRANSACTIONS')) {
AppToaster.show({
message: formatMessage({
id:
'this_vendor_cannot_be_deleted_as_it_is_associated_with_transactions',
}),
intent: Intent.DANGER,
});
}
};

View File

@@ -821,7 +821,8 @@ export default {
average_rate: 'Average rate', average_rate: 'Average rate',
the_name_used_before: 'The name is already used.', the_name_used_before: 'The name is already used.',
the_item_has_associated_transactions: 'The item has associated transactions.', the_item_has_associated_transactions: 'The item has associated transactions.',
customer_has_sales_invoices: 'Cannot delete customer has associated sales invoices.', customer_has_sales_invoices:
'Cannot delete customer has associated sales invoices.',
account_name_is_already_used: 'Account name is already used.', account_name_is_already_used: 'Account name is already used.',
vendors: 'Vendors', vendors: 'Vendors',
vendor_email: 'Vendor Email', vendor_email: 'Vendor Email',
@@ -1013,11 +1014,23 @@ export default {
'The payment amount bigger than invoice due amount.', 'The payment amount bigger than invoice due amount.',
accounting_basis_: 'Accounting Basis', accounting_basis_: 'Accounting Basis',
deposit_customer_account: 'Deposit customer account', deposit_customer_account: 'Deposit customer account',
withdrawal_customer_account: 'Withdrawal customer account', withdrawal_vendor_account: 'Withdrawal vendor account',
vendor_advance_deposit: 'Vendor advance deposit', customer_advance_deposit: 'Customer advance deposit',
cannot_delete_bill_that_has_payment_transactions: cannot_delete_bill_that_has_payment_transactions:
'Cannot delete bill that has associated payment transactions.', 'Cannot delete bill that has associated payment transactions.',
cannot_change_item_type_to_inventory_with_item_has_associated_transactions: cannot_change_item_type_to_inventory_with_item_has_associated_transactions:
'Cannot change item type to inventory with item has associated transactions.', 'Cannot change item type to inventory with item has associated transactions.',
work_phone: 'Work Phone', work_phone: 'Work Phone',
cannot_delete_vendor_that_has_associated_purchase_bills:
'Cannot delete vendor that has associated purchase bills.',
the_accountant_preferences_has_been_saved:
'The accountant preferences has been saved.',
the_items_preferences_has_been_saved: 'The items preferences has been saved.',
preferred_sell_account: 'Preferred sell account',
preferred_cost_account: 'Preferred cost account',
preferred_inventory_account: 'Preferred inventory account',
this_customer_cannot_be_deleted_as_it_is_associated_with_transactions:
'This customer cannot be deleted as it is associated with transactions.',
this_vendor_cannot_be_deleted_as_it_is_associated_with_transactions:
'This vendor cannot be deleted as it is associated with transactions.',
}; };

View File

@@ -3,6 +3,7 @@ import Users from 'containers/Preferences/Users/Users';
import Accountant from 'containers/Preferences/Accountant/Accountant'; import Accountant from 'containers/Preferences/Accountant/Accountant';
import Accounts from 'containers/Preferences/Accounts/Accounts'; import Accounts from 'containers/Preferences/Accounts/Accounts';
import Currencies from 'containers/Preferences/Currencies/Currencies'; import Currencies from 'containers/Preferences/Currencies/Currencies';
import Item from 'containers/Preferences/Item/Item';
const BASE_URL = '/preferences'; const BASE_URL = '/preferences';
@@ -27,4 +28,9 @@ export default [
component: Accountant, component: Accountant,
exact: true, exact: true,
}, },
{
path: `${BASE_URL}/items`,
component: Item,
exact: true,
},
]; ];

View File

@@ -1,4 +1,3 @@
// Accountant. // Accountant.
// --------------------------------- // ---------------------------------
.preferences-page__inside-content--accountant { .preferences-page__inside-content--accountant {
@@ -13,22 +12,20 @@
.bp3-button { .bp3-button {
min-width: 60px; min-width: 60px;
+ .bp3-button{ + .bp3-button {
margin-left: 10px; margin-left: 10px;
} }
} }
} }
} }
.form-group--select-list{ .form-group--select-list {
button {
button{
min-width: 250px; min-width: 250px;
} }
} }
.bp3-form-group { .bp3-form-group {
.bp3-form-helper-text {
.bp3-form-helper-text{
margin-top: 7px; margin-top: 7px;
} }
@@ -36,4 +33,12 @@
margin-bottom: 7px; margin-bottom: 7px;
} }
} }
} .bp3-form-group.accounts-checkbox {
.bp3-form-group.bp3-inline {
margin-bottom: 7px;
}
.bp3-control.bp3-inline {
margin-bottom: 0;
}
}
}

View File

@@ -616,4 +616,7 @@ export const updateTableRow = (rowIndex, columnId, value) => (old) => {
} }
return row; return row;
}); });
}; };
export const transformGeneralSettings = (data) => {
return _.mapKeys(data, (value, key) => _.snakeCase(key));
};

View File

@@ -4,7 +4,7 @@ export default {
type: "string", type: "string",
}, },
base_currency: { base_currency: {
type: 'string', type: "string",
}, },
industry: { industry: {
type: "string", type: "string",
@@ -13,50 +13,50 @@ export default {
type: "string", type: "string",
}, },
fiscal_year: { fiscal_year: {
type: 'string', type: "string",
}, },
financial_date_start: { financial_date_start: {
type: 'string', type: "string",
}, },
language: { language: {
type: 'string', type: "string",
}, },
time_zone: { time_zone: {
type: 'string', type: "string",
}, },
date_format: { date_format: {
type: 'string', type: "string",
}, },
accounting_basis: { accounting_basis: {
type: 'string', type: "string",
} },
}, },
manual_journals: { manual_journals: {
next_number: { next_number: {
type: 'string', type: "string",
}, },
number_prefix: { number_prefix: {
type: 'string', type: "string",
}, },
auto_increment: { auto_increment: {
type: 'boolean', type: "boolean",
} },
}, },
bill_payments: { bill_payments: {
withdrawal_account: { withdrawal_account: {
type: 'string' type: "number",
}, },
}, },
sales_estimates: { sales_estimates: {
next_number: { next_number: {
type: 'string', type: "string",
}, },
number_prefix: { number_prefix: {
type: 'string', type: "string",
}, },
auto_increment: { auto_increment: {
type: "boolean", type: "boolean",
} },
}, },
sales_receipts: { sales_receipts: {
next_number: { next_number: {
@@ -70,7 +70,7 @@ export default {
}, },
preferred_deposit_account: { preferred_deposit_account: {
type: "number", type: "number",
} },
}, },
sales_invoices: { sales_invoices: {
next_number: { next_number: {
@@ -91,37 +91,37 @@ export default {
type: "string", type: "string",
}, },
auto_increment: { auto_increment: {
type: 'boolean', type: "boolean",
}, },
deposit_account: { deposit_account: {
type: 'number', type: "number",
}, },
advance_deposit: { advance_deposit: {
type: 'number', type: "number",
} },
}, },
items: { items: {
sell_account: { sell_account: {
type: 'number', type: "number",
}, },
cost_account: { cost_account: {
type: 'number', type: "number",
}, },
inventory_account: { inventory_account: {
type: 'number', type: "number",
}, },
}, },
expenses: { expenses: {
preferred_payment_account: { preferred_payment_account: {
type: "number", type: "number",
} },
}, },
accounts: { accounts: {
account_code_required: { account_code_required: {
type: 'boolean', type: "boolean",
}, },
account_code_unique: { account_code_unique: {
type: 'boolean', type: "boolean",
} },
} },
}; };