feat: add auto increment/ money out.

This commit is contained in:
elforjani13
2021-10-24 20:01:51 +02:00
parent 9ecc7f58e7
commit e94a386fe8
14 changed files with 476 additions and 28 deletions

View File

@@ -14,10 +14,11 @@ import { CreateMoneyOutSchema } from './MoneyOutForm.schema';
import { useMoneyOutDialogContext } from './MoneyOutDialogProvider';
import withSettings from 'containers/Settings/withSettings';
import withDialogActions from 'containers/Dialog/withDialogActions';
import withCurrentOrganization from 'containers/Organization/withCurrentOrganization';
import { compose } from 'utils';
import { compose, transactionNumber } from 'utils';
const defaultInitialValues = {
date: moment(new Date()).format('YYYY-MM-DD'),
@@ -37,6 +38,11 @@ function MoneyOutForm({
// #withCurrentOrganization
organization: { base_currency },
// #withSettings
transactionNextNumber,
transactionNumberPrefix,
transactionIncrementMode,
}) {
const {
dialogName,
@@ -46,11 +52,20 @@ function MoneyOutForm({
submitPayload,
} = useMoneyOutDialogContext();
// transaction number.
const transactionNo = transactionNumber(
transactionNumberPrefix,
transactionNextNumber,
);
// Initial form values.
const initialValues = {
...defaultInitialValues,
currency_code: base_currency,
transaction_type: accountType,
...(transactionIncrementMode && {
transaction_number: transactionNo,
}),
cashflow_account_id: accountId,
};
@@ -90,4 +105,9 @@ function MoneyOutForm({
export default compose(
withDialogActions,
withCurrentOrganization(),
withSettings(({ cashflowSetting }) => ({
transactionNextNumber: cashflowSetting?.nextNumber,
transactionNumberPrefix: cashflowSetting?.numberPrefix,
transactionIncrementMode: cashflowSetting?.autoIncrement,
})),
)(MoneyOutForm);

View File

@@ -2,8 +2,8 @@ import React from 'react';
import { Form } from 'formik';
import MoneyOutFormFields from './MoneyOutFormFields';
import MoneyOutFormDialog from './MoneyOutFormDialog'
import MoneyOutFloatingActions from './MoneyOutFloatingActions';
/**
* Money out form content.
*/
@@ -11,6 +11,7 @@ export default function MoneyOutFormContent() {
return (
<Form>
<MoneyOutFormFields />
<MoneyOutFormDialog/>
<MoneyOutFloatingActions />
</Form>
);

View File

@@ -0,0 +1,27 @@
import React from 'react';
import { useFormikContext } from 'formik';
import TransactionNumberDialog from '../../Dialogs/TransactionNumberDialog';
/**
* Money out form dialog.
*/
export default function MoneyOutFormDialog() {
const { setFieldValue } = useFormikContext();
// Update the form once the transaction number form submit confirm.
const handleTransactionNumberFormConfirm = ({
incrementNumber,
manually,
}) => {
setFieldValue('transaction_number', incrementNumber || '');
setFieldValue('transaction_number_manually', manually);
};
return (
<React.Fragment>
<TransactionNumberDialog
dialogName={'transaction-number-form'}
onConfirm={handleTransactionNumberFormConfirm}
/>
</React.Fragment>
);
}

View File

@@ -15,8 +15,10 @@ import {
InputPrependText,
MoneyInputGroup,
FieldRequiredHint,
Icon,
Col,
Row,
InputPrependButton,
} from 'components';
import { DateInput } from '@blueprintjs/datetime';
import { useAutofocus } from 'hooks';
@@ -27,19 +29,56 @@ import {
momentFormatter,
tansformDateValue,
handleDateChange,
compose,
} from 'utils';
import { CLASSES } from 'common/classes';
import { useMoneyOutDialogContext } from '../MoneyOutDialogProvider';
import { useObserveTransactionNoSettings } from '../utils';
import withSettings from 'containers/Settings/withSettings';
import withDialogActions from 'containers/Dialog/withDialogActions';
/**
* Other expense form fields.
*/
function OtherExpnseFormFields() {
function OtherExpnseFormFields({
// #withDialogActions
openDialog,
// #withSettings
transactionAutoIncrement,
transactionNumberPrefix,
transactionNextNumber,
}) {
// Money in dialog context.
const { accounts } = useMoneyOutDialogContext();
const amountFieldRef = useAutofocus();
// Handle tranaction number changing.
const handleTransactionNumberChange = () => {
openDialog('transaction-number-form');
};
// Handle transaction no. field blur.
const handleTransactionNoBlur = (form, field) => (event) => {
const newValue = event.target.value;
if (field.value !== newValue && transactionAutoIncrement) {
openDialog('transaction-number-form', {
initialFormValues: {
manualTransactionNo: newValue,
incrementMode: 'manual-transaction',
},
});
}
};
// Syncs transaction number settings with form.
useObserveTransactionNoSettings(
transactionNumberPrefix,
transactionNextNumber,
);
return (
<React.Fragment>
<Row>
@@ -81,10 +120,31 @@ function OtherExpnseFormFields() {
helperText={<ErrorMessage name="transaction_number" />}
className={'form-group--transaction_number'}
>
<InputGroup
intent={inputIntent({ error, touched })}
{...field}
/>
<ControlGroup fill={true}>
<InputGroup
minimal={true}
value={field.value}
asyncControl={true}
onBlur={handleTransactionNoBlur(form, field)}
/>
<InputPrependButton
buttonProps={{
onClick: handleTransactionNumberChange,
icon: <Icon icon={'settings-18'} />,
}}
tooltip={true}
tooltipProps={{
content: (
<T
id={
'cash_flow.setting_your_auto_generated_transaction_number'
}
/>
),
position: Position.BOTTOM_LEFT,
}}
/>
</ControlGroup>
</FormGroup>
)}
</FastField>
@@ -192,4 +252,11 @@ function OtherExpnseFormFields() {
);
}
export default OtherExpnseFormFields;
export default compose(
withDialogActions,
withSettings(({ cashflowSetting }) => ({
transactionAutoIncrement: cashflowSetting?.autoIncrement,
transactionNextNumber: cashflowSetting?.nextNumber,
transactionNumberPrefix: cashflowSetting?.numberPrefix,
})),
)(OtherExpnseFormFields);

View File

@@ -15,6 +15,8 @@ import {
InputPrependText,
MoneyInputGroup,
FieldRequiredHint,
InputPrependButton,
Icon,
Col,
Row,
} from 'components';
@@ -26,19 +28,56 @@ import {
momentFormatter,
tansformDateValue,
handleDateChange,
compose,
} from 'utils';
import { CLASSES } from 'common/classes';
import { useMoneyOutDialogContext } from '../MoneyOutDialogProvider';
import { useObserveTransactionNoSettings } from '../utils';
import withSettings from 'containers/Settings/withSettings';
import withDialogActions from 'containers/Dialog/withDialogActions';
/**
* Owner drawings form fields.
*/
function OwnerDrawingsFormFields() {
function OwnerDrawingsFormFields({
// #withDialogActions
openDialog,
// #withSettings
transactionAutoIncrement,
transactionNumberPrefix,
transactionNextNumber,
}) {
// Money out dialog context.
const { accounts } = useMoneyOutDialogContext();
const amountFieldRef = useAutofocus();
// Handle tranaction number changing.
const handleTransactionNumberChange = () => {
openDialog('transaction-number-form');
};
// Handle transaction no. field blur.
const handleTransactionNoBlur = (form, field) => (event) => {
const newValue = event.target.value;
if (field.value !== newValue && transactionAutoIncrement) {
openDialog('transaction-number-form', {
initialFormValues: {
manualTransactionNo: newValue,
incrementMode: 'manual-transaction',
},
});
}
};
// Syncs transaction number settings with form.
useObserveTransactionNoSettings(
transactionNumberPrefix,
transactionNextNumber,
);
return (
<React.Fragment>
<Row>
@@ -80,10 +119,31 @@ function OwnerDrawingsFormFields() {
helperText={<ErrorMessage name="transaction_number" />}
className={'form-group--transaction_number'}
>
<InputGroup
intent={inputIntent({ error, touched })}
{...field}
/>
<ControlGroup fill={true}>
<InputGroup
minimal={true}
value={field.value}
asyncControl={true}
onBlur={handleTransactionNoBlur(form, field)}
/>
<InputPrependButton
buttonProps={{
onClick: handleTransactionNumberChange,
icon: <Icon icon={'settings-18'} />,
}}
tooltip={true}
tooltipProps={{
content: (
<T
id={
'cash_flow.setting_your_auto_generated_transaction_number'
}
/>
),
position: Position.BOTTOM_LEFT,
}}
/>
</ControlGroup>
</FormGroup>
)}
</FastField>
@@ -188,4 +248,11 @@ function OwnerDrawingsFormFields() {
);
}
export default OwnerDrawingsFormFields;
export default compose(
withDialogActions,
withSettings(({ cashflowSetting }) => ({
transactionAutoIncrement: cashflowSetting?.autoIncrement,
transactionNextNumber: cashflowSetting?.nextNumber,
transactionNumberPrefix: cashflowSetting?.numberPrefix,
})),
)(OwnerDrawingsFormFields);

View File

@@ -15,8 +15,10 @@ import {
InputPrependText,
MoneyInputGroup,
FieldRequiredHint,
Icon,
Col,
Row,
InputPrependButton,
} from 'components';
import { DateInput } from '@blueprintjs/datetime';
import { useAutofocus } from 'hooks';
@@ -27,19 +29,56 @@ import {
momentFormatter,
tansformDateValue,
handleDateChange,
compose,
} from 'utils';
import { CLASSES } from 'common/classes';
import { useMoneyOutDialogContext } from '../MoneyOutDialogProvider';
import { useObserveTransactionNoSettings } from '../utils';
import withSettings from 'containers/Settings/withSettings';
import withDialogActions from 'containers/Dialog/withDialogActions';
/**
* Transfer to account form fields.
*/
function TransferToAccountFormFields() {
function TransferToAccountFormFields({
// #withDialogActions
openDialog,
// #withSettings
transactionAutoIncrement,
transactionNumberPrefix,
transactionNextNumber,
}) {
// Money in dialog context.
const { accounts } = useMoneyOutDialogContext();
const accountRef = useAutofocus();
// Handle tranaction number changing.
const handleTransactionNumberChange = () => {
openDialog('transaction-number-form');
};
// Handle transaction no. field blur.
const handleTransactionNoBlur = (form, field) => (event) => {
const newValue = event.target.value;
if (field.value !== newValue && transactionAutoIncrement) {
openDialog('transaction-number-form', {
initialFormValues: {
manualTransactionNo: newValue,
incrementMode: 'manual-transaction',
},
});
}
};
// Syncs transaction number settings with form.
useObserveTransactionNoSettings(
transactionNumberPrefix,
transactionNextNumber,
);
return (
<React.Fragment>
<Row>
@@ -81,10 +120,31 @@ function TransferToAccountFormFields() {
helperText={<ErrorMessage name="transaction_number" />}
className={'form-group--transaction_number'}
>
<InputGroup
intent={inputIntent({ error, touched })}
{...field}
/>
<ControlGroup fill={true}>
<InputGroup
minimal={true}
value={field.value}
asyncControl={true}
onBlur={handleTransactionNoBlur(form, field)}
/>
<InputPrependButton
buttonProps={{
onClick: handleTransactionNumberChange,
icon: <Icon icon={'settings-18'} />,
}}
tooltip={true}
tooltipProps={{
content: (
<T
id={
'cash_flow.setting_your_auto_generated_transaction_number'
}
/>
),
position: Position.BOTTOM_LEFT,
}}
/>
</ControlGroup>
</FormGroup>
)}
</FastField>
@@ -193,5 +253,11 @@ function TransferToAccountFormFields() {
</React.Fragment>
);
}
export default TransferToAccountFormFields;
export default compose(
withDialogActions,
withSettings(({ cashflowSetting }) => ({
transactionAutoIncrement: cashflowSetting?.autoIncrement,
transactionNextNumber: cashflowSetting?.nextNumber,
transactionNumberPrefix: cashflowSetting?.numberPrefix,
})),
)(TransferToAccountFormFields);

View File

@@ -0,0 +1,12 @@
import React from 'react';
import { useFormikContext } from 'formik';
import { transactionNumber } from 'utils';
export const useObserveTransactionNoSettings = (prefix, nextNumber) => {
const { setFieldValue } = useFormikContext();
React.useEffect(() => {
const TransactionNo = transactionNumber(prefix, nextNumber);
setFieldValue('transacttion_numner', TransactionNo);
}, [setFieldValue, prefix, nextNumber]);
};

View File

@@ -0,0 +1,103 @@
import React from 'react';
import intl from 'react-intl-universal';
import { useSaveSettings } from 'hooks/query';
import { TransactionNumberDialogProvider } from './TransactionNumberDialogProvider';
import ReferenceNumberForm from 'containers/JournalNumber/ReferenceNumberForm';
import withDialogActions from 'containers/Dialog/withDialogActions';
import withSettings from 'containers/Settings/withSettings';
import withSettingsActions from 'containers/Settings/withSettingsActions';
import { compose } from 'utils';
import {
transformFormToSettings,
transformSettingsToForm,
} from 'containers/JournalNumber/utils';
/**
* Transaction number dialog content.
*/
function TransactionNumberDialogContent({
// #ownProps
initialValues,
onConfirm,
// #withSettings
nextNumber,
numberPrefix,
autoIncrement,
// #withDialogActions
closeDialog,
}) {
const { mutateAsync: saveSettings } = useSaveSettings();
const [referenceFormValues, setReferenceFormValues] = React.useState(null);
// Handle the submit form.
const handleSubmitForm = (values, { setSubmitting }) => {
// Handle the form success.
const handleSuccess = () => {
setSubmitting(false);
closeDialog('transaction-number-form');
onConfirm(values);
};
// Handle the form errors.
const handleErrors = () => {
setSubmitting(false);
};
if (values.incrementMode === 'manual-transaction') {
handleSuccess();
return;
}
// Transformes the form values to settings to save it.
const options = transformFormToSettings(values, 'cashflow');
// Save the settings.
saveSettings({ options }).then(handleSuccess).catch(handleErrors);
};
// Description.
const description =
referenceFormValues?.incrementMode === 'auto'
? intl.get('cash_flow.auto_increment.auto')
: intl.get('cash_flow.auto_increment.manually');
// Handle the dialog close.
const handleClose = () => {
closeDialog('transaction-number-form');
};
// Handle form change.
const handleChange = (values) => {
setReferenceFormValues(values);
};
return (
<TransactionNumberDialogProvider>
<ReferenceNumberForm
initialValues={{
...transformSettingsToForm({
nextNumber,
numberPrefix,
autoIncrement,
}),
...initialValues,
}}
description={description}
onSubmit={handleSubmitForm}
onClose={handleClose}
onChange={handleChange}
/>
</TransactionNumberDialogProvider>
);
}
export default compose(
withDialogActions,
withSettingsActions,
withSettings(({ cashflowSetting }) => ({
nextNumber: cashflowSetting?.nextNumber,
numberPrefix: cashflowSetting?.numberPrefix,
autoIncrement: cashflowSetting?.autoIncrement,
})),
)(TransactionNumberDialogContent);

View File

@@ -0,0 +1,26 @@
import React from 'react';
import { DialogContent } from 'components';
import { useSettingCashFlow } from 'hooks/query';
const TransactionNumberDialogContext = React.createContext();
/**
* Transaction number dialog provider.
*/
function TransactionNumberDialogProvider({ query, ...props }) {
const { isLoading: isSettingsLoading } = useSettingCashFlow();
// Provider payload.
const provider = { isSettingsLoading };
return (
<DialogContent isLoading={isSettingsLoading}>
<TransactionNumberDialogContext.Provider value={provider} {...props} />
</DialogContent>
);
}
const useTransactionNumberDialogContext = () =>
React.useContext(TransactionNumberDialogContext);
export { TransactionNumberDialogProvider, useTransactionNumberDialogContext };

View File

@@ -0,0 +1,42 @@
import React from 'react';
import { FormattedMessage as T } from 'components';
import { Dialog, DialogSuspense } from 'components';
import withDialogRedux from 'components/DialogReduxConnect';
import { compose, saveInvoke } from 'utils';
const TransactionNumberDialogContent = React.lazy(() =>
import('./TransactionNumberDialogContent'),
);
/**
* Transaction number dialog.
*/
function TransctionNumberDialog({
dialogName,
payload: { initialFormValues },
isOpen,
onConfirm,
}) {
const handleConfirm = (values) => {
saveInvoke(onConfirm, values);
};
return (
<Dialog
title={<T id={'transaction_number_settings'} />}
name={dialogName}
autoFocus={true}
canEscapeKeyClose={true}
isOpen={isOpen}
>
<DialogSuspense>
<TransactionNumberDialogContent
initialValues={{ ...initialFormValues }}
onConfirm={handleConfirm}
/>
</DialogSuspense>
</Dialog>
);
}
export default compose(withDialogRedux())(TransctionNumberDialog);